diff options
author | Fabio Berger <me@fabioberger.com> | 2018-01-25 23:42:58 +0800 |
---|---|---|
committer | Fabio Berger <me@fabioberger.com> | 2018-01-25 23:42:58 +0800 |
commit | 71d68f975cd7bc089f0cbef4e5888a73eab4ee42 (patch) | |
tree | 9482602fc23d2baec3fff1fb97750ad45adc6eca /packages | |
parent | ec3d8a034fe763d8255935985b1fb97aff6c177b (diff) | |
parent | f58f0ddb67555c3f0c7252ea3e003824984c48ad (diff) | |
download | dexon-sol-tools-71d68f975cd7bc089f0cbef4e5888a73eab4ee42.tar dexon-sol-tools-71d68f975cd7bc089f0cbef4e5888a73eab4ee42.tar.gz dexon-sol-tools-71d68f975cd7bc089f0cbef4e5888a73eab4ee42.tar.bz2 dexon-sol-tools-71d68f975cd7bc089f0cbef4e5888a73eab4ee42.tar.lz dexon-sol-tools-71d68f975cd7bc089f0cbef4e5888a73eab4ee42.tar.xz dexon-sol-tools-71d68f975cd7bc089f0cbef4e5888a73eab4ee42.tar.zst dexon-sol-tools-71d68f975cd7bc089f0cbef4e5888a73eab4ee42.zip |
Merge branch 'development' into feature/portal-ledger-support
* development: (437 commits)
Publish
Update yarn.lock
Update the CHANGELOG
Fix the bug making it impossible to specify the custom ZRX address
Fix fill/cancel order by looking for NoError instead of empty blockchainErr given the BlockchainErrs type refactor
Add a comment about a yarn bug
Add our mainnet and kovan nodes as backups for Portal requests
Fix bug hiding the user info from topBar
Add dev-utils package to top level README
Prettier newline
Prettier
Allow Token symbols to be alphanumeric
Update CHANGELOG, rebase on development
Should not -> cannot
Reject negative amounts in isValidBaseUnitAmount
Re-add changelog for 0x.js
Fix prettier
Update yarn.lock
Move tests to a separate folder
Change file layout
...
# Conflicts:
# packages/website/README.md
Diffstat (limited to 'packages')
512 files changed, 19034 insertions, 14417 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/abi-gen-templates/contract.mustache b/packages/0x.js/contract_templates/contract.mustache index ec06df507..3e501cce6 100644 --- a/packages/abi-gen-templates/contract.mustache +++ b/packages/0x.js/contract_templates/contract.mustache @@ -2,13 +2,11 @@ * 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'; +// 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 {TxData, TxDataPayable} from '../../types'; -import {classUtils} from '../../utils/class_utils'; - import {BaseContract} from './base_contract'; export class {{contractName}}Contract extends BaseContract { diff --git a/packages/abi-gen-templates/partials/call.mustache b/packages/0x.js/contract_templates/partials/call.mustache index ef4bda724..ef4bda724 100644 --- a/packages/abi-gen-templates/partials/call.mustache +++ b/packages/0x.js/contract_templates/partials/call.mustache diff --git a/packages/abi-gen-templates/partials/params.mustache b/packages/0x.js/contract_templates/partials/params.mustache index ac5d4ae85..ac5d4ae85 100644 --- a/packages/abi-gen-templates/partials/params.mustache +++ b/packages/0x.js/contract_templates/partials/params.mustache diff --git a/packages/abi-gen-templates/partials/return_type.mustache b/packages/0x.js/contract_templates/partials/return_type.mustache index 383961a40..383961a40 100644 --- a/packages/abi-gen-templates/partials/return_type.mustache +++ b/packages/0x.js/contract_templates/partials/return_type.mustache diff --git a/packages/abi-gen-templates/partials/tx.mustache b/packages/0x.js/contract_templates/partials/tx.mustache index 8a43e5319..8a43e5319 100644 --- a/packages/abi-gen-templates/partials/tx.mustache +++ b/packages/0x.js/contract_templates/partials/tx.mustache diff --git a/packages/abi-gen-templates/partials/typed_params.mustache b/packages/0x.js/contract_templates/partials/typed_params.mustache index 3ea4b2e95..3ea4b2e95 100644 --- a/packages/abi-gen-templates/partials/typed_params.mustache +++ b/packages/0x.js/contract_templates/partials/typed_params.mustache 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/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/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 = { diff --git a/packages/abi-gen-templates/package.json b/packages/abi-gen-templates/package.json deleted file mode 100644 index e45da3bf1..000000000 --- a/packages/abi-gen-templates/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "abi-gen-templates", - "private": true, - "version": "0.0.1", - "description": "Handlebars templates to generate TS contract wrappers", - "repository": { - "type": "git", - "url": "https://github.com/0xProject/0x.js.git" - }, - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/0xProject/0x.js/issues" - }, - "homepage": "https://github.com/0xProject/0x.js/packages/abi-gen-templates/README.md" -} diff --git a/packages/abi-gen/CHANGELOG.md b/packages/abi-gen/CHANGELOG.md new file mode 100644 index 000000000..fb2c6eb24 --- /dev/null +++ b/packages/abi-gen/CHANGELOG.md @@ -0,0 +1,7 @@ +# CHANGELOG + +## v0.1.0 - _January 11, 2018_ + +* Fixed array typings with union types (#295) +* Add event ABIs to context data passed to templates (#302) +* Add constructor ABIs to context data passed to templates (#304) diff --git a/packages/abi-gen/README.md b/packages/abi-gen/README.md index 16dd9b969..1188bd437 100644 --- a/packages/abi-gen/README.md +++ b/packages/abi-gen/README.md @@ -5,11 +5,14 @@ It's heavily inspired by [Geth abigen](https://github.com/ethereum/go-ethereum/w You can write your custom handlebars templates which will allow you to seamlessly integrate the generated code into your existing codebase with existing conventions. For an example of the generated [wrapper files](https://github.com/0xProject/0x.js/tree/development/packages/0x.js/src/contract_wrappers/generated) check out 0x.js. -[Here](https://github.com/0xProject/0x.js/tree/development/packages/abi-gen-templates) are the templates used to generate those files. +[Here](https://github.com/0xProject/0x.js/tree/development/packages/0x.js/contract_templates) are the templates used to generate those files. + +## Installation -## Instalation `yarn add -g @0xproject/abi-gen` + ## Usage + ``` abi-gen Options: @@ -19,8 +22,10 @@ Options: --templates Folder where to search for templates [string] [required] --output Folder where to put the output files [string] [required] ``` + ## ABI files -You're required to pass a [glob](https://en.wikipedia.org/wiki/Glob_(programming)) template where your abi files are located. + +You're required to pass a [glob](<https://en.wikipedia.org/wiki/Glob_(programming)>) template where your abi files are located. TL;DR - here is the example from 0x.js. `--abiGlob 'src/artifacts/@(Exchange|Token|TokenTransferProxy|EtherToken|TokenRegistry).json` @@ -28,12 +33,18 @@ TL;DR - here is the example from 0x.js. We could've just used `--abiGlob 'src/artifacts/*.json` but we wanted to exclude some of the abi files. The abi file should be either a [Truffle](http://truffleframework.com/) contract artifact (a JSON object with an abi key) or a JSON abi array. + ## How to write custom templates? -The best way to get started is to copy [0x.js templates](https://github.com/0xProject/0x.js/tree/development/packages/abi-gen-templates) and start adjusting them for your needs. -We use [handlebars](handlebarsjs.com) template engine under the hood. + +The best way to get started is to copy [0x.js templates](https://github.com/0xProject/0x.js/tree/development/packages/0x.js/contract_templates) and start adjusting them for your needs. +We use [handlebars](http://handlebarsjs.com/) template engine under the hood. You need to have a master template called `contract.mustache`. it will be used to generate each contract wrapper. Although - you don't need and probably shouldn't write all your logic in a single template file. You can write [partial templates](http://handlebarsjs.com/partials.html) and as long as they are within a partials folder - they will be registered and available. + ## Which data/context do I get in my templates? + For now you don't get much on top of methods abi, some useful helpers and a contract name because it was enough for our use-case, but if you need something else - create a PR. See the [type definition](https://github.com/0xProject/0x.js/tree/development/packages/abi-gen/src/types.ts) of what we pass to the render method. + ## Output files + Output files will be generated within an output folder with names converted to camel case and taken from abi file names. If you already have some files in that folder they will be overwritten. diff --git a/packages/abi-gen/package.json b/packages/abi-gen/package.json index 9ce64f818..8d2dee18a 100644 --- a/packages/abi-gen/package.json +++ b/packages/abi-gen/package.json @@ -1,48 +1,48 @@ { - "name": "abi-gen", - "version": "0.0.1", - "description": "Generate contract wrappers from ABI and handlebars templates", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "scripts": { - "lint": "tslint --project . 'src/**/*.ts'", - "clean": "shx rm -rf lib", - "build": "tsc" - }, - "bin": { - "abi-gen": "lib/index.js" - }, - "repository": { - "type": "git", - "url": "https://github.com/0xProject/0x.js.git" - }, - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/0xProject/0x.js/issues" - }, - "homepage": "https://github.com/0xProject/0x.js/packages/abi-gen/README.md", - "dependencies": { - "bignumber.js": "~4.1.0", - "chalk": "^2.3.0", - "glob": "^7.1.2", - "handlebars": "^4.0.11", - "lodash": "^4.17.4", - "mkdirp": "^0.5.1", - "to-snake-case": "^1.0.0", - "web3": "^0.20.0", - "yargs": "^10.0.3" - }, - "devDependencies": { - "@0xproject/tslint-config": "^0.2.0", - "@types/glob": "^5.0.33", - "@types/handlebars": "^4.0.36", - "@types/mkdirp": "^0.5.1", - "@types/node": "^8.0.53", - "@types/yargs": "^8.0.2", - "npm-run-all": "^4.1.2", - "shx": "^0.2.2", - "tslint": "5.8.0", - "typescript": "~2.6.1", - "web3-typescript-typings": "^0.7.2" - } + "name": "@0xproject/abi-gen", + "version": "0.1.3", + "description": "Generate contract wrappers from ABI and handlebars templates", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "scripts": { + "lint": "tslint --project . 'src/**/*.ts'", + "clean": "shx rm -rf lib", + "build": "tsc" + }, + "bin": { + "abi-gen": "lib/index.js" + }, + "repository": { + "type": "git", + "url": "https://github.com/0xProject/0x.js.git" + }, + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/0xProject/0x.js/issues" + }, + "homepage": "https://github.com/0xProject/0x.js/packages/abi-gen/README.md", + "dependencies": { + "@0xproject/utils": "^0.2.1", + "chalk": "^2.3.0", + "glob": "^7.1.2", + "handlebars": "^4.0.11", + "lodash": "^4.17.4", + "mkdirp": "^0.5.1", + "to-snake-case": "^1.0.0", + "web3": "^0.20.0", + "yargs": "^10.0.3" + }, + "devDependencies": { + "@0xproject/tslint-config": "^0.4.3", + "@types/glob": "^5.0.33", + "@types/handlebars": "^4.0.36", + "@types/mkdirp": "^0.5.1", + "@types/node": "^8.0.53", + "@types/yargs": "^10.0.0", + "npm-run-all": "^4.1.2", + "shx": "^0.2.2", + "tslint": "5.8.0", + "typescript": "~2.6.1", + "web3-typescript-typings": "^0.9.5" + } } diff --git a/packages/abi-gen/scripts/postpublish.js b/packages/abi-gen/scripts/postpublish.js new file mode 100644 index 000000000..16d67e03f --- /dev/null +++ b/packages/abi-gen/scripts/postpublish.js @@ -0,0 +1,15 @@ +const postpublish_utils = require('../../../scripts/postpublish_utils'); +const packageJSON = require('../package.json'); + +const subPackageName = packageJSON.name; + +postpublish_utils + .getLatestTagAndVersionAsync(subPackageName) + .then(function(result) { + const releaseName = postpublish_utils.getReleaseName(subPackageName, result.version); + const assets = []; + return postpublish_utils.publishReleaseNotes(result.tag, releaseName, assets); + }) + .catch(function(err) { + throw err; + }); diff --git a/packages/abi-gen/src/index.ts b/packages/abi-gen/src/index.ts index 19d289e49..527af32b1 100644 --- a/packages/abi-gen/src/index.ts +++ b/packages/abi-gen/src/index.ts @@ -2,7 +2,7 @@ import chalk from 'chalk'; import * as fs from 'fs'; -import {sync as globSync} from 'glob'; +import { sync as globSync } from 'glob'; import * as Handlebars from 'handlebars'; import * as _ from 'lodash'; import * as mkdirp from 'mkdirp'; @@ -11,10 +11,12 @@ import * as yargs from 'yargs'; import toSnakeCase = require('to-snake-case'); import * as Web3 from 'web3'; -import {ContextData, ParamKind} from './types'; -import {utils} from './utils'; +import { ContextData, ParamKind } from './types'; +import { utils } from './utils'; +const ABI_TYPE_CONSTRUCTOR = 'constructor'; const ABI_TYPE_METHOD = 'function'; +const ABI_TYPE_EVENT = 'event'; const MAIN_TEMPLATE_NAME = 'contract.mustache'; const args = yargs @@ -32,8 +34,7 @@ const args = yargs describe: 'Folder where to put the output files', type: 'string', demand: true, - }) - .argv; + }).argv; function writeOutputFile(name: string, renderedTsCode: string): void { const fileName = toSnakeCase(name); @@ -66,14 +67,20 @@ for (const abiFileName of abiFileNames) { const namedContent = utils.getNamedContent(abiFileName); utils.log(`Processing: ${chalk.bold(namedContent.name)}...`); const parsedContent = JSON.parse(namedContent.content); - const ABI = _.isArray(parsedContent) ? - parsedContent : // ABI file - parsedContent.abi; // Truffle contracts file + const ABI = _.isArray(parsedContent) + ? parsedContent // ABI file + : parsedContent.abi; // Truffle contracts file if (_.isUndefined(ABI)) { utils.log(`${chalk.red(`ABI not found in ${abiFileName}.`)}`); utils.log(`Please make sure your ABI file is either an array with ABI entries or an object with the abi key`); process.exit(1); } + + let ctor = ABI.find((abi: Web3.AbiDefinition) => abi.type === ABI_TYPE_CONSTRUCTOR) as Web3.ConstructorAbi; + if (_.isUndefined(ctor)) { + ctor = utils.getEmptyConstructor(); // The constructor exists, but it's implicit in JSON's ABI definition + } + const methodAbis = ABI.filter((abi: Web3.AbiDefinition) => abi.type === ABI_TYPE_METHOD) as Web3.MethodAbi[]; const methodsData = _.map(methodAbis, methodAbi => { _.map(methodAbi.inputs, input => { @@ -89,9 +96,14 @@ for (const abiFileName of abiFileNames) { }; return methodData; }); + + const eventAbis = ABI.filter((abi: Web3.AbiDefinition) => abi.type === ABI_TYPE_EVENT) as Web3.EventAbi[]; + const contextData = { contractName: namedContent.name, + ctor, methods: methodsData, + events: eventAbis, }; const renderedTsCode = template(contextData); writeOutputFile(namedContent.name, renderedTsCode); diff --git a/packages/abi-gen/src/types.ts b/packages/abi-gen/src/types.ts index 1dc039c83..e82ab824b 100644 --- a/packages/abi-gen/src/types.ts +++ b/packages/abi-gen/src/types.ts @@ -5,6 +5,13 @@ export enum ParamKind { Output = 'output', } +export enum AbiType { + Function = 'function', + Constructor = 'constructor', + Event = 'event', + Fallback = 'fallback', +} + export interface Method extends Web3.MethodAbi { singleReturnValue: boolean; } @@ -12,4 +19,5 @@ export interface Method extends Web3.MethodAbi { export interface ContextData { contractName: string; methods: Method[]; + events: Web3.EventAbi[]; } diff --git a/packages/abi-gen/src/utils.ts b/packages/abi-gen/src/utils.ts index eaf5a30cc..14255643a 100644 --- a/packages/abi-gen/src/utils.ts +++ b/packages/abi-gen/src/utils.ts @@ -1,8 +1,9 @@ import * as fs from 'fs'; import * as _ from 'lodash'; import * as path from 'path'; +import * as Web3 from 'web3'; -import {ParamKind} from './types'; +import { AbiType, ParamKind } from './types'; export const utils = { solTypeToTsType(paramKind: ParamKind, solType: string): string { @@ -10,23 +11,28 @@ export const utils = { if (solType.match(trailingArrayRegex)) { const arrayItemSolType = solType.replace(trailingArrayRegex, ''); const arrayItemTsType = utils.solTypeToTsType(paramKind, arrayItemSolType); - const arrayTsType = `${arrayItemTsType}[]`; + const arrayTsType = utils.isUnionType(arrayItemTsType) + ? `Array<${arrayItemTsType}>` + : `${arrayItemTsType}[]`; return arrayTsType; } else { const solTypeRegexToTsType = [ - {regex: '^string$', tsType: 'string'}, - {regex: '^address$', tsType: 'string'}, - {regex: '^bool$', tsType: 'boolean'}, - {regex: '^u?int\\d*$', tsType: 'BigNumber'}, - {regex: '^bytes\\d*$', tsType: 'string'}, + { regex: '^string$', tsType: 'string' }, + { regex: '^address$', tsType: 'string' }, + { regex: '^bool$', tsType: 'boolean' }, + { regex: '^u?int\\d*$', tsType: 'BigNumber' }, + { regex: '^bytes\\d*$', tsType: 'string' }, ]; if (paramKind === ParamKind.Input) { // web3 allows to pass those an non-bignumbers and that's nice // but it always returns stuff as BigNumbers - solTypeRegexToTsType.unshift({regex: '^u?int(8|16|32)?$', tsType: 'number|BigNumber'}); + solTypeRegexToTsType.unshift({ + regex: '^u?int(8|16|32)?$', + tsType: 'number|BigNumber', + }); } for (const regexAndTxType of solTypeRegexToTsType) { - const {regex, tsType} = regexAndTxType; + const { regex, tsType } = regexAndTxType; if (solType.match(regex)) { return tsType; } @@ -34,6 +40,9 @@ export const utils = { throw new Error(`Unknown Solidity type found: ${solType}`); } }, + isUnionType(tsType: string): boolean { + return tsType === 'number|BigNumber'; + }, log(...args: any[]): void { console.log(...args); // tslint:disable-line:no-console }, @@ -41,7 +50,7 @@ export const utils = { const name = path.parse(filename).name; return name; }, - getNamedContent(filename: string): {name: string; content: string} { + getNamedContent(filename: string): { name: string; content: string } { const name = utils.getPartialNameFromFileName(filename); try { const content = fs.readFileSync(filename).toString(); @@ -53,4 +62,12 @@ export const utils = { throw new Error(`Failed to read ${filename}: ${err}`); } }, + getEmptyConstructor(): Web3.ConstructorAbi { + return { + type: AbiType.Constructor, + stateMutability: 'nonpayable', + payable: false, + inputs: [], + }; + }, }; diff --git a/packages/abi-gen/tsconfig.json b/packages/abi-gen/tsconfig.json index 695f2a47e..5e0c7c6d3 100644 --- a/packages/abi-gen/tsconfig.json +++ b/packages/abi-gen/tsconfig.json @@ -1,17 +1,7 @@ { - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "lib": ["es2015", "dom"], - "outDir": "lib", - "sourceMap": true, - "declaration": true, - "noImplicitAny": true, - "strictNullChecks": true - }, - "include": [ - "./src/**/*", - "./test/**/*", - "../../node_modules/web3-typescript-typings/index.d.ts" - ] + "extends": "../../tsconfig", + "compilerOptions": { + "outDir": "lib" + }, + "include": ["./src/**/*", "./test/**/*", "../../node_modules/web3-typescript-typings/index.d.ts"] } diff --git a/packages/abi-gen/tslint.json b/packages/abi-gen/tslint.json index a07795151..ffaefe83a 100644 --- a/packages/abi-gen/tslint.json +++ b/packages/abi-gen/tslint.json @@ -1,5 +1,3 @@ { - "extends": [ - "@0xproject/tslint-config" - ] + "extends": ["@0xproject/tslint-config"] } diff --git a/packages/assert/CHANGELOG.md b/packages/assert/CHANGELOG.md index fd6bec3f4..cd04130de 100644 --- a/packages/assert/CHANGELOG.md +++ b/packages/assert/CHANGELOG.md @@ -1,6 +1,6 @@ # CHANGELOG -v0.0.4 - _Nov. 14, 2017_ ------------------------- +## v0.0.4 - _Nov. 14, 2017_ + * Re-publish Assert previously published under NPM package @0xproject/0x-assert * Added assertion isValidBaseUnitAmount which checks both that the value is a valid bigNumber and that it does not contain decimals. diff --git a/packages/assert/README.md b/packages/assert/README.md index b0dc9a451..59ab63e91 100644 --- a/packages/assert/README.md +++ b/packages/assert/README.md @@ -1,10 +1,55 @@ -assert ------- +## @0xproject/assert Standard type and schema assertions to be used across all 0x projects and packages -## Install +## Installation ```bash -npm install @0xproject/assert --save +yarn add @0xproject/assert +``` + +## Usage + +```typescript +import { assert } from '@0xproject/assert'; + +assert.isValidBaseUnitAmount('baseUnitAmount', baseUnitAmount); +``` + +## Contributing + +We strongly encourage that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. + +Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. + +### Install Dependencies + +If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: + +```bash +yarn config set workspaces-experimental true +``` + +Then install dependencies + +```bash +yarn install +``` + +### Build + +```bash +yarn build +``` + +### Lint + +```bash +yarn lint +``` + +### Run Tests + +```bash +yarn test ``` diff --git a/packages/assert/package.json b/packages/assert/package.json index 68d1ebb05..1c25b4e40 100644 --- a/packages/assert/package.json +++ b/packages/assert/package.json @@ -1,46 +1,45 @@ { - "name": "@0xproject/assert", - "version": "0.0.6", - "description": "Provides a standard way of performing type and schema validation across 0x projects", - "main": "lib/src/index.js", - "types": "lib/src/index.d.ts", - "scripts": { - "build": "tsc", - "clean": "shx rm -rf _bundles lib test_temp", - "lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'", - "run_mocha": "mocha lib/test/**/*_test.js", - "prepublishOnly": "run-p build", - "test": "run-s clean build run_mocha", - "test:circleci": "yarn test" - }, - "license": "Apache-2.0", - "repository": { - "type": "git", - "url": "https://github.com/0xProject/0x.js.git" - }, - "bugs": { - "url": "https://github.com/0xProject/0x.js/issues" - }, - "homepage": "https://github.com/0xProject/0x.js/packages/assert/README.md", - "devDependencies": { - "@0xproject/tslint-config": "^0.2.0", - "@types/lodash": "^4.14.86", - "@types/mocha": "^2.2.42", - "@types/valid-url": "^1.0.2", - "chai": "^4.0.1", - "chai-typescript-typings": "^0.0.1", - "dirty-chai": "^2.0.1", - "mocha": "^4.0.1", - "npm-run-all": "^4.1.2", - "shx": "^0.2.2", - "tslint": "5.8.0", - "typescript": "~2.6.1" - }, - "dependencies": { - "@0xproject/json-schemas": "^0.6.9", - "bignumber.js": "~4.1.0", - "ethereum-address": "^0.0.4", - "lodash": "^4.17.4", - "valid-url": "^1.0.9" - } + "name": "@0xproject/assert", + "version": "0.0.12", + "description": "Provides a standard way of performing type and schema validation across 0x projects", + "main": "lib/src/index.js", + "types": "lib/src/index.d.ts", + "scripts": { + "build": "tsc", + "clean": "shx rm -rf _bundles lib test_temp", + "lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'", + "run_mocha": "mocha lib/test/**/*_test.js", + "prepublishOnly": "run-p build", + "test": "run-s clean build run_mocha", + "test:circleci": "yarn test" + }, + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/0xProject/0x.js.git" + }, + "bugs": { + "url": "https://github.com/0xProject/0x.js/issues" + }, + "homepage": "https://github.com/0xProject/0x.js/packages/assert/README.md", + "devDependencies": { + "@0xproject/tslint-config": "^0.4.3", + "@types/lodash": "^4.14.86", + "@types/mocha": "^2.2.42", + "@types/valid-url": "^1.0.2", + "chai": "^4.0.1", + "chai-typescript-typings": "^0.0.2", + "dirty-chai": "^2.0.1", + "mocha": "^4.0.1", + "npm-run-all": "^4.1.2", + "shx": "^0.2.2", + "tslint": "5.8.0", + "typescript": "~2.6.1" + }, + "dependencies": { + "@0xproject/json-schemas": "^0.7.4", + "@0xproject/utils": "^0.2.1", + "lodash": "^4.17.4", + "valid-url": "^1.0.9" + } } diff --git a/packages/assert/scripts/postpublish.js b/packages/assert/scripts/postpublish.js index 7fa452b08..16d67e03f 100644 --- a/packages/assert/scripts/postpublish.js +++ b/packages/assert/scripts/postpublish.js @@ -3,12 +3,13 @@ const packageJSON = require('../package.json'); const subPackageName = packageJSON.name; -postpublish_utils.getLatestTagAndVersionAsync(subPackageName) +postpublish_utils + .getLatestTagAndVersionAsync(subPackageName) .then(function(result) { const releaseName = postpublish_utils.getReleaseName(subPackageName, result.version); const assets = []; return postpublish_utils.publishReleaseNotes(result.tag, releaseName, assets); }) - .catch (function(err) { + .catch(function(err) { throw err; }); diff --git a/packages/assert/src/globals.d.ts b/packages/assert/src/globals.d.ts index cc47f3113..91ed2021e 100644 --- a/packages/assert/src/globals.d.ts +++ b/packages/assert/src/globals.d.ts @@ -1,5 +1 @@ declare module 'dirty-chai'; - -declare module 'ethereum-address' { - const isAddress: (arg: any) => boolean; -} diff --git a/packages/assert/src/index.ts b/packages/assert/src/index.ts index 92bcf6f03..7ad574ec7 100644 --- a/packages/assert/src/index.ts +++ b/packages/assert/src/index.ts @@ -1,9 +1,5 @@ -import { - Schema, - SchemaValidator, -} from '@0xproject/json-schemas'; -import BigNumber from 'bignumber.js'; -import * as ethereum_address from 'ethereum-address'; +import { Schema, SchemaValidator } from '@0xproject/json-schemas'; +import { addressUtils, BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import * as validUrl from 'valid-url'; @@ -16,14 +12,14 @@ export const assert = { }, isValidBaseUnitAmount(variableName: string, value: BigNumber) { assert.isBigNumber(variableName, value); + const isNegative = value.lessThan(0); + this.assert(!isNegative, `${variableName} cannot be a negative number, found value: ${value.toNumber()}`); const hasDecimals = value.decimalPlaces() !== 0; this.assert( - !hasDecimals, `${variableName} should be in baseUnits (no decimals), found value: ${value.toNumber()}`, + !hasDecimals, + `${variableName} should be in baseUnits (no decimals), found value: ${value.toNumber()}`, ); }, - isUndefined(value: any, variableName?: string): void { - this.assert(_.isUndefined(value), this.typeAssertionMessage(variableName, 'undefined', value)); - }, isString(variableName: string, value: string): void { this.assert(_.isString(value), this.typeAssertionMessage(variableName, 'string', value)); }, @@ -31,18 +27,23 @@ export const assert = { this.assert(_.isFunction(value), this.typeAssertionMessage(variableName, 'function', value)); }, isHexString(variableName: string, value: string): void { - this.assert(_.isString(value) && HEX_REGEX.test(value), - this.typeAssertionMessage(variableName, 'HexString', value)); + this.assert( + _.isString(value) && HEX_REGEX.test(value), + this.typeAssertionMessage(variableName, 'HexString', value), + ); }, isETHAddressHex(variableName: string, value: string): void { - this.assert(ethereum_address.isAddress(value), this.typeAssertionMessage(variableName, 'ETHAddressHex', value)); + this.assert(addressUtils.isAddress(value), this.typeAssertionMessage(variableName, 'ETHAddressHex', value)); this.assert( - ethereum_address.isAddress(value) && value.toLowerCase() === value, + addressUtils.isAddress(value) && value.toLowerCase() === value, `Checksummed addresses are not supported. Convert ${variableName} to lower case before passing`, ); }, - doesBelongToStringEnum(variableName: string, value: string, - stringEnum: any /* There is no base type for every string enum */): void { + doesBelongToStringEnum( + variableName: string, + value: string, + stringEnum: any /* There is no base type for every string enum */, + ): void { const doesBelongToStringEnum = !_.isUndefined(stringEnum[value]); const enumValues = _.keys(stringEnum); const enumValuesAsStrings = _.map(enumValues, enumValue => `'${enumValue}'`); @@ -62,7 +63,7 @@ export const assert = { this.assert(_.isBoolean(value), this.typeAssertionMessage(variableName, 'boolean', value)); }, isWeb3Provider(variableName: string, value: any): void { - const isWeb3Provider = _.isFunction((value).send) || _.isFunction((value).sendAsync); + const isWeb3Provider = _.isFunction(value.send) || _.isFunction(value.sendAsync); this.assert(isWeb3Provider, this.typeAssertionMessage(variableName, 'Web3.Provider', value)); }, doesConformToSchema(variableName: string, value: any, schema: Schema): void { @@ -75,11 +76,11 @@ Validation errors: ${validationResult.errors.join(', ')}`; this.assert(!hasValidationErrors, msg); }, isHttpUrl(variableName: string, value: any): void { - const isValidUrl = validUrl.isWebUri(value); + const isValidUrl = !_.isUndefined(validUrl.isWebUri(value)); this.assert(isValidUrl, this.typeAssertionMessage(variableName, 'http url', value)); }, isUri(variableName: string, value: any): void { - const isValidUri = validUrl.isUri(value); + const isValidUri = !_.isUndefined(validUrl.isUri(value)); this.assert(isValidUri, this.typeAssertionMessage(variableName, 'uri', value)); }, assert(condition: boolean, message: string): void { diff --git a/packages/assert/test/assert_test.ts b/packages/assert/test/assert_test.ts index 5fa96e49a..b0fa398d6 100644 --- a/packages/assert/test/assert_test.ts +++ b/packages/assert/test/assert_test.ts @@ -1,10 +1,10 @@ -import {schemas} from '@0xproject/json-schemas'; -import {BigNumber} from 'bignumber.js'; +import { schemas } from '@0xproject/json-schemas'; +import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import * as dirtyChai from 'dirty-chai'; import 'mocha'; -import {assert} from '../src/index'; +import { assert } from '../src/index'; chai.config.includeStack = true; chai.use(dirtyChai); @@ -14,75 +14,45 @@ describe('Assertions', () => { const variableName = 'variable'; describe('#isBigNumber', () => { it('should not throw for valid input', () => { - const validInputs = [ - new BigNumber(23), - new BigNumber('45'), - ]; + const validInputs = [new BigNumber(23), new BigNumber('45')]; validInputs.forEach(input => expect(assert.isBigNumber.bind(assert, variableName, input)).to.not.throw()); }); it('should throw for invalid input', () => { - const invalidInputs = [ - 'test', - 42, - false, - { random: 'test' }, - undefined, - ]; + const invalidInputs = ['test', 42, false, { random: 'test' }, undefined]; invalidInputs.forEach(input => expect(assert.isBigNumber.bind(assert, variableName, input)).to.throw()); }); }); - describe('#isUndefined', () => { + describe('#isValidBaseUnitAmount', () => { it('should not throw for valid input', () => { - const validInputs = [ - undefined, - ]; - validInputs.forEach(input => expect(assert.isUndefined.bind(assert, input, variableName)).to.not.throw()); + const validInputs = [new BigNumber(23), new BigNumber('45000000')]; + validInputs.forEach(input => + expect(assert.isValidBaseUnitAmount.bind(assert, variableName, input)).to.not.throw(), + ); }); it('should throw for invalid input', () => { - const invalidInputs = [ - 'test', - 42, - false, - { random: 'test' }, - ]; - invalidInputs.forEach(input => expect(assert.isUndefined.bind(assert, input, variableName)).to.throw()); + const invalidInputs = [0, undefined, new BigNumber(3.145), 3.145, new BigNumber(-400)]; + invalidInputs.forEach(input => + expect(assert.isValidBaseUnitAmount.bind(assert, variableName, input)).to.throw(), + ); }); }); describe('#isString', () => { it('should not throw for valid input', () => { - const validInputs = [ - 'hello', - 'goodbye', - ]; + const validInputs = ['hello', 'goodbye']; validInputs.forEach(input => expect(assert.isString.bind(assert, variableName, input)).to.not.throw()); }); it('should throw for invalid input', () => { - const invalidInputs = [ - 42, - false, - { random: 'test' }, - undefined, - new BigNumber(45), - ]; + const invalidInputs = [42, false, { random: 'test' }, undefined, new BigNumber(45)]; invalidInputs.forEach(input => expect(assert.isString.bind(assert, variableName, input)).to.throw()); }); }); describe('#isFunction', () => { it('should not throw for valid input', () => { - const validInputs = [ - BigNumber, - assert.isString.bind(this), - ]; + const validInputs = [BigNumber, assert.isString]; validInputs.forEach(input => expect(assert.isFunction.bind(assert, variableName, input)).to.not.throw()); }); it('should throw for invalid input', () => { - const invalidInputs = [ - 42, - false, - { random: 'test' }, - undefined, - new BigNumber(45), - ]; + const invalidInputs = [42, false, { random: 'test' }, undefined, new BigNumber(45)]; invalidInputs.forEach(input => expect(assert.isFunction.bind(assert, variableName, input)).to.throw()); }); }); @@ -127,9 +97,7 @@ describe('Assertions', () => { '0x6FFFd0ae3f7d88c9b4925323f54c6e4b2918c5fd', '0x6FFFd0ae3f7d88c9b4925323f54c6e4', ]; - invalidInputs.forEach(input => - expect(assert.isETHAddressHex.bind(assert, variableName, input)).to.throw(), - ); + invalidInputs.forEach(input => expect(assert.isETHAddressHex.bind(assert, variableName, input)).to.throw()); }); }); describe('#doesBelongToStringEnum', () => { @@ -138,22 +106,13 @@ describe('Assertions', () => { Test2 = 'Test2', } it('should not throw for valid input', () => { - const validInputs = [ - TestEnums.Test1, - TestEnums.Test2, - ]; + const validInputs = [TestEnums.Test1, TestEnums.Test2]; validInputs.forEach(input => expect(assert.doesBelongToStringEnum.bind(assert, variableName, input, TestEnums)).to.not.throw(), ); }); it('should throw for invalid input', () => { - const invalidInputs = [ - 42, - false, - { random: 'test' }, - undefined, - new BigNumber(45), - ]; + const invalidInputs = [42, false, { random: 'test' }, undefined, new BigNumber(45)]; invalidInputs.forEach(input => expect(assert.doesBelongToStringEnum.bind(assert, variableName, input, TestEnums)).to.throw(), ); @@ -162,19 +121,13 @@ describe('Assertions', () => { describe('#hasAtMostOneUniqueValue', () => { const errorMsg = 'more than one unique value'; it('should not throw for valid input', () => { - const validInputs = [ - ['hello'], - ['goodbye', 'goodbye', 'goodbye'], - ]; + const validInputs = [['hello'], ['goodbye', 'goodbye', 'goodbye']]; validInputs.forEach(input => expect(assert.hasAtMostOneUniqueValue.bind(assert, input, errorMsg)).to.not.throw(), ); }); it('should throw for invalid input', () => { - const invalidInputs = [ - ['hello', 'goodbye'], - ['goodbye', 42, false, false], - ]; + const invalidInputs = [['hello', 'goodbye'], ['goodbye', 42, false, false]]; invalidInputs.forEach(input => expect(assert.hasAtMostOneUniqueValue.bind(assert, input, errorMsg)).to.throw(), ); @@ -182,61 +135,34 @@ describe('Assertions', () => { }); describe('#isNumber', () => { it('should not throw for valid input', () => { - const validInputs = [ - 42, - 0, - 21e+42, - ]; + const validInputs = [42, 0, 21e42]; validInputs.forEach(input => expect(assert.isNumber.bind(assert, variableName, input)).to.not.throw()); }); it('should throw for invalid input', () => { - const invalidInputs = [ - false, - { random: 'test' }, - undefined, - new BigNumber(45), - ]; + const invalidInputs = [false, { random: 'test' }, undefined, new BigNumber(45)]; invalidInputs.forEach(input => expect(assert.isNumber.bind(assert, variableName, input)).to.throw()); }); }); describe('#isBoolean', () => { it('should not throw for valid input', () => { - const validInputs = [ - true, - false, - ]; + const validInputs = [true, false]; validInputs.forEach(input => expect(assert.isBoolean.bind(assert, variableName, input)).to.not.throw()); }); it('should throw for invalid input', () => { - const invalidInputs = [ - 42, - { random: 'test' }, - undefined, - new BigNumber(45), - ]; + const invalidInputs = [42, { random: 'test' }, undefined, new BigNumber(45)]; invalidInputs.forEach(input => expect(assert.isBoolean.bind(assert, variableName, input)).to.throw()); }); }); describe('#isWeb3Provider', () => { it('should not throw for valid input', () => { - const validInputs = [ - { send: () => 45 }, - { sendAsync: () => 45 }, - ]; + const validInputs = [{ send: () => 45 }, { sendAsync: () => 45 }]; validInputs.forEach(input => expect(assert.isWeb3Provider.bind(assert, variableName, input)).to.not.throw(), ); }); it('should throw for invalid input', () => { - const invalidInputs = [ - 42, - { random: 'test' }, - undefined, - new BigNumber(45), - ]; - invalidInputs.forEach(input => - expect(assert.isWeb3Provider.bind(assert, variableName, input)).to.throw(), - ); + const invalidInputs = [42, { random: 'test' }, undefined, new BigNumber(45)]; + invalidInputs.forEach(input => expect(assert.isWeb3Provider.bind(assert, variableName, input)).to.throw()); }); }); describe('#doesConformToSchema', () => { @@ -251,12 +177,7 @@ describe('Assertions', () => { ); }); it('should throw for invalid input', () => { - const invalidInputs = [ - 42, - { random: 'test' }, - undefined, - new BigNumber(45), - ]; + const invalidInputs = [42, { random: 'test' }, undefined, new BigNumber(45)]; invalidInputs.forEach(input => expect(assert.doesConformToSchema.bind(assert, variableName, input, schema)).to.throw(), ); @@ -270,9 +191,7 @@ describe('Assertions', () => { 'https://api.radarrelay.com/0x/v0/', 'https://zeroex.beta.radarrelay.com:8000/0x/v0/', ]; - validInputs.forEach(input => - expect(assert.isHttpUrl.bind(assert, variableName, input)).to.not.throw(), - ); + validInputs.forEach(input => expect(assert.isHttpUrl.bind(assert, variableName, input)).to.not.throw()); }); it('should throw for invalid input', () => { const invalidInputs = [ @@ -286,9 +205,7 @@ describe('Assertions', () => { 'user:password@api.example-relayer.net', '//api.example-relayer.net', ]; - invalidInputs.forEach(input => - expect(assert.isHttpUrl.bind(assert, variableName, input)).to.throw(), - ); + invalidInputs.forEach(input => expect(assert.isHttpUrl.bind(assert, variableName, input)).to.throw()); }); }); describe('#isUri', () => { @@ -302,9 +219,7 @@ describe('Assertions', () => { 'wss://www.api.example-relayer.net', 'user:password@api.example-relayer.net', ]; - validInputs.forEach(input => - expect(assert.isUri.bind(assert, variableName, input)).to.not.throw(), - ); + validInputs.forEach(input => expect(assert.isUri.bind(assert, variableName, input)).to.not.throw()); }); it('should throw for invalid input', () => { const invalidInputs = [ @@ -316,9 +231,7 @@ describe('Assertions', () => { 'api.example-relayer.net', '//api.example-relayer.net', ]; - invalidInputs.forEach(input => - expect(assert.isUri.bind(assert, variableName, input)).to.throw(), - ); + invalidInputs.forEach(input => expect(assert.isUri.bind(assert, variableName, input)).to.throw()); }); }); describe('#assert', () => { @@ -332,8 +245,9 @@ describe('Assertions', () => { }); describe('#typeAssertionMessage', () => { it('should render correct message', () => { - expect(assert.typeAssertionMessage('variable', 'string', 'number')) - .to.equal(`Expected variable to be of type string, encountered: number`); + expect(assert.typeAssertionMessage('variable', 'string', 'number')).to.equal( + `Expected variable to be of type string, encountered: number`, + ); }); }); }); diff --git a/packages/assert/tsconfig.json b/packages/assert/tsconfig.json index 709e20154..88a467ccb 100644 --- a/packages/assert/tsconfig.json +++ b/packages/assert/tsconfig.json @@ -1,18 +1,7 @@ { - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "lib": [ "es2017", "dom"], - "outDir": "lib", - "sourceMap": true, - "declaration": true, - "noImplicitAny": true, - "strictNullChecks": true - }, - "include": [ - "./src/**/*", - "./test/**/*", - "../../node_modules/chai-typescript-typings/index.d.ts", - "../../node_modules/web3-typescript-typings/index.d.ts" - ] + "extends": "../../tsconfig", + "compilerOptions": { + "outDir": "lib" + }, + "include": ["./src/**/*", "./test/**/*", "../../node_modules/chai-typescript-typings/index.d.ts"] } diff --git a/packages/assert/tslint.json b/packages/assert/tslint.json index a07795151..ffaefe83a 100644 --- a/packages/assert/tslint.json +++ b/packages/assert/tslint.json @@ -1,5 +1,3 @@ { - "extends": [ - "@0xproject/tslint-config" - ] + "extends": ["@0xproject/tslint-config"] } diff --git a/packages/chai-as-promised-typescript-typings/CHANGELOG.md b/packages/chai-as-promised-typescript-typings/CHANGELOG.md new file mode 100644 index 000000000..8c52570da --- /dev/null +++ b/packages/chai-as-promised-typescript-typings/CHANGELOG.md @@ -0,0 +1,3 @@ +# CHANGELOG + +## v0.x.x - _TBD, 2018_ diff --git a/packages/chai-as-promised-typescript-typings/README.md b/packages/chai-as-promised-typescript-typings/README.md new file mode 100644 index 000000000..72784ef53 --- /dev/null +++ b/packages/chai-as-promised-typescript-typings/README.md @@ -0,0 +1,43 @@ +## chai-as-promised-typescript-typings + +Fork of type definitions for chai-as-promised that includes changes made by dirty-chai + +## Installation + +```bash +yarn add -D chai-as-promised-typescript-typings +``` + +## Usage + +Add the following line within an `include` section of your `tsconfig.json` + +```json +"./node_modules/chai-as-promised-typescript-typings/index.d.ts" +``` + +## Contributing + +We strongly encourage that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. + +Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. + +### Install Dependencies + +If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: + +```bash +yarn config set workspaces-experimental true +``` + +Then install dependencies + +```bash +yarn install +``` + +### Lint + +```bash +yarn lint +``` diff --git a/packages/chai-as-promised-typescript-typings/index.d.ts b/packages/chai-as-promised-typescript-typings/index.d.ts new file mode 100644 index 000000000..ba6dabdcc --- /dev/null +++ b/packages/chai-as-promised-typescript-typings/index.d.ts @@ -0,0 +1,268 @@ +// Type definitions for chai-as-promised +// Project: https://github.com/domenic/chai-as-promised/ +// Definitions by: jt000 <https://github.com/jt000>, Yuki Kokubun <https://github.com/Kuniwak> +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +declare module 'chai-as-promised' { + function chaiAsPromised(chai: any, utils: any): void; + namespace chaiAsPromised { + + } + export = chaiAsPromised; +} + +// tslint:disable:no-namespace ban-types member-ordering +declare namespace Chai { + // For BDD API + interface Assertion extends LanguageChains, NumericComparison, TypeComparison { + eventually: PromisedAssertion; + fulfilled: PromisedAssertion; + become(expected: any): PromisedAssertion; + rejected(): PromisedAssertion; + rejectedWith(expected: any, message?: string | RegExp): PromisedAssertion; + notify(fn: Function): PromisedAssertion; + } + + // Eventually does not have .then(), but PromisedAssertion have. + interface Eventually extends PromisedLanguageChains, PromisedNumericComparison, PromisedTypeComparison { + // From chai-as-promised + become(expected: PromiseLike<any>): PromisedAssertion; + fulfilled: PromisedAssertion; + rejected: () => PromisedAssertion; + rejectedWith(expected: any, message?: string | RegExp): PromisedAssertion; + notify(fn: Function): PromisedAssertion; + + // From chai + not: PromisedAssertion; + deep: PromisedDeep; + all: PromisedKeyFilter; + a: PromisedTypeComparison; + an: PromisedTypeComparison; + include: PromisedInclude; + contain: PromisedInclude; + ok: PromisedAssertion; + true: () => PromisedAssertion; + false: () => PromisedAssertion; + null: PromisedAssertion; + undefined: PromisedAssertion; + exist: PromisedAssertion; + empty: PromisedAssertion; + arguments: PromisedAssertion; + Arguments: PromisedAssertion; + equal: PromisedEqual; + equals: PromisedEqual; + eq: PromisedEqual; + eql: PromisedEqual; + eqls: PromisedEqual; + property: PromisedProperty; + ownProperty: PromisedOwnProperty; + haveOwnProperty: PromisedOwnProperty; + length: PromisedLength; + lengthOf: PromisedLength; + match(regexp: RegExp | string, message?: string): PromisedAssertion; + string(string: string, message?: string): PromisedAssertion; + keys: PromisedKeys; + key(string: string): PromisedAssertion; + throw: PromisedThrow; + throws: PromisedThrow; + Throw: PromisedThrow; + respondTo(method: string, message?: string): PromisedAssertion; + itself: PromisedAssertion; + satisfy(matcher: Function, message?: string): PromisedAssertion; + closeTo(expected: number, delta: number, message?: string): PromisedAssertion; + members: PromisedMembers; + } + + interface PromisedAssertion extends Eventually, PromiseLike<any> {} + + interface PromisedLanguageChains { + eventually: Eventually; + + // From chai + to: PromisedAssertion; + be: PromisedAssertion; + been: PromisedAssertion; + is: PromisedAssertion; + that: PromisedAssertion; + which: PromisedAssertion; + and: PromisedAssertion; + has: PromisedAssertion; + have: PromisedAssertion; + with: PromisedAssertion; + at: PromisedAssertion; + of: PromisedAssertion; + same: PromisedAssertion; + } + + interface PromisedNumericComparison { + above: PromisedNumberComparer; + gt: PromisedNumberComparer; + greaterThan: PromisedNumberComparer; + least: PromisedNumberComparer; + gte: PromisedNumberComparer; + below: PromisedNumberComparer; + lt: PromisedNumberComparer; + lessThan: PromisedNumberComparer; + most: PromisedNumberComparer; + lte: PromisedNumberComparer; + within(start: number, finish: number, message?: string): PromisedAssertion; + } + + type PromisedNumberComparer = (value: number, message?: string) => PromisedAssertion; + + interface PromisedTypeComparison { + (type: string, message?: string): PromisedAssertion; + instanceof: PromisedInstanceOf; + instanceOf: PromisedInstanceOf; + } + + type PromisedInstanceOf = (constructor: Object, message?: string) => PromisedAssertion; + + interface PromisedDeep { + equal: PromisedEqual; + include: PromisedInclude; + property: PromisedProperty; + } + + interface PromisedKeyFilter { + keys: PromisedKeys; + } + + type PromisedEqual = (value: any, message?: string) => PromisedAssertion; + + type PromisedProperty = (name: string, value?: any, message?: string) => PromisedAssertion; + + type PromisedOwnProperty = (name: string, message?: string) => PromisedAssertion; + + interface PromisedLength extends PromisedLanguageChains, PromisedNumericComparison { + (length: number, message?: string): PromisedAssertion; + } + + interface PromisedInclude { + (value: Object | string | number, message?: string): PromisedAssertion; + keys: PromisedKeys; + members: PromisedMembers; + all: PromisedKeyFilter; + } + + interface PromisedKeys { + (...keys: string[]): PromisedAssertion; + (keys: any[]): PromisedAssertion; + } + + interface PromisedThrow { + (): PromisedAssertion; + (expected: string | RegExp, message?: string): PromisedAssertion; + (constructor: Error | Function, expected?: string | RegExp, message?: string): PromisedAssertion; + } + + type PromisedMembers = (set: any[], message?: string) => PromisedAssertion; + + // For Assert API + interface Assert { + eventually: PromisedAssert; + isFulfilled(promise: PromiseLike<any>, message?: string): PromiseLike<void>; + becomes(promise: PromiseLike<any>, expected: any, message?: string): PromiseLike<void>; + doesNotBecome(promise: PromiseLike<any>, expected: any, message?: string): PromiseLike<void>; + isRejected(promise: PromiseLike<any>, message?: string): PromiseLike<void>; + isRejected(promise: PromiseLike<any>, expected: any | RegExp, message?: string): PromiseLike<void>; + notify(fn: Function): PromiseLike<void>; + } + + export interface PromisedAssert { + fail(actual?: any, expected?: any, msg?: string, operator?: string): PromiseLike<void>; + + ok(val: any, msg?: string): PromiseLike<void>; + notOk(val: any, msg?: string): PromiseLike<void>; + + equal(act: any, exp: any, msg?: string): PromiseLike<void>; + notEqual(act: any, exp: any, msg?: string): PromiseLike<void>; + + strictEqual(act: any, exp: any, msg?: string): PromiseLike<void>; + notStrictEqual(act: any, exp: any, msg?: string): PromiseLike<void>; + + deepEqual(act: any, exp: any, msg?: string): PromiseLike<void>; + notDeepEqual(act: any, exp: any, msg?: string): PromiseLike<void>; + + isTrue(val: any, msg?: string): PromiseLike<void>; + isFalse(val: any, msg?: string): PromiseLike<void>; + + isNull(val: any, msg?: string): PromiseLike<void>; + isNotNull(val: any, msg?: string): PromiseLike<void>; + + isUndefined(val: any, msg?: string): PromiseLike<void>; + isDefined(val: any, msg?: string): PromiseLike<void>; + + isFunction(val: any, msg?: string): PromiseLike<void>; + isNotFunction(val: any, msg?: string): PromiseLike<void>; + + isObject(val: any, msg?: string): PromiseLike<void>; + isNotObject(val: any, msg?: string): PromiseLike<void>; + + isArray(val: any, msg?: string): PromiseLike<void>; + isNotArray(val: any, msg?: string): PromiseLike<void>; + + isString(val: any, msg?: string): PromiseLike<void>; + isNotString(val: any, msg?: string): PromiseLike<void>; + + isNumber(val: any, msg?: string): PromiseLike<void>; + isNotNumber(val: any, msg?: string): PromiseLike<void>; + + isBoolean(val: any, msg?: string): PromiseLike<void>; + isNotBoolean(val: any, msg?: string): PromiseLike<void>; + + typeOf(val: any, type: string, msg?: string): PromiseLike<void>; + notTypeOf(val: any, type: string, msg?: string): PromiseLike<void>; + + instanceOf(val: any, type: Function, msg?: string): PromiseLike<void>; + notInstanceOf(val: any, type: Function, msg?: string): PromiseLike<void>; + + include(exp: string | any[], inc: any, msg?: string): PromiseLike<void>; + + notInclude(exp: string | any[], inc: any, msg?: string): PromiseLike<void>; + + match(exp: any, re: RegExp, msg?: string): PromiseLike<void>; + notMatch(exp: any, re: RegExp, msg?: string): PromiseLike<void>; + + property(obj: Object, prop: string, msg?: string): PromiseLike<void>; + notProperty(obj: Object, prop: string, msg?: string): PromiseLike<void>; + deepProperty(obj: Object, prop: string, msg?: string): PromiseLike<void>; + notDeepProperty(obj: Object, prop: string, msg?: string): PromiseLike<void>; + + propertyVal(obj: Object, prop: string, val: any, msg?: string): PromiseLike<void>; + propertyNotVal(obj: Object, prop: string, val: any, msg?: string): PromiseLike<void>; + + deepPropertyVal(obj: Object, prop: string, val: any, msg?: string): PromiseLike<void>; + deepPropertyNotVal(obj: Object, prop: string, val: any, msg?: string): PromiseLike<void>; + + lengthOf(exp: any, len: number, msg?: string): PromiseLike<void>; + // alias frenzy + throw(fn: Function, msg?: string): PromiseLike<void>; + throw(fn: Function, regExp: RegExp): PromiseLike<void>; + throw(fn: Function, errType: Function, msg?: string): PromiseLike<void>; + throw(fn: Function, errType: Function, regExp: RegExp): PromiseLike<void>; + + throws(fn: Function, msg?: string): PromiseLike<void>; + throws(fn: Function, regExp: RegExp): PromiseLike<void>; + throws(fn: Function, errType: Function, msg?: string): PromiseLike<void>; + throws(fn: Function, errType: Function, regExp: RegExp): PromiseLike<void>; + + Throw(fn: Function, msg?: string): PromiseLike<void>; + Throw(fn: Function, regExp: RegExp): PromiseLike<void>; + Throw(fn: Function, errType: Function, msg?: string): PromiseLike<void>; + Throw(fn: Function, errType: Function, regExp: RegExp): PromiseLike<void>; + + doesNotThrow(fn: Function, msg?: string): PromiseLike<void>; + doesNotThrow(fn: Function, regExp: RegExp): PromiseLike<void>; + doesNotThrow(fn: Function, errType: Function, msg?: string): PromiseLike<void>; + doesNotThrow(fn: Function, errType: Function, regExp: RegExp): PromiseLike<void>; + + operator(val: any, operator: string, val2: any, msg?: string): PromiseLike<void>; + closeTo(act: number, exp: number, delta: number, msg?: string): PromiseLike<void>; + + sameMembers(set1: any[], set2: any[], msg?: string): PromiseLike<void>; + includeMembers(set1: any[], set2: any[], msg?: string): PromiseLike<void>; + + ifError(val: any, msg?: string): PromiseLike<void>; + } +} diff --git a/packages/chai-as-promised-typescript-typings/package.json b/packages/chai-as-promised-typescript-typings/package.json new file mode 100644 index 000000000..34f4ed1f3 --- /dev/null +++ b/packages/chai-as-promised-typescript-typings/package.json @@ -0,0 +1,23 @@ +{ + "name": "chai-as-promised-typescript-typings", + "version": "0.0.5", + "description": "Typescript type definitions for chai-as-promised", + "main": "index.d.ts", + "types": "index.d.ts", + "repository": { + "type": "git", + "url": "git+https://github.com/0xProject/0x.js.git" + }, + "author": "Fabio Berger", + "contributors": [ + "Leonid Logvinov <logvinov.leon@gmail.com>" + ], + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/0xProject/0x.js/issues" + }, + "homepage": "https://github.com/0xProject/0x.js/packages/chai-as-promised-typescript-typings#readme", + "dependencies": { + "chai-typescript-typings": "^0.0.0" + } +} diff --git a/packages/chai-as-promised-typescript-typings/scripts/postpublish.js b/packages/chai-as-promised-typescript-typings/scripts/postpublish.js new file mode 100644 index 000000000..16d67e03f --- /dev/null +++ b/packages/chai-as-promised-typescript-typings/scripts/postpublish.js @@ -0,0 +1,15 @@ +const postpublish_utils = require('../../../scripts/postpublish_utils'); +const packageJSON = require('../package.json'); + +const subPackageName = packageJSON.name; + +postpublish_utils + .getLatestTagAndVersionAsync(subPackageName) + .then(function(result) { + const releaseName = postpublish_utils.getReleaseName(subPackageName, result.version); + const assets = []; + return postpublish_utils.publishReleaseNotes(result.tag, releaseName, assets); + }) + .catch(function(err) { + throw err; + }); diff --git a/packages/chai-as-promised-typescript-typings/tslint.json b/packages/chai-as-promised-typescript-typings/tslint.json new file mode 100644 index 000000000..9a93a1f74 --- /dev/null +++ b/packages/chai-as-promised-typescript-typings/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": ["tslint-config-0xproject"] +} diff --git a/packages/chai-typescript-typings/CHANGELOG.md b/packages/chai-typescript-typings/CHANGELOG.md new file mode 100644 index 000000000..8c52570da --- /dev/null +++ b/packages/chai-typescript-typings/CHANGELOG.md @@ -0,0 +1,3 @@ +# CHANGELOG + +## v0.x.x - _TBD, 2018_ diff --git a/packages/chai-typescript-typings/README.md b/packages/chai-typescript-typings/README.md new file mode 100644 index 000000000..9bd0574d1 --- /dev/null +++ b/packages/chai-typescript-typings/README.md @@ -0,0 +1,43 @@ +## chai-typescript-typings + +Fork of type definitions for chai that includes changes made by dirty-chai + +## Installation + +```bash +yarn add -D chai-typescript-typings +``` + +## Usage + +Add the following line within an `include` section of your `tsconfig.json` + +```json +"./node_modules/chai-typescript-typings/index.d.ts" +``` + +## Contributing + +We strongly encourage that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. + +Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. + +### Install Dependencies + +If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: + +```bash +yarn config set workspaces-experimental true +``` + +Then install dependencies + +```bash +yarn install +``` + +### Lint + +```bash +yarn lint +``` diff --git a/packages/chai-typescript-typings/index.d.ts b/packages/chai-typescript-typings/index.d.ts new file mode 100644 index 000000000..8b3e4c079 --- /dev/null +++ b/packages/chai-typescript-typings/index.d.ts @@ -0,0 +1,1254 @@ +// Type definitions for chai 4.0.0 +// Project: http://chaijs.com/ +// Definitions by: Jed Mao <https://github.com/jedmao/>, +// Bart van der Schoor <https://github.com/Bartvds>, +// Andrew Brown <https://github.com/AGBrown>, +// Olivier Chevet <https://github.com/olivr70>, +// Matt Wistrand <https://github.com/mwistrand>, +// Josh Goldberg <https://github.com/joshuakgoldberg> +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +// <reference types="assertion-error"/> + +// tslint:disable:no-namespace member-ordering ban-types unified-signatures variable-name callable-types +declare namespace Chai { + interface ChaiStatic { + expect: ExpectStatic; + should(): Should; + /** + * Provides a way to extend the internals of Chai + */ + use(fn: (chai: any, utils: any) => void): ChaiStatic; + assert: AssertStatic; + config: Config; + AssertionError: typeof AssertionError; + version: string; + } + + export interface ExpectStatic extends AssertionStatic { + fail(actual?: any, expected?: any, message?: string, operator?: Operator): void; + } + + export interface AssertStatic extends Assert {} + + type AssertionStatic = (target: any, message?: string) => Assertion; + + export type Operator = string; // "==" | "===" | ">" | ">=" | "<" | "<=" | "!=" | "!=="; + + export type OperatorComparable = boolean | null | number | string | undefined | Date; + + interface ShouldAssertion { + equal(value1: any, value2: any, message?: string): void; + Throw: ShouldThrow; + throw: ShouldThrow; + exist(value: any, message?: string): void; + } + + interface Should extends ShouldAssertion { + not: ShouldAssertion; + fail(actual: any, expected: any, message?: string, operator?: Operator): void; + } + + interface ShouldThrow { + (actual: Function): void; + (actual: Function, expected: string | RegExp, message?: string): void; + (actual: Function, constructor: Error | Function, expected?: string | RegExp, message?: string): void; + } + + interface Assertion extends LanguageChains, NumericComparison, TypeComparison { + not: Assertion; + deep: Deep; + nested: Nested; + any: KeyFilter; + all: KeyFilter; + a: TypeComparison; + an: TypeComparison; + include: Include; + includes: Include; + contain: Include; + contains: Include; + ok: Assertion; + true: () => Assertion; + false: () => Assertion; + null: () => Assertion; + undefined: () => Assertion; + NaN: Assertion; + exist: Assertion; + empty: Assertion; + arguments: Assertion; + Arguments: Assertion; + equal: Equal; + equals: Equal; + eq: Equal; + eql: Equal; + eqls: Equal; + property: Property; + ownProperty: OwnProperty; + haveOwnProperty: OwnProperty; + ownPropertyDescriptor: OwnPropertyDescriptor; + haveOwnPropertyDescriptor: OwnPropertyDescriptor; + length: Length; + lengthOf: Length; + match: Match; + matches: Match; + string(string: string, message?: string): Assertion; + keys: Keys; + key(string: string): Assertion; + throw: (message?: string) => Assertion; + throws: Throw; + Throw: Throw; + respondTo: RespondTo; + respondsTo: RespondTo; + itself: Assertion; + satisfy: Satisfy; + satisfies: Satisfy; + closeTo: CloseTo; + approximately: CloseTo; + members: Members; + increase: PropertyChange; + increases: PropertyChange; + decrease: PropertyChange; + decreases: PropertyChange; + change: PropertyChange; + changes: PropertyChange; + extensible: Assertion; + sealed: Assertion; + frozen: Assertion; + oneOf(list: any[], message?: string): Assertion; + } + + interface LanguageChains { + to: Assertion; + be: Assertion; + been: Assertion; + is: Assertion; + that: Assertion; + which: Assertion; + and: Assertion; + has: Assertion; + have: Assertion; + with: Assertion; + at: Assertion; + of: Assertion; + same: Assertion; + } + + interface NumericComparison { + above: NumberComparer; + gt: NumberComparer; + greaterThan: NumberComparer; + least: NumberComparer; + gte: NumberComparer; + below: NumberComparer; + lt: NumberComparer; + lessThan: NumberComparer; + most: NumberComparer; + lte: NumberComparer; + within(start: number, finish: number, message?: string): Assertion; + } + + interface NumberComparer { + (value: number, message?: string): Assertion; + } + + interface TypeComparison { + (type: string, message?: string): Assertion; + instanceof: InstanceOf; + instanceOf: InstanceOf; + } + + interface InstanceOf { + (constructor: Object, message?: string): Assertion; + } + + interface CloseTo { + (expected: number, delta: number, message?: string): Assertion; + } + + interface Nested { + include: Include; + property: Property; + members: Members; + } + + interface Deep { + equal: Equal; + equals: Equal; + eq: Equal; + include: Include; + property: Property; + members: Members; + } + + interface KeyFilter { + keys: Keys; + } + + interface Equal { + (value: any, message?: string): Assertion; + } + + interface Property { + (name: string, value?: any, message?: string): Assertion; + } + + interface OwnProperty { + (name: string, message?: string): Assertion; + } + + interface OwnPropertyDescriptor { + (name: string, descriptor: PropertyDescriptor, message?: string): Assertion; + (name: string, message?: string): Assertion; + } + + interface Length extends LanguageChains, NumericComparison { + (length: number, message?: string): Assertion; + } + + interface Include { + (value: Object | string | number, message?: string): Assertion; + keys: Keys; + members: Members; + any: KeyFilter; + all: KeyFilter; + } + + interface Match { + (regexp: RegExp | string, message?: string): Assertion; + } + + interface Keys { + (...keys: string[]): Assertion; + (keys: any[]): Assertion; + (keys: Object): Assertion; + } + + interface Throw { + (): Assertion; + (expected: string, message?: string): Assertion; + (expected: RegExp, message?: string): Assertion; + (constructor: Error, expected?: string, message?: string): Assertion; + (constructor: Error, expected?: RegExp, message?: string): Assertion; + (constructor: Function, expected?: string, message?: string): Assertion; + (constructor: Function, expected?: RegExp, message?: string): Assertion; + } + + interface RespondTo { + (method: string, message?: string): Assertion; + } + + interface Satisfy { + (matcher: Function, message?: string): Assertion; + } + + interface Members { + (set: any[], message?: string): Assertion; + } + + interface PropertyChange { + (object: Object, property: string, message?: string): Assertion; + } + + export interface Assert { + /** + * @param expression Expression to test for truthiness. + * @param message Message to display on error. + */ + (expression: any, message?: string): void; + + /** + * Throws a failure. + * + * @type T Type of the objects. + * @param actual Actual value. + * @param expected Potential expected value. + * @param message Message to display on error. + * @param operator Comparison operator, if not strict equality. + * @remarks Node.js assert module-compatible. + */ + fail<T>(actual?: T, expected?: T, message?: string, operator?: Operator): void; + + /** + * Asserts that object is truthy. + * + * @type T Type of object. + * @param object Object to test. + * @param message Message to display on error. + */ + isOk<T>(value: T, message?: string): void; + + /** + * Asserts that object is truthy. + * + * @type T Type of object. + * @param object Object to test. + * @param message Message to display on error. + */ + ok<T>(value: T, message?: string): void; + + /** + * Asserts that object is falsy. + * + * @type T Type of object. + * @param object Object to test. + * @param message Message to display on error. + */ + isNotOk<T>(value: T, message?: string): void; + + /** + * Asserts that object is falsy. + * + * @type T Type of object. + * @param object Object to test. + * @param message Message to display on error. + */ + notOk<T>(value: T, message?: string): void; + + /** + * Asserts non-strict equality (==) of actual and expected. + * + * @type T Type of the objects. + * @param actual Actual value. + * @param expected Potential expected value. + * @param message Message to display on error. + */ + equal<T>(actual: T, expected: T, message?: string): void; + + /** + * Asserts non-strict inequality (==) of actual and expected. + * + * @type T Type of the objects. + * @param actual Actual value. + * @param expected Potential expected value. + * @param message Message to display on error. + */ + notEqual<T>(actual: T, expected: T, message?: string): void; + + /** + * Asserts strict equality (===) of actual and expected. + * + * @type T Type of the objects. + * @param actual Actual value. + * @param expected Potential expected value. + * @param message Message to display on error. + */ + strictEqual<T>(actual: T, expected: T, message?: string): void; + + /** + * Asserts strict inequality (==) of actual and expected. + * + * @type T Type of the objects. + * @param actual Actual value. + * @param expected Potential expected value. + * @param message Message to display on error. + */ + notStrictEqual<T>(actual: T, expected: T, message?: string): void; + + /** + * Asserts that actual is deeply equal to expected. + * + * @type T Type of the objects. + * @param actual Actual value. + * @param expected Potential expected value. + * @param message Message to display on error. + */ + deepEqual<T>(actual: T, expected: T, message?: string): void; + + /** + * Asserts that actual is not deeply equal to expected. + * + * @type T Type of the objects. + * @param actual Actual value. + * @param expected Potential expected value. + * @param message Message to display on error. + */ + notDeepEqual<T>(actual: T, expected: T, message?: string): void; + + /** + * Asserts valueToCheck is strictly greater than (>) valueToBeAbove. + * + * @param valueToCheck Actual value. + * @param valueToBeAbove Minimum Potential expected value. + * @param message Message to display on error. + */ + isAbove(valueToCheck: number, valueToBeAbove: number, message?: string): void; + + /** + * Asserts valueToCheck is greater than or equal to (>=) valueToBeAtLeast. + * + * @param valueToCheck Actual value. + * @param valueToBeAtLeast Minimum Potential expected value. + * @param message Message to display on error. + */ + isAtLeast(valueToCheck: number, valueToBeAtLeast: number, message?: string): void; + + /** + * Asserts valueToCheck is strictly less than (<) valueToBeBelow. + * + * @param valueToCheck Actual value. + * @param valueToBeBelow Minimum Potential expected value. + * @param message Message to display on error. + */ + isBelow(valueToCheck: number, valueToBeBelow: number, message?: string): void; + + /** + * Asserts valueToCheck is greater than or equal to (>=) valueToBeAtMost. + * + * @param valueToCheck Actual value. + * @param valueToBeAtMost Minimum Potential expected value. + * @param message Message to display on error. + */ + isAtMost(valueToCheck: number, valueToBeAtMost: number, message?: string): void; + + /** + * Asserts that value is true. + * + * @type T Type of value. + * @param value Actual value. + * @param message Message to display on error. + */ + isTrue<T>(value: T, message?: string): void; + + /** + * Asserts that value is false. + * + * @type T Type of value. + * @param value Actual value. + * @param message Message to display on error. + */ + isFalse<T>(value: T, message?: string): void; + + /** + * Asserts that value is not true. + * + * @type T Type of value. + * @param value Actual value. + * @param message Message to display on error. + */ + isNotTrue<T>(value: T, message?: string): void; + + /** + * Asserts that value is not false. + * + * @type T Type of value. + * @param value Actual value. + * @param message Message to display on error. + */ + isNotFalse<T>(value: T, message?: string): void; + + /** + * Asserts that value is null. + * + * @type T Type of value. + * @param value Actual value. + * @param message Message to display on error. + */ + isNull<T>(value: T, message?: string): void; + + /** + * Asserts that value is not null. + * + * @type T Type of value. + * @param value Actual value. + * @param message Message to display on error. + */ + isNotNull<T>(value: T, message?: string): void; + + /** + * Asserts that value is not null. + * + * @type T Type of value. + * @param value Actual value. + * @param message Message to display on error. + */ + isNaN<T>(value: T, message?: string): void; + + /** + * Asserts that value is not null. + * + * @type T Type of value. + * @param value Actual value. + * @param message Message to display on error. + */ + isNotNaN<T>(value: T, message?: string): void; + + /** + * Asserts that value is undefined. + * + * @type T Type of value. + * @param value Actual value. + * @param message Message to display on error. + */ + isUndefined<T>(value: T, message?: string): void; + + /** + * Asserts that value is not undefined. + * + * @type T Type of value. + * @param value Actual value. + * @param message Message to display on error. + */ + isDefined<T>(value: T, message?: string): void; + + /** + * Asserts that value is a function. + * + * @type T Type of value. + * @param value Actual value. + * @param message Message to display on error. + */ + isFunction<T>(value: T, message?: string): void; + + /** + * Asserts that value is not a function. + * + * @type T Type of value. + * @param value Actual value. + * @param message Message to display on error. + */ + isNotFunction<T>(value: T, message?: string): void; + + /** + * Asserts that value is an object of type 'Object' + * (as revealed by Object.prototype.toString). + * + * @type T Type of value. + * @param value Actual value. + * @param message Message to display on error. + * @remarks The assertion does not match subclassed objects. + */ + isObject<T>(value: T, message?: string): void; + + /** + * Asserts that value is not an object of type 'Object' + * (as revealed by Object.prototype.toString). + * + * @type T Type of value. + * @param value Actual value. + * @param message Message to display on error. + */ + isNotObject<T>(value: T, message?: string): void; + + /** + * Asserts that value is an array. + * + * @type T Type of value. + * @param value Actual value. + * @param message Message to display on error. + */ + isArray<T>(value: T, message?: string): void; + + /** + * Asserts that value is not an array. + * + * @type T Type of value. + * @param value Actual value. + * @param message Message to display on error. + */ + isNotArray<T>(value: T, message?: string): void; + + /** + * Asserts that value is a string. + * + * @type T Type of value. + * @param value Actual value. + * @param message Message to display on error. + */ + isString<T>(value: T, message?: string): void; + + /** + * Asserts that value is not a string. + * + * @type T Type of value. + * @param value Actual value. + * @param message Message to display on error. + */ + isNotString<T>(value: T, message?: string): void; + + /** + * Asserts that value is a number. + * + * @type T Type of value. + * @param value Actual value. + * @param message Message to display on error. + */ + isNumber<T>(value: T, message?: string): void; + + /** + * Asserts that value is not a number. + * + * @type T Type of value. + * @param value Actual value. + * @param message Message to display on error. + */ + isNotNumber<T>(value: T, message?: string): void; + + /** + * Asserts that value is a boolean. + * + * @type T Type of value. + * @param value Actual value. + * @param message Message to display on error. + */ + isBoolean<T>(value: T, message?: string): void; + + /** + * Asserts that value is not a boolean. + * + * @type T Type of value. + * @param value Actual value. + * @param message Message to display on error. + */ + isNotBoolean<T>(value: T, message?: string): void; + + /** + * Asserts that value's type is name, as determined by Object.prototype.toString. + * + * @type T Type of value. + * @param value Actual value. + * @param name Potential expected type name of value. + * @param message Message to display on error. + */ + typeOf<T>(value: T, name: string, message?: string): void; + + /** + * Asserts that value's type is not name, as determined by Object.prototype.toString. + * + * @type T Type of value. + * @param value Actual value. + * @param name Potential expected type name of value. + * @param message Message to display on error. + */ + notTypeOf<T>(value: T, name: string, message?: string): void; + + /** + * Asserts that value is an instance of constructor. + * + * @type T Type of value. + * @param value Actual value. + * @param constructor Potential expected contructor of value. + * @param message Message to display on error. + */ + instanceOf<T>(value: T, constructor: Function, message?: string): void; + + /** + * Asserts that value is not an instance of constructor. + * + * @type T Type of value. + * @param value Actual value. + * @param constructor Potential expected contructor of value. + * @param message Message to display on error. + */ + notInstanceOf<T>(value: T, type: Function, message?: string): void; + + /** + * Asserts that haystack includes needle. + * + * @param haystack Container string. + * @param needle Potential expected substring of haystack. + * @param message Message to display on error. + */ + include(haystack: string, needle: string, message?: string): void; + + /** + * Asserts that haystack includes needle. + * + * @type T Type of values in haystack. + * @param haystack Container array. + * @param needle Potential value contained in haystack. + * @param message Message to display on error. + */ + include<T>(haystack: T[], needle: T, message?: string): void; + + /** + * Asserts that haystack does not include needle. + * + * @param haystack Container string. + * @param needle Potential expected substring of haystack. + * @param message Message to display on error. + */ + notInclude(haystack: string, needle: any, message?: string): void; + + /** + * Asserts that haystack does not include needle. + * + * @type T Type of values in haystack. + * @param haystack Container array. + * @param needle Potential value contained in haystack. + * @param message Message to display on error. + */ + notInclude(haystack: any[], needle: any, message?: string): void; + + /** + * Asserts that value matches the regular expression regexp. + * + * @param value Actual value. + * @param regexp Potential match of value. + * @param message Message to display on error. + */ + match(value: string, regexp: RegExp, message?: string): void; + + /** + * Asserts that value does not match the regular expression regexp. + * + * @param value Actual value. + * @param regexp Potential match of value. + * @param message Message to display on error. + */ + notMatch(expected: any, regexp: RegExp, message?: string): void; + + /** + * Asserts that object has a property named by property. + * + * @type T Type of object. + * @param object Container object. + * @param property Potential contained property of object. + * @param message Message to display on error. + */ + property<T>(object: T, property: string /* keyof T */, message?: string): void; + + /** + * Asserts that object has a property named by property. + * + * @type T Type of object. + * @param object Container object. + * @param property Potential contained property of object. + * @param message Message to display on error. + */ + notProperty<T>(object: T, property: string /* keyof T */, message?: string): void; + + /** + * Asserts that object has a property named by property, which can be a string + * using dot- and bracket-notation for deep reference. + * + * @type T Type of object. + * @param object Container object. + * @param property Potential contained property of object. + * @param message Message to display on error. + */ + deepProperty<T>(object: T, property: string, message?: string): void; + + /** + * Asserts that object does not have a property named by property, which can be a + * string using dot- and bracket-notation for deep reference. + * + * @type T Type of object. + * @param object Container object. + * @param property Potential contained property of object. + * @param message Message to display on error. + */ + notDeepProperty<T>(object: T, property: string, message?: string): void; + + /** + * Asserts that object has a property named by property with value given by value. + * + * @type T Type of object. + * @type V Type of value. + * @param object Container object. + * @param property Potential contained property of object. + * @param value Potential expected property value. + * @param message Message to display on error. + */ + propertyVal<T, V>(object: T, property: string /* keyof T */, value: V, message?: string): void; + + /** + * Asserts that object has a property named by property with value given by value. + * + * @type T Type of object. + * @type V Type of value. + * @param object Container object. + * @param property Potential contained property of object. + * @param value Potential expected property value. + * @param message Message to display on error. + */ + propertyNotVal<T, V>(object: T, property: string /* keyof T */, value: V, message?: string): void; + + /** + * Asserts that object has a property named by property, which can be a string + * using dot- and bracket-notation for deep reference. + * + * @type T Type of object. + * @type V Type of value. + * @param object Container object. + * @param property Potential contained property of object. + * @param value Potential expected property value. + * @param message Message to display on error. + */ + deepPropertyVal<T, V>(object: T, property: string, value: V, message?: string): void; + + /** + * Asserts that object does not have a property named by property, which can be a + * string using dot- and bracket-notation for deep reference. + * + * @type T Type of object. + * @type V Type of value. + * @param object Container object. + * @param property Potential contained property of object. + * @param value Potential expected property value. + * @param message Message to display on error. + */ + deepPropertyNotVal<T, V>(object: T, property: string, value: V, message?: string): void; + + /** + * Asserts that object has a length property with the expected value. + * + * @type T Type of object. + * @param object Container object. + * @param length Potential expected length of object. + * @param message Message to display on error. + */ + lengthOf<T extends { readonly length?: number }>(object: T, length: number, message?: string): void; + + /** + * Asserts that fn will throw an error. + * + * @param fn Function that may throw. + * @param message Message to display on error. + */ + throw(fn: Function, message?: string): void; + + /** + * Asserts that function will throw an error with message matching regexp. + * + * @param fn Function that may throw. + * @param regExp Potential expected message match. + * @param message Message to display on error. + */ + throw(fn: Function, regExp: RegExp): void; + + /** + * Asserts that function will throw an error that is an instance of constructor. + * + * @param fn Function that may throw. + * @param constructor Potential expected error constructor. + * @param message Message to display on error. + */ + throw(fn: Function, constructor: Function, message?: string): void; + + /** + * Asserts that function will throw an error that is an instance of constructor + * and an error with message matching regexp. + * + * @param fn Function that may throw. + * @param constructor Potential expected error constructor. + * @param message Message to display on error. + */ + throw(fn: Function, constructor: Function, regExp: RegExp): void; + + /** + * Asserts that fn will throw an error. + * + * @param fn Function that may throw. + * @param message Message to display on error. + */ + throws(fn: Function, message?: string): void; + + /** + * Asserts that function will throw an error with message matching regexp. + * + * @param fn Function that may throw. + * @param regExp Potential expected message match. + * @param message Message to display on error. + */ + throws(fn: Function, regExp: RegExp, message?: string): void; + + /** + * Asserts that function will throw an error that is an instance of constructor. + * + * @param fn Function that may throw. + * @param constructor Potential expected error constructor. + * @param message Message to display on error. + */ + throws(fn: Function, errType: Function, message?: string): void; + + /** + * Asserts that function will throw an error that is an instance of constructor + * and an error with message matching regexp. + * + * @param fn Function that may throw. + * @param constructor Potential expected error constructor. + * @param message Message to display on error. + */ + throws(fn: Function, errType: Function, regExp: RegExp): void; + + /** + * Asserts that fn will throw an error. + * + * @param fn Function that may throw. + * @param message Message to display on error. + */ + Throw(fn: Function, message?: string): void; + + /** + * Asserts that function will throw an error with message matching regexp. + * + * @param fn Function that may throw. + * @param regExp Potential expected message match. + * @param message Message to display on error. + */ + Throw(fn: Function, regExp: RegExp): void; + + /** + * Asserts that function will throw an error that is an instance of constructor. + * + * @param fn Function that may throw. + * @param constructor Potential expected error constructor. + * @param message Message to display on error. + */ + Throw(fn: Function, errType: Function, message?: string): void; + + /** + * Asserts that function will throw an error that is an instance of constructor + * and an error with message matching regexp. + * + * @param fn Function that may throw. + * @param constructor Potential expected error constructor. + * @param message Message to display on error. + */ + Throw(fn: Function, errType: Function, regExp: RegExp): void; + + /** + * Asserts that fn will not throw an error. + * + * @param fn Function that may throw. + * @param message Message to display on error. + */ + doesNotThrow(fn: Function, message?: string): void; + + /** + * Asserts that function will throw an error with message matching regexp. + * + * @param fn Function that may throw. + * @param regExp Potential expected message match. + * @param message Message to display on error. + */ + doesNotThrow(fn: Function, regExp: RegExp): void; + + /** + * Asserts that function will throw an error that is an instance of constructor. + * + * @param fn Function that may throw. + * @param constructor Potential expected error constructor. + * @param message Message to display on error. + */ + doesNotThrow(fn: Function, errType: Function, message?: string): void; + + /** + * Asserts that function will throw an error that is an instance of constructor + * and an error with message matching regexp. + * + * @param fn Function that may throw. + * @param constructor Potential expected error constructor. + * @param message Message to display on error. + */ + doesNotThrow(fn: Function, errType: Function, regExp: RegExp): void; + + /** + * Compares two values using operator. + * + * @param val1 Left value during comparison. + * @param operator Comparison operator. + * @param val2 Right value during comparison. + * @param message Message to display on error. + */ + operator(val1: OperatorComparable, operator: Operator, val2: OperatorComparable, message?: string): void; + + /** + * Asserts that the target is equal to expected, to within a +/- delta range. + * + * @param actual Actual value + * @param expected Potential expected value. + * @param delta Maximum differenced between values. + * @param message Message to display on error. + */ + closeTo(actual: number, expected: number, delta: number, message?: string): void; + + /** + * Asserts that the target is equal to expected, to within a +/- delta range. + * + * @param actual Actual value + * @param expected Potential expected value. + * @param delta Maximum differenced between values. + * @param message Message to display on error. + */ + approximately(act: number, exp: number, delta: number, message?: string): void; + + /** + * Asserts that set1 and set2 have the same members. Order is not take into account. + * + * @type T Type of set values. + * @param set1 Actual set of values. + * @param set2 Potential expected set of values. + * @param message Message to display on error. + */ + sameMembers<T>(set1: T[], set2: T[], message?: string): void; + + /** + * Asserts that set1 and set2 have the same members using deep equality checking. + * Order is not take into account. + * + * @type T Type of set values. + * @param set1 Actual set of values. + * @param set2 Potential expected set of values. + * @param message Message to display on error. + */ + sameDeepMembers<T>(set1: T[], set2: T[], message?: string): void; + + /** + * Asserts that subset is included in superset. Order is not take into account. + * + * @type T Type of set values. + * @param superset Actual set of values. + * @param subset Potential contained set of values. + * @param message Message to display on error. + */ + includeMembers<T>(superset: T[], subset: T[], message?: string): void; + + /** + * Asserts that subset is included in superset using deep equality checking. + * Order is not take into account. + * + * @type T Type of set values. + * @param superset Actual set of values. + * @param subset Potential contained set of values. + * @param message Message to display on error. + */ + includeDeepMembers<T>(superset: T[], subset: T[], message?: string): void; + + /** + * Asserts that non-object, non-array value inList appears in the flat array list. + * + * @type T Type of list values. + * @param inList Value expected to be in the list. + * @param list List of values. + * @param message Message to display on error. + */ + oneOf<T>(inList: T, list: T[], message?: string): void; + + /** + * Asserts that a function changes the value of a property. + * + * @type T Type of object. + * @param modifier Function to run. + * @param object Container object. + * @param property Property of object expected to be modified. + * @param message Message to display on error. + */ + changes<T>(modifier: Function, object: T, property: string /* keyof T */, message?: string): void; + + /** + * Asserts that a function does not change the value of a property. + * + * @type T Type of object. + * @param modifier Function to run. + * @param object Container object. + * @param property Property of object expected not to be modified. + * @param message Message to display on error. + */ + doesNotChange<T>(modifier: Function, object: T, property: string /* keyof T */, message?: string): void; + + /** + * Asserts that a function increases an object property. + * + * @type T Type of object. + * @param modifier Function to run. + * @param object Container object. + * @param property Property of object expected to be increased. + * @param message Message to display on error. + */ + increases<T>(modifier: Function, object: T, property: string /* keyof T */, message?: string): void; + + /** + * Asserts that a function does not increase an object property. + * + * @type T Type of object. + * @param modifier Function to run. + * @param object Container object. + * @param property Property of object expected not to be increased. + * @param message Message to display on error. + */ + doesNotIncrease<T>(modifier: Function, object: T, property: string /* keyof T */, message?: string): void; + + /** + * Asserts that a function decreases an object property. + * + * @type T Type of object. + * @param modifier Function to run. + * @param object Container object. + * @param property Property of object expected to be decreased. + * @param message Message to display on error. + */ + decreases<T>(modifier: Function, object: T, property: string /* keyof T */, message?: string): void; + + /** + * Asserts that a function does not decrease an object property. + * + * @type T Type of object. + * @param modifier Function to run. + * @param object Container object. + * @param property Property of object expected not to be decreased. + * @param message Message to display on error. + */ + doesNotDecrease<T>(modifier: Function, object: T, property: string /* keyof T */, message?: string): void; + + /** + * Asserts if value is not a false value, and throws if it is a true value. + * + * @type T Type of object. + * @param object Actual value. + * @param message Message to display on error. + * @remarks This is added to allow for chai to be a drop-in replacement for + * Node’s assert class. + */ + ifError<T>(object: T, message?: string): void; + + /** + * Asserts that object is extensible (can have new properties added to it). + * + * @type T Type of object + * @param object Actual value. + * @param message Message to display on error. + */ + isExtensible<T>(object: T, message?: string): void; + + /** + * Asserts that object is extensible (can have new properties added to it). + * + * @type T Type of object + * @param object Actual value. + * @param message Message to display on error. + */ + extensible<T>(object: T, message?: string): void; + + /** + * Asserts that object is not extensible. + * + * @type T Type of object + * @param object Actual value. + * @param message Message to display on error. + */ + isNotExtensible<T>(object: T, message?: string): void; + + /** + * Asserts that object is not extensible. + * + * @type T Type of object + * @param object Actual value. + * @param message Message to display on error. + */ + notExtensible<T>(object: T, message?: string): void; + + /** + * Asserts that object is sealed (can have new properties added to it + * and its existing properties cannot be removed). + * + * @type T Type of object + * @param object Actual value. + * @param message Message to display on error. + */ + isSealed<T>(object: T, message?: string): void; + + /** + * Asserts that object is sealed (can have new properties added to it + * and its existing properties cannot be removed). + * + * @type T Type of object + * @param object Actual value. + * @param message Message to display on error. + */ + sealed<T>(object: T, message?: string): void; + + /** + * Asserts that object is not sealed. + * + * @type T Type of object + * @param object Actual value. + * @param message Message to display on error. + */ + isNotSealed<T>(object: T, message?: string): void; + + /** + * Asserts that object is not sealed. + * + * @type T Type of object + * @param object Actual value. + * @param message Message to display on error. + */ + notSealed<T>(object: T, message?: string): void; + + /** + * Asserts that object is frozen (cannot have new properties added to it + * and its existing properties cannot be removed). + * + * @type T Type of object + * @param object Actual value. + * @param message Message to display on error. + */ + isFrozen<T>(object: T, message?: string): void; + + /** + * Asserts that object is frozen (cannot have new properties added to it + * and its existing properties cannot be removed). + * + * @type T Type of object + * @param object Actual value. + * @param message Message to display on error. + */ + frozen<T>(object: T, message?: string): void; + + /** + * Asserts that object is not frozen (cannot have new properties added to it + * and its existing properties cannot be removed). + * + * @type T Type of object + * @param object Actual value. + * @param message Message to display on error. + */ + isNotFrozen<T>(object: T, message?: string): void; + + /** + * Asserts that object is not frozen (cannot have new properties added to it + * and its existing properties cannot be removed). + * + * @type T Type of object + * @param object Actual value. + * @param message Message to display on error. + */ + notFrozen<T>(object: T, message?: string): void; + } + + export interface Config { + /** + * Default: false + */ + includeStack: boolean; + + /** + * Default: true + */ + showDiff: boolean; + + /** + * Default: 40 + */ + truncateThreshold: number; + } + + export class AssertionError { + constructor(message: string, _props?: any, ssf?: Function); + public name: string; + public message: string; + public showDiff: boolean; + public stack: string; + } +} + +declare const chai: Chai.ChaiStatic; + +declare module 'chai' { + export = chai; +} + +interface Object { + should: Chai.Assertion; +} diff --git a/packages/chai-typescript-typings/package.json b/packages/chai-typescript-typings/package.json new file mode 100644 index 000000000..db7cba863 --- /dev/null +++ b/packages/chai-typescript-typings/package.json @@ -0,0 +1,16 @@ +{ + "name": "chai-typescript-typings", + "version": "0.0.2", + "description": "Typescript type definitions for chai", + "main": "index.d.ts", + "types": "index.d.ts", + "repository": { + "type": "git", + "url": "git+https://github.com/0xProject/0x.js.git" + }, + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/0xProject/0x.js/issues" + }, + "homepage": "https://github.com/0xProject/0x.js/packages/chai-typescript-typings#readme" +} diff --git a/packages/chai-typescript-typings/scripts/postpublish.js b/packages/chai-typescript-typings/scripts/postpublish.js new file mode 100644 index 000000000..16d67e03f --- /dev/null +++ b/packages/chai-typescript-typings/scripts/postpublish.js @@ -0,0 +1,15 @@ +const postpublish_utils = require('../../../scripts/postpublish_utils'); +const packageJSON = require('../package.json'); + +const subPackageName = packageJSON.name; + +postpublish_utils + .getLatestTagAndVersionAsync(subPackageName) + .then(function(result) { + const releaseName = postpublish_utils.getReleaseName(subPackageName, result.version); + const assets = []; + return postpublish_utils.publishReleaseNotes(result.tag, releaseName, assets); + }) + .catch(function(err) { + throw err; + }); diff --git a/packages/chai-typescript-typings/tslint.json b/packages/chai-typescript-typings/tslint.json new file mode 100644 index 000000000..9a93a1f74 --- /dev/null +++ b/packages/chai-typescript-typings/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": ["tslint-config-0xproject"] +} diff --git a/packages/connect/CHANGELOG.md b/packages/connect/CHANGELOG.md index cf507dbe6..e02020204 100644 --- a/packages/connect/CHANGELOG.md +++ b/packages/connect/CHANGELOG.md @@ -1,16 +1,26 @@ # CHANGELOG -vx.x.x ------------------------- +## v0.5.0 - _January 17, 2018_ + + * Sanitize api endpoint url and remove trailing slashes (#318) + * Improve error message text in HttpClient (#318) + * Stop appending '/v0' to api endpoint url in HttpClient (#318) + +## v0.4.0 - _January 11, 2018_ + + * Prevent getFeesAsync method on HttpClient from mutating input (#296) + +## v0.3.0 - _December 8, 2017_ + * Expose WebSocketOrderbookChannel and associated types to public interface (#251) * Remove tokenA and tokenB fields from OrdersRequest (#256) -v0.2.0 - _November 29, 2017_ ------------------------- +## v0.2.0 - _November 29, 2017_ + * Add SignedOrder and TokenTradeInfo to the public interface * Add ECSignature and Order to the public interface * Remove dependency on 0x.js -v0.1.0 - _November 22, 2017_ ------------------------- +## v0.1.0 - _November 22, 2017_ + * Provide a HttpClient class for interacting with standard relayer api compliant HTTP urls diff --git a/packages/connect/README.md b/packages/connect/README.md index 900045526..63faf5271 100644 --- a/packages/connect/README.md +++ b/packages/connect/README.md @@ -1 +1,52 @@ +## @0xproject/connect + This repository contains a Javascript library that makes it easy to interact with Relayers that conform to the [Standard Relayer API](https://github.com/0xProject/standard-relayer-api) + +## Installation + +```bash +yarn add @0xproject/connect +``` + +## Usage + +* [Docs](https://0xproject.com/docs/connect) +* [Tutorials](https://0xproject.com/wiki#connect) + +## Contributing + +We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. + +Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. + +### Install Dependencies + +If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: + +```bash +yarn config set workspaces-experimental true +``` + +Then install dependencies + +```bash +yarn install +``` + +### Build + +```bash +yarn build +``` + +### Lint + +```bash +yarn lint +``` + +### Run Tests + +```bash +yarn test +``` diff --git a/packages/connect/package.json b/packages/connect/package.json index 2392d9907..a28916903 100644 --- a/packages/connect/package.json +++ b/packages/connect/package.json @@ -1,69 +1,69 @@ { - "name": "@0xproject/connect", - "version": "0.2.0", - "description": "A javascript library for interacting with the standard relayer api", - "keywords": [ - "connect", - "0xproject", - "ethereum", - "tokens", - "exchange" - ], - "main": "lib/src/index.js", - "types": "lib/src/index.d.ts", - "scripts": { - "build": "tsc", - "clean": "shx rm -rf _bundles lib test_temp", - "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", - "copy_test_fixtures": "copyfiles -u 2 './test/fixtures/**/*.json' ./lib/test/fixtures", - "lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'", - "run_mocha": "mocha lib/test/**/*_test.js", - "test": "run-s clean build copy_test_fixtures run_mocha", - "test:circleci": "yarn test" - }, - "repository": { - "type": "git", - "url": "https://github.com/0xProject/0x.js.git" - }, - "author": "Brandon Millman", - "license": "Apache-2.0", - "engines": { - "node": ">=6.0.0" - }, - "bugs": { - "url": "https://github.com/0xProject/0x.js/issues" - }, - "homepage": "https://github.com/0xProject/0x.js/packages/connect/README.md", - "dependencies": { - "@0xproject/assert": "^0.0.6", - "@0xproject/json-schemas": "^0.6.9", - "bignumber.js": "~4.1.0", - "isomorphic-fetch": "^2.2.1", - "lodash": "^4.17.4", - "query-string": "^5.0.1", - "websocket": "^1.0.25" - }, - "devDependencies": { - "@0xproject/tslint-config": "^0.2.0", - "@types/fetch-mock": "^5.12.1", - "@types/lodash": "^4.14.86", - "@types/mocha": "^2.2.42", - "@types/query-string": "^5.0.1", - "@types/websocket": "^0.0.34", - "chai": "^4.0.1", - "chai-as-promised": "^7.1.0", - "chai-as-promised-typescript-typings": "^0.0.3", - "chai-typescript-typings": "^0.0.1", - "copyfiles": "^1.2.0", - "dirty-chai": "^2.0.1", - "fetch-mock": "^5.13.1", - "mocha": "^4.0.1", - "npm-run-all": "^4.1.2", - "shx": "^0.2.2", - "tslint": "5.8.0", - "typedoc": "~0.8.0", - "typescript": "~2.6.1", - "web3-typescript-typings": "^0.7.2" - } + "name": "@0xproject/connect", + "version": "0.5.1", + "description": "A javascript library for interacting with the standard relayer api", + "keywords": [ + "connect", + "0xproject", + "ethereum", + "tokens", + "exchange" + ], + "main": "lib/src/index.js", + "types": "lib/src/index.d.ts", + "scripts": { + "build": "tsc", + "clean": "shx rm -rf _bundles lib test_temp", + "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", + "copy_test_fixtures": "copyfiles -u 2 './test/fixtures/**/*.json' ./lib/test/fixtures", + "lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'", + "run_mocha": "mocha lib/test/**/*_test.js", + "test": "run-s clean build copy_test_fixtures run_mocha", + "test:circleci": "yarn test" + }, + "repository": { + "type": "git", + "url": "https://github.com/0xProject/0x.js.git" + }, + "author": "Brandon Millman", + "license": "Apache-2.0", + "engines": { + "node": ">=6.0.0" + }, + "bugs": { + "url": "https://github.com/0xProject/0x.js/issues" + }, + "homepage": "https://github.com/0xProject/0x.js/packages/connect/README.md", + "dependencies": { + "@0xproject/assert": "^0.0.12", + "@0xproject/json-schemas": "^0.7.4", + "@0xproject/utils": "^0.2.1", + "isomorphic-fetch": "^2.2.1", + "lodash": "^4.17.4", + "query-string": "^5.0.1", + "websocket": "^1.0.25" + }, + "devDependencies": { + "@0xproject/tslint-config": "^0.4.3", + "@types/fetch-mock": "^5.12.1", + "@types/lodash": "^4.14.86", + "@types/mocha": "^2.2.42", + "@types/query-string": "^5.0.1", + "@types/websocket": "^0.0.34", + "chai": "^4.0.1", + "chai-as-promised": "^7.1.0", + "chai-as-promised-typescript-typings": "^0.0.5", + "chai-typescript-typings": "^0.0.2", + "copyfiles": "^1.2.0", + "dirty-chai": "^2.0.1", + "fetch-mock": "^5.13.1", + "mocha": "^4.0.1", + "npm-run-all": "^4.1.2", + "shx": "^0.2.2", + "tslint": "5.8.0", + "typedoc": "~0.8.0", + "typescript": "~2.6.1", + "web3-typescript-typings": "^0.9.5" + } } diff --git a/packages/connect/scripts/postpublish.js b/packages/connect/scripts/postpublish.js index e6a2cc065..24384b228 100644 --- a/packages/connect/scripts/postpublish.js +++ b/packages/connect/scripts/postpublish.js @@ -8,22 +8,20 @@ const S3BucketPath = 's3://connect-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); - return postpublish_utils.publishReleaseNotes(tag, releaseName); + const releaseName = postpublish_utils.getReleaseName(subPackageName, version); + return postpublish_utils.publishReleaseNotes(tag, releaseName); }) .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 !== '') { @@ -35,6 +33,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/connect/src/http_client.ts b/packages/connect/src/http_client.ts index 252c9e9dd..3df77b0f0 100644 --- a/packages/connect/src/http_client.ts +++ b/packages/connect/src/http_client.ts @@ -1,11 +1,10 @@ -import {assert} from '@0xproject/assert'; -import {schemas} from '@0xproject/json-schemas'; -import {BigNumber} from 'bignumber.js'; +import { assert } from '@0xproject/assert'; +import { schemas } from '@0xproject/json-schemas'; import 'isomorphic-fetch'; import * as _ from 'lodash'; import * as queryString from 'query-string'; -import {schemas as clientSchemas} from './schemas/schemas'; +import { schemas as clientSchemas } from './schemas/schemas'; import { Client, FeesRequest, @@ -19,19 +18,15 @@ import { TokenPairsItem, TokenPairsRequest, } from './types'; -import {typeConverters} from './utils/type_converters'; - -// TODO: move this and bigNumberConfigs in the 0x.js package into one place -BigNumber.config({ - EXPONENTIAL_AT: 1000, -}); +import { relayerResponseJsonParsers } from './utils/relayer_response_json_parsers'; +const TRAILING_SLASHES_REGEX = /\/+$/; /** * This class includes all the functionality related to interacting with a set of HTTP endpoints * that implement the standard relayer API v0 */ export class HttpClient implements Client { - private apiEndpointUrl: string; + private _apiEndpointUrl: string; /** * Instantiates a new HttpClient instance * @param url The relayer API base HTTP url you would like to interact with @@ -39,7 +34,7 @@ export class HttpClient implements Client { */ constructor(url: string) { assert.isHttpUrl('url', url); - this.apiEndpointUrl = url; + this._apiEndpointUrl = url.replace(TRAILING_SLASHES_REGEX, ''); // remove trailing slashes } /** * Retrieve token pair info from the API @@ -54,17 +49,8 @@ export class HttpClient implements Client { const requestOpts = { params: request, }; - const tokenPairs = await this._requestAsync('/token_pairs', HttpRequestType.Get, requestOpts); - assert.doesConformToSchema( - 'tokenPairs', tokenPairs, schemas.relayerApiTokenPairsResponseSchema); - _.each(tokenPairs, (tokenPair: object) => { - typeConverters.convertStringsFieldsToBigNumbers(tokenPair, [ - 'tokenA.minAmount', - 'tokenA.maxAmount', - 'tokenB.minAmount', - 'tokenB.maxAmount', - ]); - }); + const responseJson = await this._requestAsync('/token_pairs', HttpRequestType.Get, requestOpts); + const tokenPairs = relayerResponseJsonParsers.parseTokenPairsJson(responseJson); return tokenPairs; } /** @@ -79,9 +65,8 @@ export class HttpClient implements Client { const requestOpts = { params: request, }; - const orders = await this._requestAsync(`/orders`, HttpRequestType.Get, requestOpts); - assert.doesConformToSchema('orders', orders, schemas.signedOrdersSchema); - _.each(orders, (order: object) => typeConverters.convertOrderStringFieldsToBigNumber(order)); + const responseJson = await this._requestAsync(`/orders`, HttpRequestType.Get, requestOpts); + const orders = relayerResponseJsonParsers.parseOrdersJson(responseJson); return orders; } /** @@ -91,9 +76,8 @@ export class HttpClient implements Client { */ public async getOrderAsync(orderHash: string): Promise<SignedOrder> { assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema); - const order = await this._requestAsync(`/order/${orderHash}`, HttpRequestType.Get); - assert.doesConformToSchema('order', order, schemas.signedOrderSchema); - typeConverters.convertOrderStringFieldsToBigNumber(order); + const responseJson = await this._requestAsync(`/order/${orderHash}`, HttpRequestType.Get); + const order = relayerResponseJsonParsers.parseOrderJson(responseJson); return order; } /** @@ -106,10 +90,9 @@ export class HttpClient implements Client { const requestOpts = { params: request, }; - const orderBook = await this._requestAsync('/orderbook', HttpRequestType.Get, requestOpts); - assert.doesConformToSchema('orderBook', orderBook, schemas.relayerApiOrderBookResponseSchema); - typeConverters.convertOrderbookStringFieldsToBigNumber(orderBook); - return orderBook; + const responseJson = await this._requestAsync('/orderbook', HttpRequestType.Get, requestOpts); + const orderbook = relayerResponseJsonParsers.parseOrderbookResponseJson(responseJson); + return orderbook; } /** * Retrieve fee information from the API @@ -118,18 +101,11 @@ export class HttpClient implements Client { */ public async getFeesAsync(request: FeesRequest): Promise<FeesResponse> { assert.doesConformToSchema('request', request, schemas.relayerApiFeesPayloadSchema); - typeConverters.convertBigNumberFieldsToStrings(request, [ - 'makerTokenAmount', - 'takerTokenAmount', - 'expirationUnixTimestampSec', - 'salt', - ]); const requestOpts = { payload: request, }; - const fees = await this._requestAsync('/fees', HttpRequestType.Post, requestOpts); - assert.doesConformToSchema('fees', fees, schemas.relayerApiFeesResponseSchema); - typeConverters.convertStringsFieldsToBigNumbers(fees, ['makerFee', 'takerFee']); + const responseJson = await this._requestAsync('/fees', HttpRequestType.Post, requestOpts); + const fees = relayerResponseJsonParsers.parseFeesResponseJson(responseJson); return fees; } /** @@ -143,8 +119,11 @@ export class HttpClient implements Client { }; await this._requestAsync('/order', HttpRequestType.Post, requestOpts); } - private async _requestAsync(path: string, requestType: HttpRequestType, - requestOptions?: HttpRequestOptions): Promise<any> { + private async _requestAsync( + path: string, + requestType: HttpRequestType, + requestOptions?: HttpRequestOptions, + ): Promise<any> { const params = _.get(requestOptions, 'params'); const payload = _.get(requestOptions, 'payload'); let query = ''; @@ -152,20 +131,22 @@ export class HttpClient implements Client { const stringifiedParams = queryString.stringify(params); query = `?${stringifiedParams}`; } - const url = `${this.apiEndpointUrl}/v0${path}${query}`; + const url = `${this._apiEndpointUrl}${path}${query}`; const headers = new Headers({ 'content-type': 'application/json', }); - const response = await fetch(url, { method: requestType, body: JSON.stringify(payload), headers, }); + const json = await response.json(); if (!response.ok) { - throw Error(response.statusText); + const errorString = `${response.status} - ${response.statusText}\n${requestType} ${url}\n${JSON.stringify( + json, + )}`; + throw Error(errorString); } - const json = await response.json(); return json; } } diff --git a/packages/connect/src/index.ts b/packages/connect/src/index.ts index ec369a606..a492f5ae9 100644 --- a/packages/connect/src/index.ts +++ b/packages/connect/src/index.ts @@ -1,5 +1,5 @@ -export {HttpClient} from './http_client'; -export {WebSocketOrderbookChannel} from './ws_orderbook_channel'; +export { HttpClient } from './http_client'; +export { WebSocketOrderbookChannel } from './ws_orderbook_channel'; export { Client, ECSignature, diff --git a/packages/connect/src/schemas/relayer_fees_request_schema.ts b/packages/connect/src/schemas/relayer_fees_request_schema.ts index 9408c94a0..f20e077ba 100644 --- a/packages/connect/src/schemas/relayer_fees_request_schema.ts +++ b/packages/connect/src/schemas/relayer_fees_request_schema.ts @@ -2,7 +2,7 @@ export const relayerOrderBookRequestSchema = { id: '/RelayerOrderBookRequest', type: 'object', properties: { - baseTokenAddress: {$ref: '/Address'}, - quoteTokenAddress: {$ref: '/Address'}, + baseTokenAddress: { $ref: '/Address' }, + quoteTokenAddress: { $ref: '/Address' }, }, }; diff --git a/packages/connect/src/schemas/relayer_orderbook_request_schema.ts b/packages/connect/src/schemas/relayer_orderbook_request_schema.ts index 9408c94a0..f20e077ba 100644 --- a/packages/connect/src/schemas/relayer_orderbook_request_schema.ts +++ b/packages/connect/src/schemas/relayer_orderbook_request_schema.ts @@ -2,7 +2,7 @@ export const relayerOrderBookRequestSchema = { id: '/RelayerOrderBookRequest', type: 'object', properties: { - baseTokenAddress: {$ref: '/Address'}, - quoteTokenAddress: {$ref: '/Address'}, + baseTokenAddress: { $ref: '/Address' }, + quoteTokenAddress: { $ref: '/Address' }, }, }; diff --git a/packages/connect/src/schemas/relayer_orders_request_schema.ts b/packages/connect/src/schemas/relayer_orders_request_schema.ts index c11bc77be..570238dae 100644 --- a/packages/connect/src/schemas/relayer_orders_request_schema.ts +++ b/packages/connect/src/schemas/relayer_orders_request_schema.ts @@ -2,15 +2,15 @@ export const relayerOrdersRequestSchema = { id: '/RelayerOrdersRequest', type: 'object', properties: { - exchangeContractAddress: {$ref: '/Address'}, - tokenAddress: {$ref: '/Address'}, - makerTokenAddress: {$ref: '/Address'}, - takerTokenAddress: {$ref: '/Address'}, - tokenA: {$ref: '/Address'}, - tokenB: {$ref: '/Address'}, - maker: {$ref: '/Address'}, - taker: {$ref: '/Address'}, - trader: {$ref: '/Address'}, - feeRecipient: {$ref: '/Address'}, + exchangeContractAddress: { $ref: '/Address' }, + tokenAddress: { $ref: '/Address' }, + makerTokenAddress: { $ref: '/Address' }, + takerTokenAddress: { $ref: '/Address' }, + tokenA: { $ref: '/Address' }, + tokenB: { $ref: '/Address' }, + maker: { $ref: '/Address' }, + taker: { $ref: '/Address' }, + trader: { $ref: '/Address' }, + feeRecipient: { $ref: '/Address' }, }, }; diff --git a/packages/connect/src/schemas/relayer_token_pairs_request_schema.ts b/packages/connect/src/schemas/relayer_token_pairs_request_schema.ts index 8013e1454..379232204 100644 --- a/packages/connect/src/schemas/relayer_token_pairs_request_schema.ts +++ b/packages/connect/src/schemas/relayer_token_pairs_request_schema.ts @@ -2,7 +2,7 @@ export const relayerTokenPairsRequestSchema = { id: '/RelayerTokenPairsRequest', type: 'object', properties: { - tokenA: {$ref: '/Address'}, - tokenB: {$ref: '/Address'}, + tokenA: { $ref: '/Address' }, + tokenB: { $ref: '/Address' }, }, }; diff --git a/packages/connect/src/schemas/schemas.ts b/packages/connect/src/schemas/schemas.ts index 97ac672bf..288d6969d 100644 --- a/packages/connect/src/schemas/schemas.ts +++ b/packages/connect/src/schemas/schemas.ts @@ -1,12 +1,6 @@ -import { - relayerOrderBookRequestSchema, -} from './relayer_orderbook_request_schema'; -import { - relayerOrdersRequestSchema, -} from './relayer_orders_request_schema'; -import { - relayerTokenPairsRequestSchema, -} from './relayer_token_pairs_request_schema'; +import { relayerOrderBookRequestSchema } from './relayer_orderbook_request_schema'; +import { relayerOrdersRequestSchema } from './relayer_orders_request_schema'; +import { relayerTokenPairsRequestSchema } from './relayer_token_pairs_request_schema'; export const schemas = { relayerOrderBookRequestSchema, diff --git a/packages/connect/src/types.ts b/packages/connect/src/types.ts index d02444a3e..edb6c77a6 100644 --- a/packages/connect/src/types.ts +++ b/packages/connect/src/types.ts @@ -1,4 +1,4 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; // TODO: Consolidate Order, SignedOrder and ECSignature into a shared package instead of duplicating them from 0x.js export interface Order { @@ -57,19 +57,24 @@ export interface OrderbookChannelSubscriptionOpts { } export interface OrderbookChannelHandler { - onSnapshot: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts, - snapshot: OrderbookResponse) => void; - onUpdate: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts, - order: SignedOrder) => void; - onError: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts, - err: Error) => void; + onSnapshot: ( + channel: OrderbookChannel, + subscriptionOpts: OrderbookChannelSubscriptionOpts, + snapshot: OrderbookResponse, + ) => void; + onUpdate: ( + channel: OrderbookChannel, + subscriptionOpts: OrderbookChannelSubscriptionOpts, + order: SignedOrder, + ) => void; + onError: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts, err: Error) => void; onClose: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts) => void; } export type OrderbookChannelMessage = - SnapshotOrderbookChannelMessage | - UpdateOrderbookChannelMessage | - UnknownOrderbookChannelMessage; + | SnapshotOrderbookChannelMessage + | UpdateOrderbookChannelMessage + | UnknownOrderbookChannelMessage; export enum OrderbookChannelMessageTypes { Snapshot = 'snapshot', diff --git a/packages/connect/src/utils/orderbook_channel_message_parser.ts b/packages/connect/src/utils/orderbook_channel_message_parser.ts new file mode 100644 index 000000000..9a9ca8901 --- /dev/null +++ b/packages/connect/src/utils/orderbook_channel_message_parser.ts @@ -0,0 +1,37 @@ +import { assert } from '@0xproject/assert'; +import { schemas } from '@0xproject/json-schemas'; +import * as _ from 'lodash'; + +import { OrderbookChannelMessage, OrderbookChannelMessageTypes } from '../types'; + +import { relayerResponseJsonParsers } from './relayer_response_json_parsers'; + +export const orderbookChannelMessageParser = { + parse(utf8Data: string): OrderbookChannelMessage { + const messageObj = JSON.parse(utf8Data); + const type: string = _.get(messageObj, 'type'); + assert.assert(!_.isUndefined(type), `Message is missing a type parameter: ${utf8Data}`); + assert.isString('type', type); + switch (type) { + case OrderbookChannelMessageTypes.Snapshot: { + assert.doesConformToSchema('message', messageObj, schemas.relayerApiOrderbookChannelSnapshotSchema); + const orderbookJson = messageObj.payload; + const orderbook = relayerResponseJsonParsers.parseOrderbookResponseJson(orderbookJson); + return _.assign(messageObj, { payload: orderbook }); + } + case OrderbookChannelMessageTypes.Update: { + assert.doesConformToSchema('message', messageObj, schemas.relayerApiOrderbookChannelUpdateSchema); + const orderJson = messageObj.payload; + const order = relayerResponseJsonParsers.parseOrderJson(orderJson); + return _.assign(messageObj, { payload: order }); + } + default: { + return { + type: OrderbookChannelMessageTypes.Unknown, + requestId: 0, + payload: undefined, + }; + } + } + }, +}; diff --git a/packages/connect/src/utils/orderbook_channel_message_parsers.ts b/packages/connect/src/utils/orderbook_channel_message_parsers.ts deleted file mode 100644 index 486a416ef..000000000 --- a/packages/connect/src/utils/orderbook_channel_message_parsers.ts +++ /dev/null @@ -1,41 +0,0 @@ -import {assert} from '@0xproject/assert'; -import {schemas} from '@0xproject/json-schemas'; -import * as _ from 'lodash'; - -import { - OrderbookChannelMessage, - OrderbookChannelMessageTypes, - SignedOrder, -} from '../types'; - -import {typeConverters} from './type_converters'; - -export const orderbookChannelMessageParsers = { - parser(utf8Data: string): OrderbookChannelMessage { - const messageObj = JSON.parse(utf8Data); - const type: string = _.get(messageObj, 'type'); - assert.assert(!_.isUndefined(type), `Message is missing a type parameter: ${utf8Data}`); - assert.isString('type', type); - switch (type) { - case (OrderbookChannelMessageTypes.Snapshot): { - assert.doesConformToSchema('message', messageObj, schemas.relayerApiOrderbookChannelSnapshotSchema); - const orderbook = messageObj.payload; - typeConverters.convertOrderbookStringFieldsToBigNumber(orderbook); - return messageObj; - } - case (OrderbookChannelMessageTypes.Update): { - assert.doesConformToSchema('message', messageObj, schemas.relayerApiOrderbookChannelUpdateSchema); - const order = messageObj.payload; - typeConverters.convertOrderStringFieldsToBigNumber(order); - return messageObj; - } - default: { - return { - type: OrderbookChannelMessageTypes.Unknown, - requestId: 0, - payload: undefined, - }; - } - } - }, -}; diff --git a/packages/connect/src/utils/relayer_response_json_parsers.ts b/packages/connect/src/utils/relayer_response_json_parsers.ts new file mode 100644 index 000000000..668461bf4 --- /dev/null +++ b/packages/connect/src/utils/relayer_response_json_parsers.ts @@ -0,0 +1,37 @@ +import { assert } from '@0xproject/assert'; +import { schemas } from '@0xproject/json-schemas'; +import * as _ from 'lodash'; + +import { FeesResponse, OrderbookResponse, SignedOrder, TokenPairsItem } from '../types'; + +import { typeConverters } from './type_converters'; + +export const relayerResponseJsonParsers = { + parseTokenPairsJson(json: any): TokenPairsItem[] { + assert.doesConformToSchema('tokenPairs', json, schemas.relayerApiTokenPairsResponseSchema); + return json.map((tokenPair: any) => { + return typeConverters.convertStringsFieldsToBigNumbers(tokenPair, [ + 'tokenA.minAmount', + 'tokenA.maxAmount', + 'tokenB.minAmount', + 'tokenB.maxAmount', + ]); + }); + }, + parseOrdersJson(json: any): SignedOrder[] { + assert.doesConformToSchema('orders', json, schemas.signedOrdersSchema); + return json.map((order: object) => typeConverters.convertOrderStringFieldsToBigNumber(order)); + }, + parseOrderJson(json: any): SignedOrder { + assert.doesConformToSchema('order', json, schemas.signedOrderSchema); + return typeConverters.convertOrderStringFieldsToBigNumber(json); + }, + parseOrderbookResponseJson(json: any): OrderbookResponse { + assert.doesConformToSchema('orderBook', json, schemas.relayerApiOrderBookResponseSchema); + return typeConverters.convertOrderbookStringFieldsToBigNumber(json); + }, + parseFeesResponseJson(json: any): FeesResponse { + assert.doesConformToSchema('fees', json, schemas.relayerApiFeesResponseSchema); + return typeConverters.convertStringsFieldsToBigNumbers(json, ['makerFee', 'takerFee']); + }, +}; diff --git a/packages/connect/src/utils/type_converters.ts b/packages/connect/src/utils/type_converters.ts index c136382fd..c1808ce8a 100644 --- a/packages/connect/src/utils/type_converters.ts +++ b/packages/connect/src/utils/type_converters.ts @@ -1,15 +1,17 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; -// TODO: convert all of these to non-mutating, pure functions export const typeConverters = { - convertOrderbookStringFieldsToBigNumber(orderbook: object): void { - _.each(orderbook, (orders: object[]) => { - _.each(orders, (order: object) => this.convertOrderStringFieldsToBigNumber(order)); - }); + convertOrderbookStringFieldsToBigNumber(orderbook: any): any { + const bids = _.get(orderbook, 'bids', []); + const asks = _.get(orderbook, 'asks', []); + return { + bids: bids.map((order: any) => this.convertOrderStringFieldsToBigNumber(order)), + asks: asks.map((order: any) => this.convertOrderStringFieldsToBigNumber(order)), + }; }, - convertOrderStringFieldsToBigNumber(order: object): void { - this.convertStringsFieldsToBigNumbers(order, [ + convertOrderStringFieldsToBigNumber(order: any): any { + return this.convertStringsFieldsToBigNumbers(order, [ 'makerTokenAmount', 'takerTokenAmount', 'makerFee', @@ -18,14 +20,11 @@ export const typeConverters = { 'salt', ]); }, - convertBigNumberFieldsToStrings(obj: object, fields: string[]): void { - _.each(fields, field => { - _.update(obj, field, (value: BigNumber) => value.toString()); - }); - }, - convertStringsFieldsToBigNumbers(obj: object, fields: string[]): void { + convertStringsFieldsToBigNumbers(obj: any, fields: string[]): any { + const result = _.assign({}, obj); _.each(fields, field => { - _.update(obj, field, (value: string) => new BigNumber(value)); + _.update(result, field, (value: string) => new BigNumber(value)); }); + return result; }, }; diff --git a/packages/connect/src/ws_orderbook_channel.ts b/packages/connect/src/ws_orderbook_channel.ts index 6687025c0..822a022f4 100644 --- a/packages/connect/src/ws_orderbook_channel.ts +++ b/packages/connect/src/ws_orderbook_channel.ts @@ -1,5 +1,5 @@ -import {assert} from '@0xproject/assert'; -import {schemas} from '@0xproject/json-schemas'; +import { assert } from '@0xproject/assert'; +import { schemas } from '@0xproject/json-schemas'; import * as _ from 'lodash'; import * as WebSocket from 'websocket'; @@ -8,21 +8,20 @@ import { OrderbookChannelHandler, OrderbookChannelMessageTypes, OrderbookChannelSubscriptionOpts, - SignedOrder, WebsocketClientEventType, WebsocketConnectionEventType, } from './types'; -import {orderbookChannelMessageParsers} from './utils/orderbook_channel_message_parsers'; +import { orderbookChannelMessageParser } from './utils/orderbook_channel_message_parser'; /** * This class includes all the functionality related to interacting with a websocket endpoint * that implements the standard relayer API v0 */ export class WebSocketOrderbookChannel implements OrderbookChannel { - private apiEndpointUrl: string; - private client: WebSocket.client; - private connectionIfExists?: WebSocket.connection; - private subscriptionCounter = 0; + private _apiEndpointUrl: string; + private _client: WebSocket.client; + private _connectionIfExists?: WebSocket.connection; + private _subscriptionCounter = 0; /** * Instantiates a new WebSocketOrderbookChannel instance * @param url The relayer API base WS url you would like to interact with @@ -30,8 +29,8 @@ export class WebSocketOrderbookChannel implements OrderbookChannel { */ constructor(url: string) { assert.isUri('url', url); - this.apiEndpointUrl = url; - this.client = new WebSocket.client(); + this._apiEndpointUrl = url; + this._client = new WebSocket.client(); } /** * Subscribe to orderbook snapshots and updates from the websocket @@ -42,16 +41,19 @@ export class WebSocketOrderbookChannel implements OrderbookChannel { */ public subscribe(subscriptionOpts: OrderbookChannelSubscriptionOpts, handler: OrderbookChannelHandler): void { assert.doesConformToSchema( - 'subscriptionOpts', subscriptionOpts, schemas.relayerApiOrderbookChannelSubscribePayload); + 'subscriptionOpts', + subscriptionOpts, + schemas.relayerApiOrderbookChannelSubscribePayload, + ); assert.isFunction('handler.onSnapshot', _.get(handler, 'onSnapshot')); assert.isFunction('handler.onUpdate', _.get(handler, 'onUpdate')); assert.isFunction('handler.onError', _.get(handler, 'onError')); assert.isFunction('handler.onClose', _.get(handler, 'onClose')); - this.subscriptionCounter += 1; + this._subscriptionCounter += 1; const subscribeMessage = { type: 'subscribe', channel: 'orderbook', - requestId: this.subscriptionCounter, + requestId: this._subscriptionCounter, payload: subscriptionOpts, }; this._getConnection((error, connection) => { @@ -75,44 +77,50 @@ export class WebSocketOrderbookChannel implements OrderbookChannel { * Close the websocket and stop receiving updates */ public close() { - if (!_.isUndefined(this.connectionIfExists)) { - this.connectionIfExists.close(); + if (!_.isUndefined(this._connectionIfExists)) { + this._connectionIfExists.close(); } } private _getConnection(callback: (error?: Error, connection?: WebSocket.connection) => void) { - if (!_.isUndefined(this.connectionIfExists) && this.connectionIfExists.connected) { - callback(undefined, this.connectionIfExists); + if (!_.isUndefined(this._connectionIfExists) && this._connectionIfExists.connected) { + callback(undefined, this._connectionIfExists); } else { - this.client.on(WebsocketClientEventType.Connect, connection => { - this.connectionIfExists = connection; - callback(undefined, this.connectionIfExists); + this._client.on(WebsocketClientEventType.Connect, connection => { + this._connectionIfExists = connection; + callback(undefined, this._connectionIfExists); }); - this.client.on(WebsocketClientEventType.ConnectFailed, error => { + this._client.on(WebsocketClientEventType.ConnectFailed, error => { callback(error, undefined); }); - this.client.connect(this.apiEndpointUrl); + this._client.connect(this._apiEndpointUrl); } } - private _handleWebSocketMessage(requestId: number, subscriptionOpts: OrderbookChannelSubscriptionOpts, - message: WebSocket.IMessage, handler: OrderbookChannelHandler): void { + private _handleWebSocketMessage( + requestId: number, + subscriptionOpts: OrderbookChannelSubscriptionOpts, + message: WebSocket.IMessage, + handler: OrderbookChannelHandler, + ): void { if (!_.isUndefined(message.utf8Data)) { try { const utf8Data = message.utf8Data; - const parserResult = orderbookChannelMessageParsers.parser(utf8Data); - const type = parserResult.type; + const parserResult = orderbookChannelMessageParser.parse(utf8Data); if (parserResult.requestId === requestId) { switch (parserResult.type) { - case (OrderbookChannelMessageTypes.Snapshot): { + case OrderbookChannelMessageTypes.Snapshot: { handler.onSnapshot(this, subscriptionOpts, parserResult.payload); break; } - case (OrderbookChannelMessageTypes.Update): { + case OrderbookChannelMessageTypes.Update: { handler.onUpdate(this, subscriptionOpts, parserResult.payload); break; } default: { handler.onError( - this, subscriptionOpts, new Error(`Message has missing a type parameter: ${utf8Data}`)); + this, + subscriptionOpts, + new Error(`Message has missing a type parameter: ${utf8Data}`), + ); } } } diff --git a/packages/connect/test/fixtures/standard_relayer_api/fees.ts b/packages/connect/test/fixtures/standard_relayer_api/fees.ts index 68421880e..fecbaacff 100644 --- a/packages/connect/test/fixtures/standard_relayer_api/fees.ts +++ b/packages/connect/test/fixtures/standard_relayer_api/fees.ts @@ -1,6 +1,6 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; -import {FeesResponse} from '../../../src/types'; +import { FeesResponse } from '../../../src/types'; export const feesResponse: FeesResponse = { feeRecipient: '0x323b5d4c32345ced77393b3530b1eed0f346429d', diff --git a/packages/connect/test/fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f.ts b/packages/connect/test/fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f.ts index 9df45065c..5a03a2ff6 100644 --- a/packages/connect/test/fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f.ts +++ b/packages/connect/test/fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f.ts @@ -1,4 +1,4 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; export const orderResponse = { maker: '0x9e56625509c2f60af937f23b7b532600390e8c8b', diff --git a/packages/connect/test/fixtures/standard_relayer_api/orderbook.json b/packages/connect/test/fixtures/standard_relayer_api/orderbook.json index bd6e10e4c..825be34c2 100644 --- a/packages/connect/test/fixtures/standard_relayer_api/orderbook.json +++ b/packages/connect/test/fixtures/standard_relayer_api/orderbook.json @@ -41,4 +41,4 @@ } } ] -}
\ No newline at end of file +} diff --git a/packages/connect/test/fixtures/standard_relayer_api/orderbook.ts b/packages/connect/test/fixtures/standard_relayer_api/orderbook.ts index 529d2b450..6684ac2e5 100644 --- a/packages/connect/test/fixtures/standard_relayer_api/orderbook.ts +++ b/packages/connect/test/fixtures/standard_relayer_api/orderbook.ts @@ -1,4 +1,4 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; export const orderbookResponse = { bids: [ diff --git a/packages/connect/test/fixtures/standard_relayer_api/orders.ts b/packages/connect/test/fixtures/standard_relayer_api/orders.ts index 54c8a150d..5044777bd 100644 --- a/packages/connect/test/fixtures/standard_relayer_api/orders.ts +++ b/packages/connect/test/fixtures/standard_relayer_api/orders.ts @@ -1,4 +1,4 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; export const ordersResponse = [ { diff --git a/packages/connect/test/fixtures/standard_relayer_api/token_pairs.ts b/packages/connect/test/fixtures/standard_relayer_api/token_pairs.ts index b3ae7a1b1..f48b1e877 100644 --- a/packages/connect/test/fixtures/standard_relayer_api/token_pairs.ts +++ b/packages/connect/test/fixtures/standard_relayer_api/token_pairs.ts @@ -1,6 +1,6 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; -import {TokenPairsItem} from '../../../src/types'; +import { TokenPairsItem } from '../../../src/types'; export const tokenPairsResponse: TokenPairsItem[] = [ { diff --git a/packages/connect/test/http_client_test.ts b/packages/connect/test/http_client_test.ts index 21e7abb69..15759d911 100644 --- a/packages/connect/test/http_client_test.ts +++ b/packages/connect/test/http_client_test.ts @@ -1,24 +1,21 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import * as chaiAsPromised from 'chai-as-promised'; import * as dirtyChai from 'dirty-chai'; import * as fetchMock from 'fetch-mock'; import 'mocha'; -import {HttpClient} from '../src/index'; +import { HttpClient } from '../src/index'; -import {feesResponse} from './fixtures/standard_relayer_api/fees'; +import { feesResponse } from './fixtures/standard_relayer_api/fees'; import * as feesResponseJSON from './fixtures/standard_relayer_api/fees.json'; -import { - orderResponse, -} from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f'; -// tslint:disable-next-line:max-line-length +import { orderResponse } from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f'; import * as orderResponseJSON from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f.json'; -import {orderbookResponse} from './fixtures/standard_relayer_api/orderbook'; +import { orderbookResponse } from './fixtures/standard_relayer_api/orderbook'; import * as orderbookJSON from './fixtures/standard_relayer_api/orderbook.json'; -import {ordersResponse} from './fixtures/standard_relayer_api/orders'; +import { ordersResponse } from './fixtures/standard_relayer_api/orders'; import * as ordersResponseJSON from './fixtures/standard_relayer_api/orders.json'; -import {tokenPairsResponse} from './fixtures/standard_relayer_api/token_pairs'; +import { tokenPairsResponse } from './fixtures/standard_relayer_api/token_pairs'; import * as tokenPairsResponseJSON from './fixtures/standard_relayer_api/token_pairs.json'; chai.config.includeStack = true; @@ -32,14 +29,23 @@ describe('HttpClient', () => { afterEach(() => { fetchMock.restore(); }); + describe('#constructor', () => { + it('should remove trailing slashes from api url', async () => { + const urlWithTrailingSlash = 'https://slash.com/'; + const urlWithoutTrailingSlash = 'https://slash.com'; + const client = new HttpClient(urlWithTrailingSlash); + const sanitizedUrl = (client as any)._apiEndpointUrl; + expect(sanitizedUrl).to.be.deep.equal(urlWithoutTrailingSlash); + }); + }); describe('#getTokenPairsAsync', () => { - const url = `${relayUrl}/v0/token_pairs`; + const url = `${relayUrl}/token_pairs`; it('gets token pairs', async () => { fetchMock.get(url, tokenPairsResponseJSON); const tokenPairs = await relayerClient.getTokenPairsAsync(); expect(tokenPairs).to.be.deep.equal(tokenPairsResponse); }); - it('gets specfic token pairs for request', async () => { + it('gets specific token pairs for request', async () => { const tokenAddress = '0x323b5d4c32345ced77393b3530b1eed0f346429d'; const tokenPairsRequest = { tokenA: tokenAddress, @@ -50,12 +56,12 @@ describe('HttpClient', () => { expect(tokenPairs).to.be.deep.equal(tokenPairsResponse); }); it('throws an error for invalid JSON response', async () => { - fetchMock.get(url, {test: 'dummy'}); + fetchMock.get(url, { test: 'dummy' }); expect(relayerClient.getTokenPairsAsync()).to.be.rejected(); }); }); describe('#getOrdersAsync', () => { - const url = `${relayUrl}/v0/orders`; + const url = `${relayUrl}/orders`; it('gets orders', async () => { fetchMock.get(url, ordersResponseJSON); const orders = await relayerClient.getOrdersAsync(); @@ -72,20 +78,20 @@ describe('HttpClient', () => { expect(orders).to.be.deep.equal(ordersResponse); }); it('throws an error for invalid JSON response', async () => { - fetchMock.get(url, {test: 'dummy'}); + fetchMock.get(url, { test: 'dummy' }); expect(relayerClient.getOrdersAsync()).to.be.rejected(); }); }); describe('#getOrderAsync', () => { const orderHash = '0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f'; - const url = `${relayUrl}/v0/order/${orderHash}`; + const url = `${relayUrl}/order/${orderHash}`; it('gets order', async () => { fetchMock.get(url, orderResponseJSON); const order = await relayerClient.getOrderAsync(orderHash); expect(order).to.be.deep.equal(orderResponse); }); it('throws an error for invalid JSON response', async () => { - fetchMock.get(url, {test: 'dummy'}); + fetchMock.get(url, { test: 'dummy' }); expect(relayerClient.getOrderAsync(orderHash)).to.be.rejected(); }); }); @@ -94,15 +100,16 @@ describe('HttpClient', () => { baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d', quoteTokenAddress: '0xa2b31dacf30a9c50ca473337c01d8a201ae33e32', }; - // tslint:disable-next-line:max-line-length - const url = `${relayUrl}/v0/orderbook?baseTokenAddress=${request.baseTokenAddress}"eTokenAddress=${request.quoteTokenAddress}`; + const url = `${relayUrl}/orderbook?baseTokenAddress=${request.baseTokenAddress}"eTokenAddress=${ + request.quoteTokenAddress + }`; it('gets order book', async () => { fetchMock.get(url, orderbookJSON); const orderbook = await relayerClient.getOrderbookAsync(request); expect(orderbook).to.be.deep.equal(orderbookResponse); }); it('throws an error for invalid JSON response', async () => { - fetchMock.get(url, {test: 'dummy'}); + fetchMock.get(url, { test: 'dummy' }); expect(relayerClient.getOrderbookAsync(request)).to.be.rejected(); }); }); @@ -118,14 +125,26 @@ describe('HttpClient', () => { salt: new BigNumber('256'), expirationUnixTimestampSec: new BigNumber('42'), }; - const url = `${relayUrl}/v0/fees`; + const url = `${relayUrl}/fees`; it('gets fees', async () => { fetchMock.post(url, feesResponseJSON); const fees = await relayerClient.getFeesAsync(request); expect(fees).to.be.deep.equal(feesResponse); }); + it('does not mutate input', async () => { + fetchMock.post(url, feesResponseJSON); + const makerTokenAmountBefore = new BigNumber(request.makerTokenAmount); + const takerTokenAmountBefore = new BigNumber(request.takerTokenAmount); + const saltBefore = new BigNumber(request.salt); + const expirationUnixTimestampSecBefore = new BigNumber(request.expirationUnixTimestampSec); + await relayerClient.getFeesAsync(request); + expect(makerTokenAmountBefore).to.be.deep.equal(request.makerTokenAmount); + expect(takerTokenAmountBefore).to.be.deep.equal(request.takerTokenAmount); + expect(saltBefore).to.be.deep.equal(request.salt); + expect(expirationUnixTimestampSecBefore).to.be.deep.equal(request.expirationUnixTimestampSec); + }); it('throws an error for invalid JSON response', async () => { - fetchMock.post(url, {test: 'dummy'}); + fetchMock.post(url, { test: 'dummy' }); expect(relayerClient.getFeesAsync(request)).to.be.rejected(); }); }); diff --git a/packages/connect/test/orderbook_channel_message_parsers_test.ts b/packages/connect/test/orderbook_channel_message_parsers_test.ts index 2c776b095..3e1f44384 100644 --- a/packages/connect/test/orderbook_channel_message_parsers_test.ts +++ b/packages/connect/test/orderbook_channel_message_parsers_test.ts @@ -2,16 +2,15 @@ import * as chai from 'chai'; import * as dirtyChai from 'dirty-chai'; import 'mocha'; -import {orderbookChannelMessageParsers} from '../src/utils/orderbook_channel_message_parsers'; +import { orderbookChannelMessageParser } from '../src/utils/orderbook_channel_message_parser'; -// tslint:disable-next-line:max-line-length -import {orderResponse} from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f'; -import {orderbookResponse} from './fixtures/standard_relayer_api/orderbook'; +import { orderResponse } from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f'; +import { orderbookResponse } from './fixtures/standard_relayer_api/orderbook'; import { malformedSnapshotOrderbookChannelMessage, snapshotOrderbookChannelMessage, } from './fixtures/standard_relayer_api/snapshot_orderbook_channel_message'; -import {unknownOrderbookChannelMessage} from './fixtures/standard_relayer_api/unknown_orderbook_channel_message'; +import { unknownOrderbookChannelMessage } from './fixtures/standard_relayer_api/unknown_orderbook_channel_message'; import { malformedUpdateOrderbookChannelMessage, updateOrderbookChannelMessage, @@ -21,20 +20,20 @@ chai.config.includeStack = true; chai.use(dirtyChai); const expect = chai.expect; -describe('orderbookChannelMessageParsers', () => { +describe('orderbookChannelMessageParser', () => { describe('#parser', () => { it('parses snapshot messages', () => { - const snapshotMessage = orderbookChannelMessageParsers.parser(snapshotOrderbookChannelMessage); + const snapshotMessage = orderbookChannelMessageParser.parse(snapshotOrderbookChannelMessage); expect(snapshotMessage.type).to.be.equal('snapshot'); expect(snapshotMessage.payload).to.be.deep.equal(orderbookResponse); }); it('parses update messages', () => { - const updateMessage = orderbookChannelMessageParsers.parser(updateOrderbookChannelMessage); + const updateMessage = orderbookChannelMessageParser.parse(updateOrderbookChannelMessage); expect(updateMessage.type).to.be.equal('update'); expect(updateMessage.payload).to.be.deep.equal(orderResponse); }); it('returns unknown message for messages with unsupported types', () => { - const unknownMessage = orderbookChannelMessageParsers.parser(unknownOrderbookChannelMessage); + const unknownMessage = orderbookChannelMessageParser.parse(unknownOrderbookChannelMessage); expect(unknownMessage.type).to.be.equal('unknown'); expect(unknownMessage.payload).to.be.undefined(); }); @@ -44,7 +43,7 @@ describe('orderbookChannelMessageParsers', () => { "requestId": 1, "payload": {} }`; - const badCall = () => orderbookChannelMessageParsers.parser(typelessMessage); + const badCall = () => orderbookChannelMessageParser.parse(typelessMessage); expect(badCall).throws(`Message is missing a type parameter: ${typelessMessage}`); }); it('throws when type is not a string', () => { @@ -54,24 +53,23 @@ describe('orderbookChannelMessageParsers', () => { "requestId": 1, "payload": {} }`; - const badCall = () => orderbookChannelMessageParsers.parser(messageWithBadType); + const badCall = () => orderbookChannelMessageParser.parse(messageWithBadType); expect(badCall).throws('Expected type to be of type string, encountered: 1'); }); it('throws when snapshot message has malformed payload', () => { - const badCall = () => - orderbookChannelMessageParsers.parser(malformedSnapshotOrderbookChannelMessage); + const badCall = () => orderbookChannelMessageParser.parse(malformedSnapshotOrderbookChannelMessage); // tslint:disable-next-line:max-line-length - const errMsg = 'Validation errors: instance.payload requires property "bids", instance.payload requires property "asks"'; + const errMsg = + 'Validation errors: instance.payload requires property "bids", instance.payload requires property "asks"'; expect(badCall).throws(errMsg); }); it('throws when update message has malformed payload', () => { - const badCall = () => - orderbookChannelMessageParsers.parser(malformedUpdateOrderbookChannelMessage); + const badCall = () => orderbookChannelMessageParser.parse(malformedUpdateOrderbookChannelMessage); expect(badCall).throws(/^Expected message to conform to schema/); }); it('throws when input message is not valid JSON', () => { const nonJsonString = 'h93b{sdfs9fsd f'; - const badCall = () => orderbookChannelMessageParsers.parser(nonJsonString); + const badCall = () => orderbookChannelMessageParser.parse(nonJsonString); expect(badCall).throws('Unexpected token h in JSON at position 0'); }); }); diff --git a/packages/connect/test/ws_orderbook_channel_test.ts b/packages/connect/test/ws_orderbook_channel_test.ts index 6190a5ac3..ce404d934 100644 --- a/packages/connect/test/ws_orderbook_channel_test.ts +++ b/packages/connect/test/ws_orderbook_channel_test.ts @@ -3,9 +3,7 @@ import * as dirtyChai from 'dirty-chai'; import * as _ from 'lodash'; import 'mocha'; -import { - WebSocketOrderbookChannel, -} from '../src/ws_orderbook_channel'; +import { WebSocketOrderbookChannel } from '../src/ws_orderbook_channel'; chai.config.includeStack = true; chai.use(dirtyChai); @@ -21,26 +19,42 @@ describe('WebSocketOrderbookChannel', () => { limit: 100, }; const emptyOrderbookChannelHandler = { - onSnapshot: () => { _.noop(); }, - onUpdate: () => { _.noop(); }, - onError: () => { _.noop(); }, - onClose: () => { _.noop(); }, + onSnapshot: () => { + _.noop(); + }, + onUpdate: () => { + _.noop(); + }, + onError: () => { + _.noop(); + }, + onClose: () => { + _.noop(); + }, }; describe('#subscribe', () => { it('throws when subscriptionOpts does not conform to schema', () => { const badSubscribeCall = orderbookChannel.subscribe.bind( - orderbookChannel, {}, emptyOrderbookChannelHandler); - // tslint:disable-next-line:max-line-length - expect(badSubscribeCall).throws('Expected subscriptionOpts to conform to schema /RelayerApiOrderbookChannelSubscribePayload\nEncountered: {}\nValidation errors: instance requires property "baseTokenAddress", instance requires property "quoteTokenAddress"'); + orderbookChannel, + {}, + emptyOrderbookChannelHandler, + ); + expect(badSubscribeCall).throws( + 'Expected subscriptionOpts to conform to schema /RelayerApiOrderbookChannelSubscribePayload\nEncountered: {}\nValidation errors: instance requires property "baseTokenAddress", instance requires property "quoteTokenAddress"', + ); }); it('throws when handler has the incorrect members', () => { const badSubscribeCall = orderbookChannel.subscribe.bind(orderbookChannel, subscriptionOpts, {}); - expect(badSubscribeCall) - .throws('Expected handler.onSnapshot to be of type function, encountered: undefined'); + expect(badSubscribeCall).throws( + 'Expected handler.onSnapshot to be of type function, encountered: undefined', + ); }); it('does not throw when inputs are of correct types', () => { const goodSubscribeCall = orderbookChannel.subscribe.bind( - orderbookChannel, subscriptionOpts, emptyOrderbookChannelHandler); + orderbookChannel, + subscriptionOpts, + emptyOrderbookChannelHandler, + ); expect(goodSubscribeCall).to.not.throw(); }); }); diff --git a/packages/connect/tsconfig.json b/packages/connect/tsconfig.json index a6c8277f8..3c150236e 100644 --- a/packages/connect/tsconfig.json +++ b/packages/connect/tsconfig.json @@ -1,19 +1,12 @@ { + "extends": "../../tsconfig", "compilerOptions": { - "module": "commonjs", - "target": "es5", - "lib": [ "es2015", "dom" ], - "outDir": "lib", - "sourceMap": true, - "declaration": true, - "noImplicitAny": true, - "strictNullChecks": true + "outDir": "lib" }, "include": [ - "./src/**/*", - "./test/**/*", - "../../node_modules/chai-as-promised-typescript-typings/index.d.ts", - "../../node_modules/chai-typescript-typings/index.d.ts", - "../../node_modules/web3-typescript-typings/index.d.ts" + "./src/**/*", + "./test/**/*", + "../../node_modules/chai-as-promised-typescript-typings/index.d.ts", + "../../node_modules/chai-typescript-typings/index.d.ts" ] - } +} diff --git a/packages/connect/tslint.json b/packages/connect/tslint.json index a07795151..ffaefe83a 100644 --- a/packages/connect/tslint.json +++ b/packages/connect/tslint.json @@ -1,5 +1,3 @@ { - "extends": [ - "@0xproject/tslint-config" - ] + "extends": ["@0xproject/tslint-config"] } diff --git a/packages/contracts/README.md b/packages/contracts/README.md index 57c75cb85..0a1c272ab 100644 --- a/packages/contracts/README.md +++ b/packages/contracts/README.md @@ -1,51 +1,68 @@ -Contracts ------ +## Contracts -## Useful 0x Wiki Articles +Smart contracts that implement the 0x protocol. -* [Architecture](https://0xproject.com/wiki#Architecture) -* [Contract Interactions](https://0xproject.com/wiki#Contract-Interactions) -* [Contract deployed addresses](https://0xproject.com/wiki#Deployed-Addresses) -* [0x Protocol Message Format](https://0xproject.com/wiki#Message-Format) -* [Bug Bounty Program](https://0xproject.com/wiki#Bug-Bounty) +## Usage -## Setup +* [Docs](https://0xproject.com/docs/contracts) +* [Overview of 0x protocol architecture](https://0xproject.com/wiki#Architecture) +* [0x smart contract interactions](https://0xproject.com/wiki#Contract-Interactions) +* [Deployed smart contract addresses](https://0xproject.com/wiki#Deployed-Addresses) +* [0x protocol message format](https://0xproject.com/wiki#Message-Format) -### Installing Dependencies +## Contributing -Install [Node](https://nodejs.org/en/download/releases/) +We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. -Install [yarn](https://yarnpkg.com/lang/en/docs/install/) in order to install the project dependencies more deterministically. +For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein. -Install project dependencies: +Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. -``` -yarn -``` +### Install Dependencies + +If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: -### Running Tests +```bash +yarn config set workspaces-experimental true +``` -Start Testrpc +Then install dependencies +```bash +yarn install ``` -yarn testrpc + +### Build + +```bash +yarn build ``` -Run tests +### Clean +```bash +yarn clean ``` -yarn test + +### Lint + +```bash +yarn lint ``` -## Contributing +### Run Tests -0x protocol is intended to serve as an open technical standard for EVM blockchains and we strongly encourage our community members to help us make improvements and to determine the future direction of the protocol. To report bugs within the 0x smart contracts or unit tests, please create an issue in this repository. +Before running the tests, you will need to spin up a [TestRPC](https://www.npmjs.com/package/ethereumjs-testrpc) instance. -### ZEIPs -Significant changes to 0x protocol's smart contracts, architecture, message format or functionality should be proposed in the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository. Follow the contribution guidelines provided therein. +In a separate terminal, start TestRPC (a convenience command is provided as part of the [0x.js monorepo](https://github.com/0xProject/0x.js)) -### Coding conventions +```bash +cd ../.. +yarn testrpc +``` -We use a custom set of [TSLint](https://palantir.github.io/tslint/) rules to enforce our coding conventions. +Then in your main terminal run -In order to see style violation errors, install a tslinter for your text editor. e.g Atom's [atom-typescript](https://atom.io/packages/atom-typescript). +```bash +yarn test +``` diff --git a/packages/contracts/build/contracts/DummyToken.json b/packages/contracts/build/contracts/DummyToken.json index 2698a1e17..6ed9daeed 100644 --- a/packages/contracts/build/contracts/DummyToken.json +++ b/packages/contracts/build/contracts/DummyToken.json @@ -286,7 +286,7 @@ "type": "event" } ], - "unlinked_binary": "0x6060604052341561000c57fe5b604051610a46380380610a4683398101604090815281516020830151918301516060840151918401939290920191905b5b60038054600160a060020a03191633600160a060020a03161790555b835161006c9060049060208701906100b0565b5082516100809060059060208601906100b0565b5060068290556002819055600160a060020a03331660009081526020819052604090208190555b50505050610150565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100f157805160ff191683800117855561011e565b8280016001018555821561011e579182015b8281111561011e578251825591602001919060010190610103565b5b5061012b92915061012f565b5090565b61014d91905b8082111561012b5760008155600101610135565b5090565b90565b6108e78061015f6000396000f300606060405236156100a95763ffffffff60e060020a60003504166306fdde0381146100ab578063095ea7b31461013b57806318160ddd1461016e57806323b872dd14610190578063313ce567146101c957806370a08231146101eb5780638da5cb5b1461021957806395d89b4114610245578063a0712d68146102d5578063a9059cbb146102ea578063dd62ed3e1461031d578063e30443bc14610351578063f2fde38b14610372575bfe5b34156100b357fe5b6100bb610390565b604080516020808252835181830152835191928392908301918501908083838215610101575b80518252602083111561010157601f1990920191602091820191016100e1565b505050905090810190601f16801561012d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014357fe5b61015a600160a060020a036004351660243561041e565b604080519115158252519081900360200190f35b341561017657fe5b61017e610489565b60408051918252519081900360200190f35b341561019857fe5b61015a600160a060020a036004358116906024351660443561048f565b604080519115158252519081900360200190f35b34156101d157fe5b61017e61058b565b60408051918252519081900360200190f35b34156101f357fe5b61017e600160a060020a0360043516610591565b60408051918252519081900360200190f35b341561022157fe5b6102296105b0565b60408051600160a060020a039092168252519081900360200190f35b341561024d57fe5b6100bb6105bf565b604080516020808252835181830152835191928392908301918501908083838215610101575b80518252602083111561010157601f1990920191602091820191016100e1565b505050905090810190601f16801561012d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156102dd57fe5b6102e860043561064d565b005b34156102f257fe5b61015a600160a060020a03600435166024356106b5565b604080519115158252519081900360200190f35b341561032557fe5b61017e600160a060020a0360043581169060243516610767565b60408051918252519081900360200190f35b341561035957fe5b6102e8600160a060020a0360043516602435610794565b005b341561037a57fe5b6102e8600160a060020a036004351661081e565b005b6004805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156104165780601f106103eb57610100808354040283529160200191610416565b820191906000526020600020905b8154815290600101906020018083116103f957829003601f168201915b505050505081565b600160a060020a03338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60025481565b600160a060020a0383166000908152602081905260408120548290108015906104df5750600160a060020a0380851660009081526001602090815260408083203390941683529290522054829010155b80156105055750600160a060020a03831660009081526020819052604090205482810110155b1561057f57600160a060020a03808416600081815260208181526040808320805488019055888516808452818420805489900390556001835281842033909616845294825291829020805487900390558151868152915192939260008051602061089c8339815191529281900390910190a3506001610583565b5060005b5b9392505050565b60065481565b600160a060020a0381166000908152602081905260409020545b919050565b600354600160a060020a031681565b6005805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156104165780601f106103eb57610100808354040283529160200191610416565b820191906000526020600020905b8154815290600101906020018083116103f957829003601f168201915b505050505081565b68056bc75e2d631000008111156106645760006000fd5b600160a060020a03331660009081526020819052604090205461068890829061086a565b600160a060020a0333166000908152602081905260409020556002546106ae908261086a565b6002555b50565b600160a060020a0333166000908152602081905260408120548290108015906106f85750600160a060020a03831660009081526020819052604090205482810110155b1561075857600160a060020a03338116600081815260208181526040808320805488900390559387168083529184902080548701905583518681529351919360008051602061089c833981519152929081900390910190a3506001610483565b506000610483565b5b92915050565b600160a060020a038083166000908152600160209081526040808320938516835292905220545b92915050565b60035460009033600160a060020a039081169116146107b35760006000fd5b6107bc83610591565b9050808210156107e3576107db6002546107d68385610884565b610884565b6002556107fc565b6107f86002546107f38484610884565b61086a565b6002555b600160a060020a03831660009081526020819052604090208290555b5b505050565b60035433600160a060020a0390811691161461083a5760006000fd5b600160a060020a038116156106b25760038054600160a060020a031916600160a060020a0383161790555b5b5b50565b60008282018381101561087957fe5b8091505b5092915050565b60008282111561089057fe5b508082035b929150505600ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a723058204a428de115c741873c68da562de00a2839a910073c061da3394aa07287d9ef5f0029", + "unlinked_binary": "0x6060604052341561000c57fe5b604051610a6d380380610a6d83398101604090815281516020830151918301516060840151918401939290920191905b5b60038054600160a060020a03191633600160a060020a03161790555b835161006c9060049060208701906100b0565b5082516100809060059060208601906100b0565b5060068290556002819055600160a060020a03331660009081526020819052604090208190555b50505050610150565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100f157805160ff191683800117855561011e565b8280016001018555821561011e579182015b8281111561011e578251825591602001919060010190610103565b5b5061012b92915061012f565b5090565b61014d91905b8082111561012b5760008155600101610135565b5090565b90565b61090e8061015f6000396000f300606060405236156100a95763ffffffff60e060020a60003504166306fdde0381146100ab578063095ea7b31461013b57806318160ddd1461016e57806323b872dd14610190578063313ce567146101c957806370a08231146101eb5780638da5cb5b1461021957806395d89b4114610245578063a0712d68146102d5578063a9059cbb146102ea578063dd62ed3e1461031d578063e30443bc14610351578063f2fde38b14610372575bfe5b34156100b357fe5b6100bb610390565b604080516020808252835181830152835191928392908301918501908083838215610101575b80518252602083111561010157601f1990920191602091820191016100e1565b505050905090810190601f16801561012d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014357fe5b61015a600160a060020a036004351660243561041e565b604080519115158252519081900360200190f35b341561017657fe5b61017e610489565b60408051918252519081900360200190f35b341561019857fe5b61015a600160a060020a036004358116906024351660443561048f565b604080519115158252519081900360200190f35b34156101d157fe5b61017e6105b2565b60408051918252519081900360200190f35b34156101f357fe5b61017e600160a060020a03600435166105b8565b60408051918252519081900360200190f35b341561022157fe5b6102296105d7565b60408051600160a060020a039092168252519081900360200190f35b341561024d57fe5b6100bb6105e6565b604080516020808252835181830152835191928392908301918501908083838215610101575b80518252602083111561010157601f1990920191602091820191016100e1565b505050905090810190601f16801561012d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156102dd57fe5b6102e8600435610674565b005b34156102f257fe5b61015a600160a060020a03600435166024356106dc565b604080519115158252519081900360200190f35b341561032557fe5b61017e600160a060020a036004358116906024351661078e565b60408051918252519081900360200190f35b341561035957fe5b6102e8600160a060020a03600435166024356107bb565b005b341561037a57fe5b6102e8600160a060020a0360043516610845565b005b6004805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156104165780601f106103eb57610100808354040283529160200191610416565b820191906000526020600020905b8154815290600101906020018083116103f957829003601f168201915b505050505081565b600160a060020a03338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60025481565b600160a060020a03808416600081815260016020908152604080832033909516835293815283822054928252819052918220548390108015906104d25750828110155b80156104f85750600160a060020a03841660009081526020819052604090205483810110155b156105a457600160a060020a038085166000908152602081905260408082208054870190559187168152208054849003905560001981101561056257600160a060020a03808616600090815260016020908152604080832033909416835292905220805484900390555b83600160a060020a031685600160a060020a03166000805160206108c3833981519152856040518082815260200191505060405180910390a3600191506105a9565b600091505b5b509392505050565b60065481565b600160a060020a0381166000908152602081905260409020545b919050565b600354600160a060020a031681565b6005805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156104165780601f106103eb57610100808354040283529160200191610416565b820191906000526020600020905b8154815290600101906020018083116103f957829003601f168201915b505050505081565b68056bc75e2d6310000081111561068b5760006000fd5b600160a060020a0333166000908152602081905260409020546106af908290610891565b600160a060020a0333166000908152602081905260409020556002546106d59082610891565b6002555b50565b600160a060020a03331660009081526020819052604081205482901080159061071f5750600160a060020a03831660009081526020819052604090205482810110155b1561077f57600160a060020a0333811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191936000805160206108c3833981519152929081900390910190a3506001610483565b506000610483565b5b92915050565b600160a060020a038083166000908152600160209081526040808320938516835292905220545b92915050565b60035460009033600160a060020a039081169116146107da5760006000fd5b6107e3836105b8565b90508082101561080a576108026002546107fd83856108ab565b6108ab565b600255610823565b61081f60025461081a84846108ab565b610891565b6002555b600160a060020a03831660009081526020819052604090208290555b5b505050565b60035433600160a060020a039081169116146108615760006000fd5b600160a060020a038116156106d95760038054600160a060020a031916600160a060020a0383161790555b5b5b50565b6000828201838110156108a057fe5b8091505b5092915050565b6000828211156108b757fe5b508082035b929150505600ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a72305820d93905a702dd25447548c9b62604a718169270050b73347c63e4161fb4317c7e0029", "networks": { "50": { "links": {}, @@ -336,9 +336,9 @@ "type": "event" } }, - "updated_at": 1502391794392 + "updated_at": 1513088404208 } }, "schema_version": "0.0.5", - "updated_at": 1502391794392 + "updated_at": 1513088404208 }
\ No newline at end of file diff --git a/packages/contracts/build/contracts/EtherToken.json b/packages/contracts/build/contracts/EtherToken.json index f46e256ca..64e144e20 100644 --- a/packages/contracts/build/contracts/EtherToken.json +++ b/packages/contracts/build/contracts/EtherToken.json @@ -233,9 +233,9 @@ "type": "event" } ], - "unlinked_binary": "0x6060604052341561000c57fe5b5b61070f8061001c6000396000f300606060405236156100935763ffffffff60e060020a60003504166306fdde0381146100a4578063095ea7b31461013457806318160ddd1461016757806323b872dd146101895780632e1a7d4d146101c2578063313ce567146101d757806370a08231146101fd57806395d89b411461022b578063a9059cbb146102bb578063d0e30db0146102ee578063dd62ed3e146102f8575b6100a25b61009f61032c565b5b565b005b34156100ac57fe5b6100b461037b565b6040805160208082528351818301528351919283929083019185019080838382156100fa575b8051825260208311156100fa57601f1990920191602091820191016100da565b505050905090810190601f1680156101265780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561013c57fe5b610153600160a060020a03600435166024356103a3565b604080519115158252519081900360200190f35b341561016f57fe5b61017761040e565b60408051918252519081900360200190f35b341561019157fe5b610153600160a060020a0360043581169060243516604435610414565b604080519115158252519081900360200190f35b34156101ca57fe5b6100a26004356104ff565b005b34156101df57fe5b6101e7610580565b6040805160ff9092168252519081900360200190f35b341561020557fe5b610177600160a060020a0360043516610585565b60408051918252519081900360200190f35b341561023357fe5b6100b46105a4565b6040805160208082528351818301528351919283929083019185019080838382156100fa575b8051825260208311156100fa57601f1990920191602091820191016100da565b505050905090810190601f1680156101265780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156102c357fe5b610153600160a060020a03600435166024356105c5565b604080519115158252519081900360200190f35b6100a261032c565b005b341561030057fe5b610177600160a060020a0360043581169060243516610665565b60408051918252519081900360200190f35b600160a060020a03331660009081526020819052604090205461034f9034610692565b600160a060020a0333166000908152602081905260409020556002546103759034610692565b6002555b565b60408051808201909152600b815260a960020a6a22ba3432b9102a37b5b2b702602082015281565b600160a060020a03338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60025481565b600160a060020a03831660009081526020819052604081205461043790836106ac565b600160a060020a03808616600090815260208181526040808320949094556001815283822033909316825291909152205461047290836106ac565b600160a060020a038086166000908152600160209081526040808320338516845282528083209490945591861681529081905220546104b19083610692565b600160a060020a038085166000818152602081815260409182902094909455805186815290519193928816926000805160206106c483398151915292918290030190a35060015b9392505050565b600160a060020a03331660009081526020819052604090205461052290826106ac565b600160a060020a03331660009081526020819052604090205560025461054890826106ac565b600255604051600160a060020a0333169082156108fc029083906000818181858888f19350505050151561057c5760006000fd5b5b50565b601281565b600160a060020a0381166000908152602081905260409020545b919050565b604080518082019091526004815260e360020a630ae8aa8902602082015281565b600160a060020a0333166000908152602081905260408120546105e890836106ac565b600160a060020a0333811660009081526020819052604080822093909355908516815220546106179083610692565b600160a060020a03808516600081815260208181526040918290209490945580518681529051919333909316926000805160206106c483398151915292918290030190a35060015b92915050565b600160a060020a038083166000908152600160209081526040808320938516835292905220545b92915050565b6000828201838110156106a157fe5b8091505b5092915050565b6000828211156106b857fe5b508082035b929150505600ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a72305820b0be668913b36ff13a97f9ad56d8eb2e9c169cc9b32bfde9e3b92cec1036f1080029", + "unlinked_binary": "0x6060604052341561000c57fe5b5b6107598061001c6000396000f300606060405236156100935763ffffffff60e060020a60003504166306fdde0381146100a4578063095ea7b31461013457806318160ddd1461016757806323b872dd146101895780632e1a7d4d146101c2578063313ce567146101d757806370a08231146101fd57806395d89b411461022b578063a9059cbb146102bb578063d0e30db0146102ee578063dd62ed3e146102f8575b6100a25b61009f61032c565b5b565b005b34156100ac57fe5b6100b461037b565b6040805160208082528351818301528351919283929083019185019080838382156100fa575b8051825260208311156100fa57601f1990920191602091820191016100da565b505050905090810190601f1680156101265780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561013c57fe5b610153600160a060020a03600435166024356103a3565b604080519115158252519081900360200190f35b341561016f57fe5b61017761040e565b60408051918252519081900360200190f35b341561019157fe5b610153600160a060020a0360043581169060243516604435610414565b604080519115158252519081900360200190f35b34156101ca57fe5b6100a2600435610537565b005b34156101df57fe5b6101e76105b8565b6040805160ff9092168252519081900360200190f35b341561020557fe5b610177600160a060020a03600435166105bd565b60408051918252519081900360200190f35b341561023357fe5b6100b46105dc565b6040805160208082528351818301528351919283929083019185019080838382156100fa575b8051825260208311156100fa57601f1990920191602091820191016100da565b505050905090810190601f1680156101265780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156102c357fe5b610153600160a060020a03600435166024356105fd565b604080519115158252519081900360200190f35b6100a261032c565b005b341561030057fe5b610177600160a060020a03600435811690602435166106af565b60408051918252519081900360200190f35b600160a060020a03331660009081526020819052604090205461034f90346106dc565b600160a060020a03331660009081526020819052604090205560025461037590346106dc565b6002555b565b60408051808201909152600b815260a960020a6a22ba3432b9102a37b5b2b702602082015281565b600160a060020a03338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60025481565b600160a060020a03808416600081815260016020908152604080832033909516835293815283822054928252819052918220548390108015906104575750828110155b801561047d5750600160a060020a03841660009081526020819052604090205483810110155b1561052957600160a060020a03808516600090815260208190526040808220805487019055918716815220805484900390556000198110156104e757600160a060020a03808616600090815260016020908152604080832033909416835292905220805484900390555b83600160a060020a031685600160a060020a031660008051602061070e833981519152856040518082815260200191505060405180910390a36001915061052e565b600091505b5b509392505050565b600160a060020a03331660009081526020819052604090205461055a90826106f6565b600160a060020a03331660009081526020819052604090205560025461058090826106f6565b600255604051600160a060020a0333169082156108fc029083906000818181858888f1935050505015156105b45760006000fd5b5b50565b601281565b600160a060020a0381166000908152602081905260409020545b919050565b604080518082019091526004815260e360020a630ae8aa8902602082015281565b600160a060020a0333166000908152602081905260408120548290108015906106405750600160a060020a03831660009081526020819052604090205482810110155b156106a057600160a060020a03338116600081815260208181526040808320805488900390559387168083529184902080548701905583518681529351919360008051602061070e833981519152929081900390910190a3506001610408565b506000610408565b5b92915050565b600160a060020a038083166000908152600160209081526040808320938516835292905220545b92915050565b6000828201838110156106eb57fe5b8091505b5092915050565b60008282111561070257fe5b508082035b929150505600ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a7230582036b62e75991ca24307fbb7333dc79a1493b9acb6b3e146e3c707708262cfbe430029", "networks": { - "50": { + "1": { "links": {}, "events": { "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef": { @@ -283,8 +283,8 @@ "type": "event" } }, - "updated_at": 1502391794392, - "address": "0x6eead871b92e216b0368f596e751a25841f65bec" + "updated_at": 1502488087000, + "address": "0x2956356cd2a2bf3202f771f50d3d14a367b48070" }, "42": { "links": {}, @@ -337,7 +337,7 @@ "updated_at": 1502391794392, "address": "0x05d090b51c40b020eab3bfcb6a2dff130df22e9c" }, - "1": { + "50": { "links": {}, "events": { "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef": { @@ -385,10 +385,10 @@ "type": "event" } }, - "updated_at": 1502488087000, - "address": "0x2956356cd2a2bf3202f771f50d3d14a367b48070" + "updated_at": 1513088404209, + "address": "0x48bacb9266a570d521063ef5dd96e61686dbe788" } }, "schema_version": "0.0.5", - "updated_at": 1502391794392 -} + "updated_at": 1513088404209 +}
\ No newline at end of file diff --git a/packages/contracts/build/contracts/Exchange.json b/packages/contracts/build/contracts/Exchange.json index 245b8e86c..3e2308f8f 100644 --- a/packages/contracts/build/contracts/Exchange.json +++ b/packages/contracts/build/contracts/Exchange.json @@ -590,9 +590,9 @@ "type": "event" } ], - "unlinked_binary": "0x6060604052341561000f57600080fd5b604051604080612c4d833981016040528080519060200190919080519060200190919050505b816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b50505b612b84806100c96000396000f300606060405236156100fa576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806314df96ee146100ff578063288cdc911461014c5780632ac1262214610187578063363349be146101c2578063394c21e7146103bc5780633b30ba591461044b5780634f150787146104a0578063741bcc93146106b25780637e9abb50146107535780638163681e1461078e57806398024a8b14610812578063add1cbc51461085b578063b7b2c7d6146108b0578063baa0181d14610acd578063bc61394a14610c1f578063cfc4d0ec14610cdf578063f06bbf7514610d6d578063ffa1ad7414610d9e575b600080fd5b341561010a57600080fd5b6101326004808035906020019091908035906020019091908035906020019091905050610e2d565b604051808215151515815260200191505060405180910390f35b341561015757600080fd5b610171600480803560001916906020019091905050610e7c565b6040518082815260200191505060405180910390f35b341561019257600080fd5b6101ac600480803560001916906020019091905050610e94565b6040518082815260200191505060405180910390f35b34156101cd57600080fd5b6103a660048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b8282101561024857848483905060a002016005806020026040519081016040528092919082600560200280828437820191505050505081526020019060010190610203565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156102c457848483905060c00201600680602002604051908101604052809291908260066020028082843782019150505050508152602001906001019061027f565b5050505050919080359060200190919080351515906020019091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050610eac565b6040518082815260200191505060405180910390f35b34156103c757600080fd5b6104356004808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091908060c001906006806020026040519081016040528092919082600660200280828437820191505050505091908035906020019091905050611013565b6040518082815260200191505060405180910390f35b341561045657600080fd5b61045e6114fb565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156104ab57600080fd5b6106b060048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b8282101561052657848483905060a0020160058060200260405190810160405280929190826005602002808284378201915050505050815260200190600101906104e1565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156105a257848483905060c00201600680602002604051908101604052809291908260066020028082843782019150505050508152602001906001019061055d565b50505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050611520565b005b34156106bd57600080fd5b6107516004808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091908060c00190600680602002604051908101604052809291908260066020028082843782019150505050509190803590602001909190803560ff1690602001909190803560001916906020019091908035600019169060200190919050506115df565b005b341561075e57600080fd5b610778600480803560001916906020019091905050611605565b6040518082815260200191505060405180910390f35b341561079957600080fd5b6107f8600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080356000191690602001909190803560ff16906020019091908035600019169060200190919080356000191690602001909190505061164f565b604051808215151515815260200191505060405180910390f35b341561081d57600080fd5b6108456004808035906020019091908035906020019091908035906020019091905050611757565b6040518082815260200191505060405180910390f35b341561086657600080fd5b61086e611776565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156108bb57600080fd5b610acb60048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b8282101561093657848483905060a0020160058060200260405190810160405280929190826005602002808284378201915050505050815260200190600101906108f1565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156109b257848483905060c00201600680602002604051908101604052809291908260066020028082843782019150505050508152602001906001019061096d565b50505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091908035151590602001909190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190505061179c565b005b3415610ad857600080fd5b610c1d60048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610b5357848483905060a002016005806020026040519081016040528092919082600560200280828437820191505050505081526020019060010190610b0e565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610bcf57848483905060c002016006806020026040519081016040528092919082600660200280828437820191505050505081526020019060010190610b8a565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190505061185e565b005b3415610c2a57600080fd5b610cc96004808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091908060c001906006806020026040519081016040528092919082600660200280828437820191505050505091908035906020019091908035151590602001909190803560ff1690602001909190803560001916906020019091908035600019169060200190919050506118d3565b6040518082815260200191505060405180910390f35b3415610cea57600080fd5b610d4f6004808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091908060c001906006806020026040519081016040528092919082600660200280828437820191505050505091905050612073565b60405180826000191660001916815260200191505060405180910390f35b3415610d7857600080fd5b610d8061231f565b604051808261ffff1661ffff16815260200191505060405180910390f35b3415610da957600080fd5b610db1612325565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610df25780820151818401525b602081019050610dd6565b50505050905090810190601f168015610e1f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60008060008486850991506000821415610e4a5760009250610e73565b610e69610e5a83620f424061235e565b610e64888761235e565b612392565b90506103e8811192505b50509392505050565b60026020528060005260406000206000915090505481565b60036020528060005260406000206000915090505481565b6000806000809150600090505b895181101561100257896000815181101515610ed157fe5b906020019060200201516003600581101515610ee957fe5b602002015173ffffffffffffffffffffffffffffffffffffffff168a82815181101515610f1257fe5b906020019060200201516003600581101515610f2a57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16141515610f5157600080fd5b610fe582610fe08c84815181101515610f6657fe5b906020019060200201518c85815181101515610f7e57fe5b90602001906020020151610f928d886123ae565b8c8c88815181101515610fa157fe5b906020019060200201518c89815181101515610fb957fe5b906020019060200201518c8a815181101515610fd157fe5b906020019060200201516118d3565b6123c8565b915087821415610ff457611002565b5b8080600101915050610eb9565b8192505b5050979650505050505050565b600061101d612a8c565b6000806101606040519081016040528088600060058110151561103c57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200188600160058110151561106b57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200188600260058110151561109a57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018860036005811015156110c957fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018860046005811015156110f857fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200187600060068110151561112757fe5b6020020151815260200187600160068110151561114057fe5b6020020151815260200187600260068110151561115957fe5b6020020151815260200187600360068110151561117257fe5b6020020151815260200187600460068110151561118b57fe5b6020020151815260200161119f8989612073565b6000191681525092503373ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff161415156111e657600080fd5b60008360a001511180156111fe575060008360c00151115b801561120a5750600085115b151561121557600080fd5b8261012001514210151561127257826101400151600019166000600381111561123a57fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a3600093506114f1565b61128d8360c00151611288856101400151611605565b6123ae565b915061129985836123e7565b905060008114156112f35782610140015160001916600160038111156112bb57fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a3600093506114f1565b61131d600360008561014001516000191660001916815260200190815260200160002054826123c8565b60036000856101400151600019166000191681526020019081526020016000208190555082604001518360600151604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140192505050604051809103902060001916836080015173ffffffffffffffffffffffffffffffffffffffff16846000015173ffffffffffffffffffffffffffffffffffffffff167f67d66f160bc93d925d05dae1794c90d2d6d6688b29b84ff069398a9b0458713186604001518760600151611455878a60c001518b60a00151611757565b878a6101400151604051808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200184815260200183815260200182600019166000191681526020019550505050505060405180910390a48093505b5050509392505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008090505b86518110156115d5576115c7878281518110151561154057fe5b90602001906020020151878381518110151561155857fe5b90602001906020020151878481518110151561157057fe5b90602001906020020151878581518110151561158857fe5b9060200190602002015187868151811015156115a057fe5b9060200190602002015187878151811015156115b857fe5b906020019060200201516115df565b5b8080600101915050611526565b5b50505050505050565b836115f087878760008888886118d3565b1415156115fc57600080fd5b5b505050505050565b600061164760026000846000191660001916815260200190815260200160002054600360008560001916600019168152602001908152602001600020546123c8565b90505b919050565b600060018560405180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c0182600019166000191681526020019150506040518091039020858585604051600081526020016040526000604051602001526040518085600019166000191681526020018460ff1660ff16815260200183600019166000191681526020018260001916600019168152602001945050505050602060405160208103908084039060008661646e5a03f1151561171457600080fd5b50506020604051035173ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161490505b95945050505050565b600061176c611766858461235e565b84612392565b90505b9392505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008090505b87518110156118535761184488828151811015156117bc57fe5b9060200190602002015188838151811015156117d457fe5b9060200190602002015188848151811015156117ec57fe5b9060200190602002015188888681518110151561180557fe5b90602001906020020151888781518110151561181d57fe5b90602001906020020151888881518110151561183557fe5b906020019060200201516118d3565b505b80806001019150506117a2565b5b5050505050505050565b60008090505b83518110156118cc576118bd848281518110151561187e57fe5b90602001906020020151848381518110151561189657fe5b9060200190602002015184848151811015156118ae57fe5b90602001906020020151611013565b505b8080600101915050611864565b5b50505050565b60006118dd612a8c565b600080600080610160604051908101604052808e60006005811015156118ff57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e600160058110151561192e57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e600260058110151561195d57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e600360058110151561198c57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e60046005811015156119bb57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018d60006006811015156119ea57fe5b602002015181526020018d6001600681101515611a0357fe5b602002015181526020018d6002600681101515611a1c57fe5b602002015181526020018d6003600681101515611a3557fe5b602002015181526020018d6004600681101515611a4e57fe5b60200201518152602001611a628f8f612073565b600019168152509450600073ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff161480611ad957503373ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff16145b1515611ae457600080fd5b60008560a00151118015611afc575060008560c00151115b8015611b08575060008b115b1515611b1357600080fd5b611b2985600001518661014001518b8b8b61164f565b1515611b3457600080fd5b84610120015142101515611b91578461014001516000191660006003811115611b5957fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612063565b611bac8560c00151611ba7876101400151611605565b6123ae565b9350611bb88b856123e7565b95506000861415611c12578461014001516000191660016003811115611bda57fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612063565b611c25868660c001518760a00151610e2d565b15611c79578461014001516000191660026003811115611c4157fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612063565b89158015611c8e5750611c8c8587612401565b155b15611ce15784610140015160001916600380811115611ca957fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612063565b611cf4868660c001518760a00151611757565b9250611d20600260008761014001516000191660001916815260200190815260200160002054876123c8565b600260008761014001516000191660001916815260200190815260200160002081905550611d58856040015186600001513386612751565b1515611d6357600080fd5b611d77856060015133876000015189612751565b1515611d8257600080fd5b600073ffffffffffffffffffffffffffffffffffffffff16856080015173ffffffffffffffffffffffffffffffffffffffff16141515611e815760008560e001511115611e1f57611ddc868660c001518760e00151611757565b9150611e136000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168660000151876080015185612751565b1515611e1e57600080fd5b5b60008561010001511115611e8057611e41868660c00151876101000151611757565b9050611e746000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1633876080015184612751565b1515611e7f57600080fd5b5b5b84604001518560600151604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140192505050604051809103902060001916856080015173ffffffffffffffffffffffffffffffffffffffff16866000015173ffffffffffffffffffffffffffffffffffffffff167f0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb33389604001518a60600151898d8a8a8f6101400151604051808973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200186815260200185815260200184815260200183815260200182600019166000191681526020019850505050505050505060405180910390a48595505b5050505050979650505050505050565b60003083600060058110151561208557fe5b602002015184600160058110151561209957fe5b60200201518560026005811015156120ad57fe5b60200201518660036005811015156120c157fe5b60200201518760046005811015156120d557fe5b60200201518760006006811015156120e957fe5b60200201518860016006811015156120fd57fe5b602002015189600260068110151561211157fe5b60200201518a600360068110151561212557fe5b60200201518b600460068110151561213957fe5b60200201518c600560068110151561214d57fe5b6020020151604051808d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018781526020018681526020018581526020018481526020018381526020018281526020019c50505050505050505050505050604051809103902090505b92915050565b61138781565b6040805190810160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b6000808284029050600084148061237f575082848281151561237c57fe5b04145b151561238757fe5b8091505b5092915050565b60008082848115156123a057fe5b0490508091505b5092915050565b60008282111515156123bc57fe5b81830390505b92915050565b60008082840190508381101515156123dc57fe5b8091505b5092915050565b60008183106123f657816123f8565b825b90505b92915050565b60008060008060008060008060003397506124258a8c60c001518d60a00151611757565b9650600073ffffffffffffffffffffffffffffffffffffffff168b6080015173ffffffffffffffffffffffffffffffffffffffff161415156126d2576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168b6040015173ffffffffffffffffffffffffffffffffffffffff161495506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168b6060015173ffffffffffffffffffffffffffffffffffffffff161494506125208a8c60c001518d60e00151611757565b93506125368a8c60c001518d6101000151611757565b925085612543578361254e565b61254d87856123c8565b5b91508461255b5782612566565b6125658a846123c8565b5b9050816125986000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168d600001516128ae565b10806125d15750816125cf6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168d60000151612972565b105b806126055750806126036000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168a6128ae565b105b806126395750806126376000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168a612972565b105b156126475760009850612743565b851580156126805750866126638c604001518d600001516128ae565b108061267f57508661267d8c604001518d60000151612972565b105b5b1561268e5760009850612743565b841580156126bf5750896126a68c606001518a6128ae565b10806126be5750896126bc8c606001518a612972565b105b5b156126cd5760009850612743565b61273e565b866126e58c604001518d600001516128ae565b10806127015750866126ff8c604001518d60000151612972565b105b806127185750896127168c606001518a6128ae565b105b8061272f57508961272d8c606001518a612972565b105b1561273d5760009850612743565b5b600198505b505050505050505092915050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166315dacbea868686866000604051602001526040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001945050505050602060405180830381600087803b151561288857600080fd5b6102c65a03f1151561289957600080fd5b5050506040518051905090505b949350505050565b60008273ffffffffffffffffffffffffffffffffffffffff166370a0823161138761ffff16846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600088803b151561295157600080fd5b87f1151561295e57600080fd5b505050506040518051905090505b92915050565b60008273ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e61138761ffff1684600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600088803b1515612a6b57600080fd5b87f11515612a7857600080fd5b505050506040518051905090505b92915050565b61016060405190810160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000801916815250905600a165627a7a7230582051fd36c20467561cfff517e73443e85bfad01c2fe07b8431ba9903676db7bb140029", + "unlinked_binary": "0x6060604052341561000c57fe5b604051604080611ed68339810160405280516020909101515b60008054600160a060020a03808516600160a060020a03199283161790925560018054928416929091169190911790555b50505b611e6e806100686000396000f300606060405236156100e05763ffffffff60e060020a60003504166314df96ee81146100e2578063288cdc911461010f5780632ac1262214610134578063363349be14610159578063394c21e71461031b5780633b30ba591461038e5780634f150787146103ba578063741bcc931461059d5780637e9abb50146106135780638163681e1461063857806398024a8b14610677578063add1cbc5146106a2578063b7b2c7d6146106ce578063baa0181d146108b9578063bc61394a146109f4578063cfc4d0ec14610a81578063f06bbf7514610af2578063ffa1ad7414610b19575bfe5b34156100ea57fe5b6100fb600435602435604435610ba9565b604080519115158252519081900360200190f35b341561011757fe5b610122600435610bf7565b60408051918252519081900360200190f35b341561013c57fe5b610122600435610c09565b60408051918252519081900360200190f35b341561016157fe5b61012260048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156101d3576040805160a08181019092529080840287019060059083908390808284375050509183525050600190910190602001610197565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610246576040805160c0818101909252908084028701906006908390839080828437505050918352505060019091019060200161020a565b5050604080516020878301358901803582810280850184019095528084529799893599838101351515999198506060019650929450810192829185019084908082843750506040805187358901803560208181028481018201909552818452989a998901989297509082019550935083925085019084908082843750506040805187358901803560208181028481018201909552818452989a998901989297509082019550935083925085019084908082843750949650610c1b95505050505050565b60408051918252519081900360200190f35b341561032357fe5b6040805160a08181019092526101229160049160a4918390600590839083908082843750506040805160c08181019092529496958181019594509250600691508390839080828437509395505092359250610d44915050565b60408051918252519081900360200190f35b341561039657fe5b61039e611036565b60408051600160a060020a039092168252519081900360200190f35b34156103c257fe5b61059b60048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610434576040805160a081810190925290808402870190600590839083908082843750505091835250506001909101906020016103f8565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156104a7576040805160c0818101909252908084028701906006908390839080828437505050918352505060019091019060200161046b565b50505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843750506040805187358901803560208181028481018201909552818452989a998901989297509082019550935083925085019084908082843750506040805187358901803560208181028481018201909552818452989a998901989297509082019550935083925085019084908082843750506040805187358901803560208181028481018201909552818452989a99890198929750908201955093508392508501908490808284375094965061104595505050505050565b005b34156105a557fe5b6040805160a081810190925261059b9160049160a4918390600590839083908082843750506040805160c08181019092529496958181019594509250600691508390839080828437509395505083359360ff6020820135169350604081013592506060013590506110fc565b005b341561061b57fe5b610122600435611121565b60408051918252519081900360200190f35b341561064057fe5b6100fb600160a060020a036004351660243560ff6044351660643560843561114d565b604080519115158252519081900360200190f35b341561067f57fe5b610122600435602435604435611205565b60408051918252519081900360200190f35b34156106aa57fe5b61039e611224565b60408051600160a060020a039092168252519081900360200190f35b34156106d657fe5b61059b60048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610748576040805160a0818101909252908084028701906005908390839080828437505050918352505060019091019060200161070c565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156107bb576040805160c0818101909252908084028701906006908390839080828437505050918352505060019091019060200161077f565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284375050604080516020808901358a01803580830284810184018652818552999b8b3515159b909a950198509296508101945090925082919085019084908082843750506040805187358901803560208181028481018201909552818452989a998901989297509082019550935083925085019084908082843750506040805187358901803560208181028481018201909552818452989a99890198929750908201955093508392508501908490808284375094965061123395505050505050565b005b34156108c157fe5b61059b60048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610933576040805160a081810190925290808402870190600590839083908082843750505091835250506001909101906020016108f7565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156109a6576040805160c0818101909252908084028701906006908390839080828437505050918352505060019091019060200161096a565b505050505091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437509496506112ed95505050505050565b005b34156109fc57fe5b6040805160a08181019092526101229160049160a4918390600590839083908082843750506040805160c08181019092529496958181019594509250600691508390839080828437509395505083359360208101351515935060ff6040820135169250606081013591506080013561135a565b60408051918252519081900360200190f35b3415610a8957fe5b6040805160a08181019092526101229160049160a4918390600590839083908082843750506040805160c0818101909252949695818101959450925060069150839083908082843750939550611838945050505050565b60408051918252519081900360200190f35b3415610afa57fe5b610b0261192b565b6040805161ffff9092168252519081900360200190f35b3415610b2157fe5b610b29611931565b604080516020808252835181830152835191928392908301918501908083838215610b6f575b805182526020831115610b6f57601f199092019160209182019101610b4f565b505050905090810190601f168015610b9b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b600060006000848685099150811515610bc55760009250610bee565b610be4610bd583620f4240611953565b610bdf8887611953565b611982565b90506103e8811192505b50509392505050565b60026020526000908152604090205481565b60036020526000908152604090205481565b600080805b8951811015610d3357896000815181101515610c3857fe5b6020908102909101015160035b6020020151600160a060020a03168a82815181101515610c6157fe5b6020908102909101015160035b6020020151600160a060020a031614610c875760006000fd5b610d1b82610d168c84815181101515610c9c57fe5b906020019060200201518c85815181101515610cb457fe5b90602001906020020151610cc88d8861199f565b8c8c88815181101515610cd757fe5b906020019060200201518c89815181101515610cef57fe5b906020019060200201518c8a815181101515610d0757fe5b9060200190602002015161135a565b6119b6565b915087821415610d2a57610d33565b5b600101610c20565b8192505b5050979650505050505050565b6000610d4e611dc6565b60408051610160810190915260009081908088835b60209081029190910151600160a060020a03168252018860015b60209081029190910151600160a060020a03168252018860025b60209081029190910151600160a060020a03168252018860035b60209081029190910151600160a060020a03168252018860045b60209081029190910151600160a060020a03168252018760005b602090810291909101518252018760015b602090810291909101518252018760025b602090810291909101518252018760035b602090810291909101518252018760045b60200201518152602001610e3d8989611838565b9052805190935033600160a060020a03908116911614610e5d5760006000fd5b60008360a00151118015610e75575060008360c00151115b8015610e815750600085115b1515610e8d5760006000fd5b6101208301514210610ec95761014083015160005b60405160ff9190911690600080516020611e2383398151915290600090a36000935061102c565b610ee48360c00151610edf856101400151611121565b61199f565b9150610ef085836119d0565b9050801515610f2d576101408301516001610ea2565b60405160ff9190911690600080516020611e2383398151915290600090a36000935061102c565b610140830151600090815260036020526040902054610f4c90826119b6565b610140840151600090815260036020526040908190209190915580840180516060860180518451606060020a600160a060020a03948516810282529184169091026014820152935193849003602801909320608087015187519351945160c089015160a08a0151939692851695909416937f67d66f160bc93d925d05dae1794c90d2d6d6688b29b84ff069398a9b0458713193610fea918991611205565b6101408a015160408051600160a060020a0395861681529390941660208401528284019190915260608201889052608082015290519081900360a00190a48093505b5050509392505050565b600054600160a060020a031681565b60005b86518110156110f2576110e9878281518110151561106257fe5b90602001906020020151878381518110151561107a57fe5b90602001906020020151878481518110151561109257fe5b9060200190602002015187858151811015156110aa57fe5b9060200190602002015187868151811015156110c257fe5b9060200190602002015187878151811015156110da57fe5b906020019060200201516110fc565b5b600101611048565b5b50505050505050565b8361110d878787600088888861135a565b146111185760006000fd5b5b505050505050565b600081815260026020908152604080832054600390925282205461114591906119b6565b90505b919050565b604080517f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c8101869052815190819003603c018120600082815260208381018552928401819052835191825260ff8716828401528184018690526060820185905292516001926080808401939192601f1981019281900390910190868661646e5a03f115156111dc57fe5b505060206040510351600160a060020a031686600160a060020a03161490505b95945050505050565b600061121a6112148584611953565b84611982565b90505b9392505050565b600154600160a060020a031681565b60005b87518110156112e2576112d8888281518110151561125057fe5b90602001906020020151888381518110151561126857fe5b90602001906020020151888481518110151561128057fe5b9060200190602002015188888681518110151561129957fe5b9060200190602002015188878151811015156112b157fe5b906020019060200201518888815181101515610d0757fe5b9060200190602002015161135a565b505b600101611236565b5b5050505050505050565b60005b835181101561135357611349848281518110151561130a57fe5b90602001906020020151848381518110151561132257fe5b90602001906020020151848481518110151561133a57fe5b90602001906020020151610d44565b505b6001016112f0565b5b50505050565b6000611364611dc6565b6000600060006000610160604051908101604052808e600060058110151561138857fe5b60209081029190910151600160a060020a03168252018e60015b60209081029190910151600160a060020a03168252018e60025b60209081029190910151600160a060020a03168252018e60035b60209081029190910151600160a060020a03168252018e60045b60209081029190910151600160a060020a03168252018d60005b602090810291909101518252018d60015b602090810291909101518252018d60025b602090810291909101518252018d60035b602090810291909101518252018d60045b602002015181526020016114628f8f611838565b90526020810151909550600160a060020a03161580611496575033600160a060020a03168560200151600160a060020a0316145b15156114a25760006000fd5b60008560a001511180156114ba575060008560c00151115b80156114c6575060008b115b15156114d25760006000fd5b6114e885600001518661014001518b8b8b61114d565b15156114f45760006000fd5b61012085015142106115305761014085015160005b60405160ff9190911690600080516020611e2383398151915290600090a360009550611828565b61154b8560c00151610edf876101400151611121565b61199f565b93506115578b856119d0565b9550851515611594576101408501516001611509565b60405160ff9190911690600080516020611e2383398151915290600090a360009550611828565b6115a7868660c001518760a00151610ba9565b156115e0576101408501516002611509565b60405160ff9190911690600080516020611e2383398151915290600090a360009550611828565b891580156115f557506115f385876119ea565b155b1561162e576101408501516003611509565b60405160ff9190911690600080516020611e2383398151915290600090a360009550611828565b611641868660c001518760a00151611205565b61014086015160009081526002602052604090205490935061166390876119b6565b6101408601516000908152600260205260409081902091909155850151855161168e91903386611c46565b151561169a5760006000fd5b6116ae856060015133876000015189611c46565b15156116ba5760006000fd5b6080850151600160a060020a03161561176e5760008560e00151111561171c576116ed868660c001518760e00151611205565b6000548651608088015192945061171092600160a060020a039092169185611c46565b151561171c5760006000fd5b5b6000856101000151111561176e5761173f868660c00151876101000151611205565b600054608087015191925061176291600160a060020a0390911690339084611c46565b151561176e5760006000fd5b5b5b60408086018051606080890180518551606060020a600160a060020a0395861681028252918516909102601482015285519081900360280181206080808d01518d51975194516101408f0151338916865295881660208601528716848a01529483018b905282018d905260a0820189905260c0820188905260e08201929092529451909491831693909216917f0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb3918190036101000190a45b5050505050979650505050505050565b60003083825b60200201518460015b60200201518560025b60200201518660035b60200201518760045b60200201518760005b60200201518860015b60200201518960025b60200201518a60035b60200201518b60045b60200201518c60055b602002015160408051606060020a600160a060020a039e8f16810282529c8e168d0260148201529a8d168c0260288c0152988c168b02603c8b0152968b168a0260508a01529490991690970260648701526078860191909152609885015260b884019490945260d883019490945260f8820192909252610118810192909252519081900361013801902090505b92915050565b61138781565b604080518082019091526005815260dc60020a640312e302e302602082015281565b600082820283158061196f575082848281151561196c57fe5b04145b151561197757fe5b8091505b5092915050565b60006000828481151561199157fe5b0490508091505b5092915050565b6000828211156119ab57fe5b508082035b92915050565b60008282018381101561197757fe5b8091505b5092915050565b60008183106119df57816119e1565b825b90505b92915050565b600060006000600060006000600060006000339750611a128a8c60c001518d60a00151611205565b60808c0151909750600160a060020a031615611bc75760005460408c015160608d015160c08e015160e08f0151600160a060020a0394851693851684149a50939091169091149650611a66918c9190611205565b9350611a7c8a8c60c001518d6101000151611205565b925085611a895783611a93565b611a9387856119b6565b5b915084611aa15782611aab565b611aab8a846119b6565b5b6000548c519192508391611ac991600160a060020a031690611cd5565b1080611aee57506000548b518391611aec91600160a060020a0390911690611d50565b105b80611b0e57506000548190611b0c90600160a060020a03168a611cd5565b105b80611b2e57506000548190611b2c90600160a060020a03168a611d50565b105b15611b3c5760009850611c38565b85158015611b74575086611b588c604001518d60000151611cd5565b1080611b74575086611b728c604001518d60000151611d50565b105b5b15611b835760009850611c38565b84158015611bb3575089611b9b8c606001518a611cd5565b1080611bb3575089611bb18c606001518a611d50565b105b5b15611bc25760009850611c38565b611c32565b86611bda8c604001518d60000151611cd5565b1080611bf6575086611bf48c604001518d60000151611d50565b105b80611c0d575089611c0b8c606001518a611cd5565b105b80611c24575089611c228c606001518a611d50565b105b15611c325760009850611c38565b5b600198505b505050505050505092915050565b6001546040805160006020918201819052825160e160020a630aed65f5028152600160a060020a03898116600483015288811660248301528781166044830152606482018790529351919493909316926315dacbea92608480830193919282900301818787803b1515611cb557fe5b6102c65a03f11515611cc357fe5b5050604051519150505b949350505050565b600082600160a060020a03166370a0823161138761ffff16846040518363ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600088803b1515611d3557fe5b87f11515611d3f57fe5b505060405151925050505b92915050565b6001546040805160e160020a636eb1769f028152600160a060020a0384811660048301529283166024820152905160009285169163dd62ed3e916113879160448082019260209290919082900301818888803b1515611d3557fe5b87f11515611d3f57fe5b505060405151925050505b92915050565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915290560036d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e90a165627a7a723058204d97d325c74ccfe9265611080c9dadbe995124be2fa6e0eb6384a4474bc271600029", "networks": { - "50": { + "1": { "links": {}, "events": { "0x0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb3": { @@ -722,8 +722,8 @@ "type": "event" } }, - "updated_at": 1502391794390, - "address": "0x38024cc964e6f2745672c86ecf45f5965efe6310" + "updated_at": 1502480340000, + "address": "0x12459C951127e0c374FF9105DdA097662A027093" }, "42": { "links": {}, @@ -858,7 +858,7 @@ "updated_at": 1502391794390, "address": "0x90fe2af704b34e0224bf2299c838e04d4dcf1364" }, - "1": { + "50": { "links": {}, "events": { "0x0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb3": { @@ -988,10 +988,10 @@ "type": "event" } }, - "updated_at": 1502480340000, - "address": "0x12459C951127e0c374FF9105DdA097662A027093" + "updated_at": 1513088404206, + "address": "0xb69e673309512a9d726f87304c6984054f87a93b" } }, "schema_version": "0.0.5", - "updated_at": 1502391794390 -} + "updated_at": 1513088404206 +}
\ No newline at end of file diff --git a/packages/contracts/build/contracts/MaliciousToken.json b/packages/contracts/build/contracts/MaliciousToken.json index 61c48f26a..fc8c8faeb 100644 --- a/packages/contracts/build/contracts/MaliciousToken.json +++ b/packages/contracts/build/contracts/MaliciousToken.json @@ -169,7 +169,7 @@ "type": "event" } ], - "unlinked_binary": "0x60606040526003805460ff19166001179055341561001957fe5b5b610467806100296000396000f3006060604052361561005c5763ffffffff60e060020a600035041663095ea7b3811461005e57806318160ddd1461009157806323b872dd146100b357806370a08231146100ec578063a9059cbb1461011a578063dd62ed3e1461014d575bfe5b341561006657fe5b61007d600160a060020a0360043516602435610181565b604080519115158252519081900360200190f35b341561009957fe5b6100a16101ec565b60408051918252519081900360200190f35b34156100bb57fe5b61007d600160a060020a03600435811690602435166044356101f2565b604080519115158252519081900360200190f35b34156100f457fe5b6100a1600160a060020a03600435166102ee565b60408051918252519081900360200190f35b341561012257fe5b61007d600160a060020a0360043516602435610318565b604080519115158252519081900360200190f35b341561015557fe5b6100a1600160a060020a03600435811690602435166103ca565b60408051918252519081900360200190f35b600160a060020a03338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60025481565b600160a060020a0383166000908152602081905260408120548290108015906102425750600160a060020a0380851660009081526001602090815260408083203390941683529290522054829010155b80156102685750600160a060020a03831660009081526020819052604090205482810110155b156102e257600160a060020a03808416600081815260208181526040808320805488019055888516808452818420805489900390556001835281842033909616845294825291829020805487900390558151868152915192939260008051602061041c8339815191529281900390910190a35060016102e6565b5060005b5b9392505050565b60006102f8610402565b50600160a060020a0381166000908152602081905260409020545b919050565b600160a060020a03331660009081526020819052604081205482901080159061035b5750600160a060020a03831660009081526020819052604090205482810110155b156103bb57600160a060020a03338116600081815260208181526040808320805488900390559387168083529184902080548701905583518681529351919360008051602061041c833981519152929081900390910190a35060016101e6565b5060006101e6565b5b92915050565b60006103d4610402565b50600160a060020a038083166000908152600160209081526040808320938516835292905220545b92915050565b6003805460ff8082166001011660ff199091161790555b5600ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a723058201238dbb2f96252f5d35040796309238210d3a5d9ac3261d0effff444e8f0cd0c0029", + "unlinked_binary": "0x60606040526003805460ff19166001179055341561001957fe5b5b610467806100296000396000f3006060604052361561005c5763ffffffff60e060020a600035041663095ea7b3811461005e57806318160ddd1461009157806323b872dd146100b357806370a08231146100ec578063a9059cbb1461011a578063dd62ed3e1461014d575bfe5b341561006657fe5b61007d600160a060020a0360043516602435610181565b604080519115158252519081900360200190f35b341561009957fe5b6100a16101ec565b60408051918252519081900360200190f35b34156100bb57fe5b61007d600160a060020a03600435811690602435166044356101f2565b604080519115158252519081900360200190f35b34156100f457fe5b6100a1600160a060020a03600435166102ee565b60408051918252519081900360200190f35b341561012257fe5b61007d600160a060020a0360043516602435610318565b604080519115158252519081900360200190f35b341561015557fe5b6100a1600160a060020a03600435811690602435166103ca565b60408051918252519081900360200190f35b600160a060020a03338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60025481565b600160a060020a0383166000908152602081905260408120548290108015906102425750600160a060020a0380851660009081526001602090815260408083203390941683529290522054829010155b80156102685750600160a060020a03831660009081526020819052604090205482810110155b156102e257600160a060020a03808416600081815260208181526040808320805488019055888516808452818420805489900390556001835281842033909616845294825291829020805487900390558151868152915192939260008051602061041c8339815191529281900390910190a35060016102e6565b5060005b5b9392505050565b60006102f8610402565b50600160a060020a0381166000908152602081905260409020545b919050565b600160a060020a03331660009081526020819052604081205482901080159061035b5750600160a060020a03831660009081526020819052604090205482810110155b156103bb57600160a060020a03338116600081815260208181526040808320805488900390559387168083529184902080548701905583518681529351919360008051602061041c833981519152929081900390910190a35060016101e6565b5060006101e6565b5b92915050565b60006103d4610402565b50600160a060020a038083166000908152600160209081526040808320938516835292905220545b92915050565b6003805460ff8082166001011660ff199091161790555b5600ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a7230582078edadabd342b34dc605a47ad9eab0ab5ad8513193a546e042b2ab9c6101d5250029", "networks": { "50": { "links": {}, @@ -219,9 +219,9 @@ "type": "event" } }, - "updated_at": 1502391794396 + "updated_at": 1513088404210 } }, "schema_version": "0.0.5", - "updated_at": 1502391794396 + "updated_at": 1513088404210 }
\ No newline at end of file diff --git a/packages/contracts/build/contracts/Migrations.json b/packages/contracts/build/contracts/Migrations.json index e421c8130..a0643bb6c 100644 --- a/packages/contracts/build/contracts/Migrations.json +++ b/packages/contracts/build/contracts/Migrations.json @@ -64,9 +64,9 @@ "50": { "links": {}, "events": {}, - "updated_at": 1502391794384 + "updated_at": 1513088404203 } }, "schema_version": "0.0.5", - "updated_at": 1502391794384 + "updated_at": 1513088404203 }
\ No newline at end of file diff --git a/packages/contracts/build/contracts/Mintable.json b/packages/contracts/build/contracts/Mintable.json index 157d49a44..3d89194a0 100644 --- a/packages/contracts/build/contracts/Mintable.json +++ b/packages/contracts/build/contracts/Mintable.json @@ -182,8 +182,8 @@ "type": "event" } ], - "unlinked_binary": "0x6060604052341561000c57fe5b5b6104da8061001c6000396000f300606060405236156100675763ffffffff60e060020a600035041663095ea7b3811461006957806318160ddd1461009c57806323b872dd146100be57806370a08231146100f7578063a0712d6814610125578063a9059cbb1461013a578063dd62ed3e1461016d575bfe5b341561007157fe5b610088600160a060020a03600435166024356101a1565b604080519115158252519081900360200190f35b34156100a457fe5b6100ac61020c565b60408051918252519081900360200190f35b34156100c657fe5b610088600160a060020a0360043581169060243516604435610212565b604080519115158252519081900360200190f35b34156100ff57fe5b6100ac600160a060020a036004351661030e565b60408051918252519081900360200190f35b341561012d57fe5b61013860043561032d565b005b341561014257fe5b610088600160a060020a0360043516602435610395565b604080519115158252519081900360200190f35b341561017557fe5b6100ac600160a060020a0360043581169060243516610447565b60408051918252519081900360200190f35b600160a060020a03338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60025481565b600160a060020a0383166000908152602081905260408120548290108015906102625750600160a060020a0380851660009081526001602090815260408083203390941683529290522054829010155b80156102885750600160a060020a03831660009081526020819052604090205482810110155b1561030257600160a060020a03808416600081815260208181526040808320805488019055888516808452818420805489900390556001835281842033909616845294825291829020805487900390558151868152915192939260008051602061048f8339815191529281900390910190a3506001610306565b5060005b5b9392505050565b600160a060020a0381166000908152602081905260409020545b919050565b68056bc75e2d631000008111156103445760006000fd5b600160a060020a033316600090815260208190526040902054610368908290610474565b600160a060020a03331660009081526020819052604090205560025461038e9082610474565b6002555b50565b600160a060020a0333166000908152602081905260408120548290108015906103d85750600160a060020a03831660009081526020819052604090205482810110155b1561043857600160a060020a03338116600081815260208181526040808320805488900390559387168083529184902080548701905583518681529351919360008051602061048f833981519152929081900390910190a3506001610206565b506000610206565b5b92915050565b600160a060020a038083166000908152600160209081526040808320938516835292905220545b92915050565b60008282018381101561048357fe5b8091505b50929150505600ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a72305820fb9e3b0567bae493373766d7c9980e78be7513e22369cbce495956e5849c284d0029", + "unlinked_binary": "0x6060604052341561000c57fe5b5b6105018061001c6000396000f300606060405236156100675763ffffffff60e060020a600035041663095ea7b3811461006957806318160ddd1461009c57806323b872dd146100be57806370a08231146100f7578063a0712d6814610125578063a9059cbb1461013a578063dd62ed3e1461016d575bfe5b341561007157fe5b610088600160a060020a03600435166024356101a1565b604080519115158252519081900360200190f35b34156100a457fe5b6100ac61020c565b60408051918252519081900360200190f35b34156100c657fe5b610088600160a060020a0360043581169060243516604435610212565b604080519115158252519081900360200190f35b34156100ff57fe5b6100ac600160a060020a0360043516610335565b60408051918252519081900360200190f35b341561012d57fe5b610138600435610354565b005b341561014257fe5b610088600160a060020a03600435166024356103bc565b604080519115158252519081900360200190f35b341561017557fe5b6100ac600160a060020a036004358116906024351661046e565b60408051918252519081900360200190f35b600160a060020a03338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60025481565b600160a060020a03808416600081815260016020908152604080832033909516835293815283822054928252819052918220548390108015906102555750828110155b801561027b5750600160a060020a03841660009081526020819052604090205483810110155b1561032757600160a060020a03808516600090815260208190526040808220805487019055918716815220805484900390556000198110156102e557600160a060020a03808616600090815260016020908152604080832033909416835292905220805484900390555b83600160a060020a031685600160a060020a03166000805160206104b6833981519152856040518082815260200191505060405180910390a36001915061032c565b600091505b5b509392505050565b600160a060020a0381166000908152602081905260409020545b919050565b68056bc75e2d6310000081111561036b5760006000fd5b600160a060020a03331660009081526020819052604090205461038f90829061049b565b600160a060020a0333166000908152602081905260409020556002546103b5908261049b565b6002555b50565b600160a060020a0333166000908152602081905260408120548290108015906103ff5750600160a060020a03831660009081526020819052604090205482810110155b1561045f57600160a060020a0333811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191936000805160206104b6833981519152929081900390910190a3506001610206565b506000610206565b5b92915050565b600160a060020a038083166000908152600160209081526040808320938516835292905220545b92915050565b6000828201838110156104aa57fe5b8091505b50929150505600ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a72305820b1c955ed24ff28cfa482298867cac2a83e25903b0100a429152919223fdf653f0029", "networks": {}, "schema_version": "0.0.5", - "updated_at": 1502391449723 + "updated_at": 1513088402049 }
\ No newline at end of file diff --git a/packages/contracts/build/contracts/MultiSigWallet.json b/packages/contracts/build/contracts/MultiSigWallet.json index cb6be0217..931c8100d 100644 --- a/packages/contracts/build/contracts/MultiSigWallet.json +++ b/packages/contracts/build/contracts/MultiSigWallet.json @@ -510,8 +510,8 @@ "type": "event" } ], - "unlinked_binary": "0x606060405234156200000d57fe5b604051620022e9380380620022e9833981016040528080518201919060200180519060200190919050505b600082518260328211806200004c57508181115b80620000585750600081145b80620000645750600082145b15620000705760006000fd5b600092505b8451831015620001a9576002600086858151811015156200009257fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16806200011e575060008584815181101515620000fc57fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff16145b156200012a5760006000fd5b60016002600087868151811015156200013f57fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505b828060010193505062000075565b8460039080519060200190620001c1929190620001d6565b50836004819055505b5b5050505050620002ab565b82805482825590600052602060002090810192821562000252579160200282015b82811115620002515782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555091602001919060010190620001f7565b5b50905062000261919062000265565b5090565b620002a891905b80821115620002a457600081816101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055506001016200026c565b5090565b90565b61202e80620002bb6000396000f3006060604052361561011b576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063025e7c271461017c578063173825d9146101dc57806320ea8d86146102125780632f54bf6e146102325780633411c81c1461028057806354741525146102d75780637065cb4814610318578063784547a71461034e5780638b51d13f146103865780639ace38c2146103ba578063a0e67e2b146104b5578063a8abe69a1461052a578063b5dc40c3146105cc578063b77bf6001461064f578063ba51a6df14610675578063c01a8c8414610695578063c6427474146106b5578063d74f8edd1461074b578063dc8452cd14610771578063e20056e614610797578063ee22610b146107ec575b61017a5b6000341115610177573373ffffffffffffffffffffffffffffffffffffffff167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c346040518082815260200191505060405180910390a25b5b565b005b341561018457fe5b61019a600480803590602001909190505061080c565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101e457fe5b610210600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190505061084c565b005b341561021a57fe5b6102306004808035906020019091905050610af4565b005b341561023a57fe5b610266600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610ca5565b604051808215151515815260200191505060405180910390f35b341561028857fe5b6102bd600480803590602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610cc5565b604051808215151515815260200191505060405180910390f35b34156102df57fe5b610302600480803515159060200190919080351515906020019091905050610cf4565b6040518082815260200191505060405180910390f35b341561032057fe5b61034c600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610d8b565b005b341561035657fe5b61036c6004808035906020019091905050610f8e565b604051808215151515815260200191505060405180910390f35b341561038e57fe5b6103a46004808035906020019091905050611078565b6040518082815260200191505060405180910390f35b34156103c257fe5b6103d86004808035906020019091905050611148565b604051808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200184815260200180602001831515151581526020018281038252848181546001816001161561010002031660029004815260200191508054600181600116156101000203166002900480156104a35780601f10610478576101008083540402835291602001916104a3565b820191906000526020600020905b81548152906001019060200180831161048657829003601f168201915b50509550505050505060405180910390f35b34156104bd57fe5b6104c56111a4565b6040518080602001828103825283818151815260200191508051906020019060200280838360008314610517575b805182526020831115610517576020820191506020810190506020830392506104f3565b5050509050019250505060405180910390f35b341561053257fe5b610567600480803590602001909190803590602001909190803515159060200190919080351515906020019091905050611239565b60405180806020018281038252838181518152602001915080519060200190602002808383600083146105b9575b8051825260208311156105b957602082019150602081019050602083039250610595565b5050509050019250505060405180910390f35b34156105d457fe5b6105ea600480803590602001909190505061139d565b604051808060200182810382528381815181526020019150805190602001906020028083836000831461063c575b80518252602083111561063c57602082019150602081019050602083039250610618565b5050509050019250505060405180910390f35b341561065757fe5b61065f6115cf565b6040518082815260200191505060405180910390f35b341561067d57fe5b61069360048080359060200190919050506115d5565b005b341561069d57fe5b6106b3600480803590602001909190505061168c565b005b34156106bd57fe5b610735600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091905050611871565b6040518082815260200191505060405180910390f35b341561075357fe5b61075b611891565b6040518082815260200191505060405180910390f35b341561077957fe5b610781611896565b6040518082815260200191505060405180910390f35b341561079f57fe5b6107ea600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190505061189c565b005b34156107f457fe5b61080a6004808035906020019091905050611bc1565b005b60038181548110151561081b57fe5b906000526020600020900160005b915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60003073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156108895760006000fd5b81600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615156108e35760006000fd5b6000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600091505b600160038054905003821015610a6f578273ffffffffffffffffffffffffffffffffffffffff1660038381548110151561097657fe5b906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610a615760036001600380549050038154811015156109d657fe5b906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600383815481101515610a1257fe5b906000526020600020900160005b6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610a6f565b5b8180600101925050610940565b6001600381818054905003915081610a879190611edd565b506003805490506004541115610aa657610aa56003805490506115d5565b5b8273ffffffffffffffffffffffffffffffffffffffff167f8001553a916ef2f495d26a907cc54d96ed840d7bda71e73194bf5a9df7a76b9060405180905060405180910390a25b5b505b5050565b33600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161515610b4e5760006000fd5b81336001600083815260200190815260200160002060008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161515610bba5760006000fd5b836000600082815260200190815260200160002060030160009054906101000a900460ff1615610bea5760006000fd5b60006001600087815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550843373ffffffffffffffffffffffffffffffffffffffff167ff6a317157440607f36269043eb55f1287a5a19ba2216afeab88cd46cbcfb88e960405180905060405180910390a35b5b505b50505b5050565b60026020528060005260406000206000915054906101000a900460ff1681565b60016020528160005260406000206020528060005260406000206000915091509054906101000a900460ff1681565b60006000600090505b600554811015610d8357838015610d3557506000600082815260200190815260200160002060030160009054906101000a900460ff16155b80610d695750828015610d6857506000600082815260200190815260200160002060030160009054906101000a900460ff165b5b15610d75576001820191505b5b8080600101915050610cfd565b5b5092915050565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610dc65760006000fd5b80600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615610e1f5760006000fd5b8160008173ffffffffffffffffffffffffffffffffffffffff161415610e455760006000fd5b6001600380549050016004546032821180610e5f57508181115b80610e6a5750600081145b80610e755750600082145b15610e805760006000fd5b6001600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555060038054806001018281610eec9190611f09565b916000526020600020900160005b87909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550508473ffffffffffffffffffffffffffffffffffffffff167ff39e6e1eb0edcf53c221607b54b00cd28f3196fed0a24994dc308b8f611b682d60405180905060405180910390a25b5b50505b505b505b50565b60006000600060009150600090505b60038054905081101561107057600160008581526020019081526020016000206000600383815481101515610fce57fe5b906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161561104f576001820191505b6004548214156110625760019250611071565b5b8080600101915050610f9d565b5b5050919050565b60006000600090505b600380549050811015611141576001600084815260200190815260200160002060006003838154811015156110b257fe5b906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615611133576001820191505b5b8080600101915050611081565b5b50919050565b60006020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169080600101549080600201908060030160009054906101000a900460ff16905084565b6111ac611f35565b600380548060200260200160405190810160405280929190818152602001828054801561122e57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116111e4575b505050505090505b90565b611241611f49565b611249611f49565b6000600060055460405180591061125d5750595b908082528060200260200182016040525b50925060009150600090505b60055481101561131d578580156112b257506000600082815260200190815260200160002060030160009054906101000a900460ff16155b806112e657508480156112e557506000600082815260200190815260200160002060030160009054906101000a900460ff165b5b1561130f578083838151811015156112fa57fe5b90602001906020020181815250506001820191505b5b808060010191505061127a565b87870360405180591061132d5750595b908082528060200260200182016040525b5093508790505b8681101561139157828181518110151561135b57fe5b906020019060200201518489830381518110151561137557fe5b90602001906020020181815250505b8080600101915050611345565b5b505050949350505050565b6113a5611f35565b6113ad611f35565b600060006003805490506040518059106113c45750595b908082528060200260200182016040525b50925060009150600090505b6003805490508110156115275760016000868152602001908152602001600020600060038381548110151561141257fe5b906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16156115195760038181548110151561149b57fe5b906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683838151811015156114d657fe5b9060200190602002019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506001820191505b5b80806001019150506113e1565b816040518059106115355750595b908082528060200260200182016040525b509350600090505b818110156115c657828181518110151561156457fe5b90602001906020020151848281518110151561157c57fe5b9060200190602002019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250505b808060010191505061154e565b5b505050919050565b60055481565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156116105760006000fd5b60038054905081603282118061162557508181115b806116305750600081145b8061163b5750600082145b156116465760006000fd5b826004819055507fa3f1ee9126a074d9326c682f561767f710e927faa811f7a99829d49dc421797a836040518082815260200191505060405180910390a15b5b50505b50565b33600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615156116e65760006000fd5b8160006000600083815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156117425760006000fd5b82336001600083815260200190815260200160002060008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16156117ad5760006000fd5b60016001600087815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550843373ffffffffffffffffffffffffffffffffffffffff167f4a504a94899432a9846e1aa406dceb1bcfd538bb839071d49d1e5e23f5be30ef60405180905060405180910390a361186685611bc1565b5b5b50505b505b5050565b600061187e848484611d86565b90506118898161168c565b5b9392505050565b603281565b60045481565b60003073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156118d95760006000fd5b82600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615156119335760006000fd5b82600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161561198c5760006000fd5b600092505b600380549050831015611a7a578473ffffffffffffffffffffffffffffffffffffffff166003848154811015156119c457fe5b906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415611a6c5783600384815481101515611a1d57fe5b906000526020600020900160005b6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550611a7a565b5b8280600101935050611991565b6000600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508473ffffffffffffffffffffffffffffffffffffffff167f8001553a916ef2f495d26a907cc54d96ed840d7bda71e73194bf5a9df7a76b9060405180905060405180910390a28373ffffffffffffffffffffffffffffffffffffffff167ff39e6e1eb0edcf53c221607b54b00cd28f3196fed0a24994dc308b8f611b682d60405180905060405180910390a25b5b505b505b505050565b6000816000600082815260200190815260200160002060030160009054906101000a900460ff1615611bf35760006000fd5b611bfc83610f8e565b15611d7f5760006000848152602001908152602001600020915060018260030160006101000a81548160ff0219169083151502179055508160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168260010154836002016040518082805460018160011615610100020316600290048015611cdc5780601f10611cb157610100808354040283529160200191611cdc565b820191906000526020600020905b815481529060010190602001808311611cbf57829003601f168201915b505091505060006040518083038185876185025a03f19250505015611d3057827f33e13ecb54c3076d8e8bb8c2881800a4d972b792045ffae98fdf46df365fed7560405180905060405180910390a2611d7e565b827f526441bb6c1aba3c9a4a6ca1d6545da9c2333c8c48343ef398eb858d72b7923660405180905060405180910390a260008260030160006101000a81548160ff0219169083151502179055505b5b5b5b505050565b60008360008173ffffffffffffffffffffffffffffffffffffffff161415611dae5760006000fd5b60055491506080604051908101604052808673ffffffffffffffffffffffffffffffffffffffff168152602001858152602001848152602001600015158152506000600084815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550602082015181600101556040820151816002019080519060200190611e6e929190611f5d565b5060608201518160030160006101000a81548160ff0219169083151502179055509050506001600560008282540192505081905550817fc0ba8fe4b176c1714197d43b9cc6bcf797a4a7461c5fe8d0ef6e184ae7601e5160405180905060405180910390a25b5b509392505050565b815481835581811511611f0457818360005260206000209182019101611f039190611fdd565b5b505050565b815481835581811511611f3057818360005260206000209182019101611f2f9190611fdd565b5b505050565b602060405190810160405280600081525090565b602060405190810160405280600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611f9e57805160ff1916838001178555611fcc565b82800160010185558215611fcc579182015b82811115611fcb578251825591602001919060010190611fb0565b5b509050611fd99190611fdd565b5090565b611fff91905b80821115611ffb576000816000905550600101611fe3565b5090565b905600a165627a7a7230582037376d0ddd0c0be43b8a9a66d16ad08c1e2fdbae90c81561ee56cd32dfb316730029", + "unlinked_binary": "0x606060405234156200000d57fe5b604051620018013803806200180183398101604052805160208201519101905b600082518260328211806200004157508181115b806200004b575080155b8062000055575081155b15620000615760006000fd5b600092505b845183101562000136576002600086858151811015156200008357fe5b6020908102909101810151600160a060020a031682528101919091526040016000205460ff1680620000d657508483815181101515620000bf57fe5b90602001906020020151600160a060020a03166000145b15620000e25760006000fd5b6001600260008786815181101515620000f757fe5b602090810291909101810151600160a060020a03168252810191909152604001600020805460ff19169115159190911790555b60019092019162000066565b84516200014b9060039060208801906200015e565b5060048490555b5b5050505050620001f7565b828054828255906000526020600020908101928215620001b6579160200282015b82811115620001b65782518254600160a060020a031916600160a060020a039091161782556020909201916001909101906200017f565b5b50620001c5929150620001c9565b5090565b620001f491905b80821115620001c5578054600160a060020a0319168155600101620001d0565b5090565b90565b6115fa80620002076000396000f300606060405236156101015763ffffffff60e060020a600035041663025e7c278114610153578063173825d91461018257806320ea8d86146101a05780632f54bf6e146101b55780633411c81c146101e557806354741525146102185780637065cb4814610244578063784547a7146102625780638b51d13f146102895780639ace38c2146102ae578063a0e67e2b1461036b578063a8abe69a146103d6578063b5dc40c314610451578063b77bf600146104bf578063ba51a6df146104e1578063c01a8c84146104f6578063c64274741461050b578063d74f8edd14610580578063dc8452cd146105a2578063e20056e6146105c4578063ee22610b146105e8575b6101515b600034111561014e57604080513481529051600160a060020a033316917fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c919081900360200190a25b5b565b005b341561015b57fe5b6101666004356105fd565b60408051600160a060020a039092168252519081900360200190f35b341561018a57fe5b610151600160a060020a036004351661062f565b005b34156101a857fe5b6101516004356107ce565b005b34156101bd57fe5b6101d1600160a060020a03600435166108ab565b604080519115158252519081900360200190f35b34156101ed57fe5b6101d1600435600160a060020a03602435166108c0565b604080519115158252519081900360200190f35b341561022057fe5b610232600435151560243515156108e0565b60408051918252519081900360200190f35b341561024c57fe5b610151600160a060020a036004351661094f565b005b341561026a57fe5b6101d1600435610a74565b604080519115158252519081900360200190f35b341561029157fe5b610232600435610b08565b60408051918252519081900360200190f35b34156102b657fe5b6102c1600435610b87565b60408051600160a060020a03861681526020810185905282151560608201526080918101828152845460026000196101006001841615020190911604928201839052909160a0830190859080156103595780601f1061032e57610100808354040283529160200191610359565b820191906000526020600020905b81548152906001019060200180831161033c57829003601f168201915b50509550505050505060405180910390f35b341561037357fe5b61037b610bbb565b60408051602080825283518183015283519192839290830191858101910280838382156103c3575b8051825260208311156103c357601f1990920191602091820191016103a3565b5050509050019250505060405180910390f35b34156103de57fe5b61037b60043560243560443515156064351515610c24565b60408051602080825283518183015283519192839290830191858101910280838382156103c3575b8051825260208311156103c357601f1990920191602091820191016103a3565b5050509050019250505060405180910390f35b341561045957fe5b61037b600435610d59565b60408051602080825283518183015283519192839290830191858101910280838382156103c3575b8051825260208311156103c357601f1990920191602091820191016103a3565b5050509050019250505060405180910390f35b34156104c757fe5b610232610ee1565b60408051918252519081900360200190f35b34156104e957fe5b610151600435610ee7565b005b34156104fe57fe5b610151600435610f77565b005b341561051357fe5b604080516020600460443581810135601f8101849004840285018401909552848452610232948235600160a060020a031694602480359560649492939190920191819084018382808284375094965061106595505050505050565b60408051918252519081900360200190f35b341561058857fe5b610232611085565b60408051918252519081900360200190f35b34156105aa57fe5b61023261108a565b60408051918252519081900360200190f35b34156105cc57fe5b610151600160a060020a0360043581169060243516611090565b005b34156105f057fe5b610151600435611228565b005b600380548290811061060b57fe5b906000526020600020900160005b915054906101000a9004600160a060020a031681565b600030600160a060020a031633600160a060020a03161415156106525760006000fd5b600160a060020a038216600090815260026020526040902054829060ff16151561067c5760006000fd5b600160a060020a0383166000908152600260205260408120805460ff1916905591505b600354600019018210156107775782600160a060020a03166003838154811015156106c657fe5b906000526020600020900160005b9054906101000a9004600160a060020a0316600160a060020a0316141561076b5760038054600019810190811061070757fe5b906000526020600020900160005b9054906101000a9004600160a060020a031660038381548110151561073657fe5b906000526020600020900160005b6101000a815481600160a060020a030219169083600160a060020a03160217905550610777565b5b60019091019061069f565b60038054600019019061078a9082611476565b5060035460045411156107a3576003546107a390610ee7565b5b604051600160a060020a038416906000805160206115af83398151915290600090a25b5b505b5050565b33600160a060020a03811660009081526002602052604090205460ff1615156107f75760006000fd5b600082815260016020908152604080832033600160a060020a038116855292529091205483919060ff16151561082d5760006000fd5b600084815260208190526040902060030154849060ff161561084f5760006000fd5b6000858152600160209081526040808320600160a060020a0333168085529252808320805460ff191690555187927ff6a317157440607f36269043eb55f1287a5a19ba2216afeab88cd46cbcfb88e991a35b5b505b50505b5050565b60026020526000908152604090205460ff1681565b600160209081526000928352604080842090915290825290205460ff1681565b6000805b6005548110156109475783801561090d575060008181526020819052604090206003015460ff16155b806109315750828015610931575060008181526020819052604090206003015460ff165b5b1561093e576001820191505b5b6001016108e4565b5b5092915050565b30600160a060020a031633600160a060020a03161415156109705760006000fd5b600160a060020a038116600090815260026020526040902054819060ff16156109995760006000fd5b81600160a060020a03811615156109b05760006000fd5b60038054905060010160045460328211806109ca57508181115b806109d3575080155b806109dc575081155b156109e75760006000fd5b600160a060020a0385166000908152600260205260409020805460ff191660019081179091556003805490918101610a1f8382611476565b916000526020600020900160005b8154600160a060020a03808a166101009390930a8381029102199091161790915560405190915060008051602061158f83398151915290600090a25b5b50505b505b505b50565b600080805b600354811015610b005760008481526001602052604081206003805491929184908110610aa257fe5b906000526020600020900160005b9054600160a060020a036101009290920a900416815260208101919091526040016000205460ff1615610ae4576001820191505b600454821415610af75760019250610b00565b5b600101610a79565b5b5050919050565b6000805b600354811015610b805760008381526001602052604081206003805491929184908110610b3557fe5b906000526020600020900160005b9054600160a060020a036101009290920a900416815260208101919091526040016000205460ff1615610b77576001820191505b5b600101610b0c565b5b50919050565b6000602081905290815260409020805460018201546003830154600160a060020a0390921692909160029091019060ff1684565b610bc36114ca565b6003805480602002602001604051908101604052809291908181526020018280548015610c1957602002820191906000526020600020905b8154600160a060020a03168152600190910190602001808311610bfb575b505050505090505b90565b610c2c6114ca565b610c346114ca565b60006000600554604051805910610c485750595b908082528060200260200182016040525b50925060009150600090505b600554811015610ce257858015610c8e575060008181526020819052604090206003015460ff16155b80610cb25750848015610cb2575060008181526020819052604090206003015460ff165b5b15610cd957808383815181101515610cc757fe5b60209081029091010152600191909101905b5b600101610c65565b878703604051805910610cf25750595b908082528060200260200182016040525b5093508790505b86811015610d4d578281815181101515610d2057fe5b9060200190602002015184898303815181101515610d3a57fe5b602090810290910101525b600101610d0a565b5b505050949350505050565b610d616114ca565b610d696114ca565b6003546040516000918291805910610d7e5750595b908082528060200260200182016040525b50925060009150600090505b600354811015610e635760008581526001602052604081206003805491929184908110610dc457fe5b906000526020600020900160005b9054600160a060020a036101009290920a900416815260208101919091526040016000205460ff1615610e5a576003805482908110610e0d57fe5b906000526020600020900160005b9054906101000a9004600160a060020a03168383815181101515610e3b57fe5b600160a060020a03909216602092830290910190910152600191909101905b5b600101610d9b565b81604051805910610e715750595b908082528060200260200182016040525b509350600090505b81811015610ed8578281815181101515610ea057fe5b906020019060200201518482815181101515610eb857fe5b600160a060020a039092166020928302909101909101525b600101610e8a565b5b505050919050565b60055481565b30600160a060020a031633600160a060020a0316141515610f085760006000fd5b600354816032821180610f1a57508181115b80610f23575080155b80610f2c575081155b15610f375760006000fd5b60048390556040805184815290517fa3f1ee9126a074d9326c682f561767f710e927faa811f7a99829d49dc421797a9181900360200190a15b5b50505b50565b33600160a060020a03811660009081526002602052604090205460ff161515610fa05760006000fd5b6000828152602081905260409020548290600160a060020a03161515610fc65760006000fd5b600083815260016020908152604080832033600160a060020a038116855292529091205484919060ff1615610ffb5760006000fd5b6000858152600160208181526040808420600160a060020a0333168086529252808420805460ff1916909317909255905187927f4a504a94899432a9846e1aa406dceb1bcfd538bb839071d49d1e5e23f5be30ef91a36108a185611228565b5b5b50505b505b5050565b6000611072848484611390565b905061107d81610f77565b5b9392505050565b603281565b60045481565b600030600160a060020a031633600160a060020a03161415156110b35760006000fd5b600160a060020a038316600090815260026020526040902054839060ff1615156110dd5760006000fd5b600160a060020a038316600090815260026020526040902054839060ff16156111065760006000fd5b600092505b6003548310156111ae5784600160a060020a031660038481548110151561112e57fe5b906000526020600020900160005b9054906101000a9004600160a060020a0316600160a060020a031614156111a2578360038481548110151561116d57fe5b906000526020600020900160005b6101000a815481600160a060020a030219169083600160a060020a031602179055506111ae565b5b60019092019161110b565b600160a060020a03808616600081815260026020526040808220805460ff1990811690915593881682528082208054909416600117909355915190916000805160206115af83398151915291a2604051600160a060020a0385169060008051602061158f83398151915290600090a25b5b505b505b505050565b600081815260208190526040812060030154829060ff161561124a5760006000fd5b61125383610a74565b156107c7576000838152602081905260409081902060038101805460ff19166001908117909155815481830154935160028085018054959850600160a060020a03909316959492939192839285926000199183161561010002919091019091160480156113015780601f106112d657610100808354040283529160200191611301565b820191906000526020600020905b8154815290600101906020018083116112e457829003601f168201915b505091505060006040518083038185876187965a03f192505050156113505760405183907f33e13ecb54c3076d8e8bb8c2881800a4d972b792045ffae98fdf46df365fed7590600090a26107c7565b60405183907f526441bb6c1aba3c9a4a6ca1d6545da9c2333c8c48343ef398eb858d72b7923690600090a260038201805460ff191690555b5b5b5b505050565b600083600160a060020a03811615156113a95760006000fd5b60055460408051608081018252600160a060020a03888116825260208083018981528385018981526000606086018190528781528084529590952084518154600160a060020a0319169416939093178355516001830155925180519496509193909261141c9260028501929101906114ee565b50606091909101516003909101805460ff191691151591909117905560058054600101905560405182907fc0ba8fe4b176c1714197d43b9cc6bcf797a4a7461c5fe8d0ef6e184ae7601e5190600090a25b5b509392505050565b8154818355818115116107c7576000838152602090206107c791810190830161156d565b5b505050565b8154818355818115116107c7576000838152602090206107c791810190830161156d565b5b505050565b60408051602081019091526000815290565b60408051602081019091526000815290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061152f57805160ff191683800117855561155c565b8280016001018555821561155c579182015b8281111561155c578251825591602001919060010190611541565b5b5061156992915061156d565b5090565b610c2191905b808211156115695760008155600101611573565b5090565b905600f39e6e1eb0edcf53c221607b54b00cd28f3196fed0a24994dc308b8f611b682d8001553a916ef2f495d26a907cc54d96ed840d7bda71e73194bf5a9df7a76b90a165627a7a723058202f72592fe4e3a02180fe200a1e87105cc2db68ed7d59c782cc0e156fd816af640029", "networks": {}, "schema_version": "0.0.5", - "updated_at": 1502391449722 + "updated_at": 1513088402049 }
\ No newline at end of file diff --git a/packages/contracts/build/contracts/MultiSigWalletWithTimeLock.json b/packages/contracts/build/contracts/MultiSigWalletWithTimeLock.json index 8bab88188..a44d63919 100644 --- a/packages/contracts/build/contracts/MultiSigWalletWithTimeLock.json +++ b/packages/contracts/build/contracts/MultiSigWalletWithTimeLock.json @@ -587,7 +587,7 @@ "type": "event" } ], - "unlinked_binary": "0x606060405234156200000d57fe5b6040516200250138038062002501833981016040528080518201919060200180519060200190919080519060200190919050505b82825b600082518260328211806200005857508181115b80620000645750600081145b80620000705750600082145b156200007c5760006000fd5b600092505b8451831015620001b5576002600086858151811015156200009e57fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16806200012a5750600085848151811015156200010857fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff16145b15620001365760006000fd5b60016002600087868151811015156200014b57fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505b828060010193505062000081565b8460039080519060200190620001cd929190620001ed565b50836004819055505b5b5050505050806006819055505b505050620002c2565b82805482825590600052602060002090810192821562000269579160200282015b82811115620002685782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550916020019190600101906200020e565b5b5090506200027891906200027c565b5090565b620002bf91905b80821115620002bb57600081816101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690555060010162000283565b5090565b90565b61222f80620002d26000396000f3006060604052361561013c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063025e7c271461019d578063173825d9146101fd57806320ea8d86146102335780632f54bf6e146102535780633411c81c146102a157806337bd78a0146102f8578063547415251461031e5780637065cb481461035f578063784547a7146103955780637ad28c51146103cd5780638b51d13f146103ed5780639ace38c214610421578063a0e67e2b1461051c578063a8abe69a14610591578063b5dc40c314610633578063b77bf600146106b6578063ba51a6df146106dc578063c01a8c84146106fc578063c64274741461071c578063d38f2d82146107b2578063d74f8edd146107e6578063dc8452cd1461080c578063e20056e614610832578063ee22610b14610887575b61019b5b6000341115610198573373ffffffffffffffffffffffffffffffffffffffff167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c346040518082815260200191505060405180910390a25b5b565b005b34156101a557fe5b6101bb60048080359060200190919050506108a7565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561020557fe5b610231600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506108e7565b005b341561023b57fe5b6102516004808035906020019091905050610b8f565b005b341561025b57fe5b610287600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610d59565b604051808215151515815260200191505060405180910390f35b34156102a957fe5b6102de600480803590602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610d79565b604051808215151515815260200191505060405180910390f35b341561030057fe5b610308610da8565b6040518082815260200191505060405180910390f35b341561032657fe5b610349600480803515159060200190919080351515906020019091905050610dae565b6040518082815260200191505060405180910390f35b341561036757fe5b610393600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610e45565b005b341561039d57fe5b6103b36004808035906020019091905050611048565b604051808215151515815260200191505060405180910390f35b34156103d557fe5b6103eb6004808035906020019091905050611132565b005b34156103f557fe5b61040b60048080359060200190919050506111b0565b6040518082815260200191505060405180910390f35b341561042957fe5b61043f6004808035906020019091905050611280565b604051808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001848152602001806020018315151515815260200182810382528481815460018160011615610100020316600290048152602001915080546001816001161561010002031660029004801561050a5780601f106104df5761010080835404028352916020019161050a565b820191906000526020600020905b8154815290600101906020018083116104ed57829003601f168201915b50509550505050505060405180910390f35b341561052457fe5b61052c6112dc565b604051808060200182810382528381815181526020019150805190602001906020028083836000831461057e575b80518252602083111561057e5760208201915060208101905060208303925061055a565b5050509050019250505060405180910390f35b341561059957fe5b6105ce600480803590602001909190803590602001909190803515159060200190919080351515906020019091905050611371565b6040518080602001828103825283818151815260200191508051906020019060200280838360008314610620575b805182526020831115610620576020820191506020810190506020830392506105fc565b5050509050019250505060405180910390f35b341561063b57fe5b61065160048080359060200190919050506114d5565b60405180806020018281038252838181518152602001915080519060200190602002808383600083146106a3575b8051825260208311156106a35760208201915060208101905060208303925061067f565b5050509050019250505060405180910390f35b34156106be57fe5b6106c6611707565b6040518082815260200191505060405180910390f35b34156106e457fe5b6106fa600480803590602001909190505061170d565b005b341561070457fe5b61071a60048080359060200190919050506117c4565b005b341561072457fe5b61079c600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919050506119d2565b6040518082815260200191505060405180910390f35b34156107ba57fe5b6107d060048080359060200190919050506119f2565b6040518082815260200191505060405180910390f35b34156107ee57fe5b6107f6611a0a565b6040518082815260200191505060405180910390f35b341561081457fe5b61081c611a0f565b6040518082815260200191505060405180910390f35b341561083a57fe5b610885600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611a15565b005b341561088f57fe5b6108a56004808035906020019091905050611d3a565b005b6003818154811015156108b657fe5b906000526020600020900160005b915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60003073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156109245760006000fd5b81600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16151561097e5760006000fd5b6000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600091505b600160038054905003821015610b0a578273ffffffffffffffffffffffffffffffffffffffff16600383815481101515610a1157fe5b906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610afc576003600160038054905003815481101515610a7157fe5b906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600383815481101515610aad57fe5b906000526020600020900160005b6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610b0a565b5b81806001019250506109db565b6001600381818054905003915081610b2291906120de565b506003805490506004541115610b4157610b4060038054905061170d565b5b8273ffffffffffffffffffffffffffffffffffffffff167f8001553a916ef2f495d26a907cc54d96ed840d7bda71e73194bf5a9df7a76b9060405180905060405180910390a25b5b505b5050565b33600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161515610be95760006000fd5b81336001600083815260200190815260200160002060008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161515610c555760006000fd5b836000600082815260200190815260200160002060030160009054906101000a900460ff1615610c855760006000fd5b84610c8f81611048565b151515610c9c5760006000fd5b60006001600088815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550853373ffffffffffffffffffffffffffffffffffffffff167ff6a317157440607f36269043eb55f1287a5a19ba2216afeab88cd46cbcfb88e960405180905060405180910390a35b5b505b505b50505b5050565b60026020528060005260406000206000915054906101000a900460ff1681565b60016020528160005260406000206020528060005260406000206000915091509054906101000a900460ff1681565b60065481565b60006000600090505b600554811015610e3d57838015610def57506000600082815260200190815260200160002060030160009054906101000a900460ff16155b80610e235750828015610e2257506000600082815260200190815260200160002060030160009054906101000a900460ff165b5b15610e2f576001820191505b5b8080600101915050610db7565b5b5092915050565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610e805760006000fd5b80600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615610ed95760006000fd5b8160008173ffffffffffffffffffffffffffffffffffffffff161415610eff5760006000fd5b6001600380549050016004546032821180610f1957508181115b80610f245750600081145b80610f2f5750600082145b15610f3a5760006000fd5b6001600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555060038054806001018281610fa6919061210a565b916000526020600020900160005b87909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550508473ffffffffffffffffffffffffffffffffffffffff167ff39e6e1eb0edcf53c221607b54b00cd28f3196fed0a24994dc308b8f611b682d60405180905060405180910390a25b5b50505b505b505b50565b60006000600060009150600090505b60038054905081101561112a5760016000858152602001908152602001600020600060038381548110151561108857fe5b906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615611109576001820191505b60045482141561111c576001925061112b565b5b8080600101915050611057565b5b5050919050565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561116d5760006000fd5b806006819055507fd1c9101a34feff75cccef14a28785a0279cb0b49c1f321f21f5f422e746b4377816040518082815260200191505060405180910390a15b5b50565b60006000600090505b600380549050811015611279576001600084815260200190815260200160002060006003838154811015156111ea57fe5b906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161561126b576001820191505b5b80806001019150506111b9565b5b50919050565b60006020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169080600101549080600201908060030160009054906101000a900460ff16905084565b6112e4612136565b600380548060200260200160405190810160405280929190818152602001828054801561136657602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001906001019080831161131c575b505050505090505b90565b61137961214a565b61138161214a565b600060006005546040518059106113955750595b908082528060200260200182016040525b50925060009150600090505b600554811015611455578580156113ea57506000600082815260200190815260200160002060030160009054906101000a900460ff16155b8061141e575084801561141d57506000600082815260200190815260200160002060030160009054906101000a900460ff165b5b156114475780838381518110151561143257fe5b90602001906020020181815250506001820191505b5b80806001019150506113b2565b8787036040518059106114655750595b908082528060200260200182016040525b5093508790505b868110156114c957828181518110151561149357fe5b90602001906020020151848983038151811015156114ad57fe5b90602001906020020181815250505b808060010191505061147d565b5b505050949350505050565b6114dd612136565b6114e5612136565b600060006003805490506040518059106114fc5750595b908082528060200260200182016040525b50925060009150600090505b60038054905081101561165f5760016000868152602001908152602001600020600060038381548110151561154a57fe5b906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615611651576003818154811015156115d357fe5b906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16838381518110151561160e57fe5b9060200190602002019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506001820191505b5b8080600101915050611519565b8160405180591061166d5750595b908082528060200260200182016040525b509350600090505b818110156116fe57828181518110151561169c57fe5b9060200190602002015184828151811015156116b457fe5b9060200190602002019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250505b8080600101915050611686565b5b505050919050565b60055481565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156117485760006000fd5b60038054905081603282118061175d57508181115b806117685750600081145b806117735750600082145b1561177e5760006000fd5b826004819055507fa3f1ee9126a074d9326c682f561767f710e927faa811f7a99829d49dc421797a836040518082815260200191505060405180910390a15b5b50505b50565b33600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16151561181e5760006000fd5b8160006000600083815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561187a5760006000fd5b82336001600083815260200190815260200160002060008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16156118e55760006000fd5b846118ef81611048565b1515156118fc5760006000fd5b60016001600088815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550853373ffffffffffffffffffffffffffffffffffffffff167f4a504a94899432a9846e1aa406dceb1bcfd538bb839071d49d1e5e23f5be30ef60405180905060405180910390a36119b586611048565b156119c5576119c48642611f32565b5b5b5b505b50505b505b5050565b60006119df848484611f87565b90506119ea816117c4565b5b9392505050565b60076020528060005260406000206000915090505481565b603281565b60045481565b60003073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515611a525760006000fd5b82600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161515611aac5760006000fd5b82600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615611b055760006000fd5b600092505b600380549050831015611bf3578473ffffffffffffffffffffffffffffffffffffffff16600384815481101515611b3d57fe5b906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415611be55783600384815481101515611b9657fe5b906000526020600020900160005b6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550611bf3565b5b8280600101935050611b0a565b6000600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508473ffffffffffffffffffffffffffffffffffffffff167f8001553a916ef2f495d26a907cc54d96ed840d7bda71e73194bf5a9df7a76b9060405180905060405180910390a28373ffffffffffffffffffffffffffffffffffffffff167ff39e6e1eb0edcf53c221607b54b00cd28f3196fed0a24994dc308b8f611b682d60405180905060405180910390a25b5b505b505b505050565b6000816000600082815260200190815260200160002060030160009054906101000a900460ff1615611d6c5760006000fd5b82611d7681611048565b1515611d825760006000fd5b836006546007600083815260200190815260200160002054014210151515611daa5760006000fd5b60006000868152602001908152602001600020935060018460030160006101000a81548160ff0219169083151502179055508360000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168460010154856002016040518082805460018160011615610100020316600290048015611e855780601f10611e5a57610100808354040283529160200191611e85565b820191906000526020600020905b815481529060010190602001808311611e6857829003601f168201915b505091505060006040518083038185876185025a03f19250505015611ed957847f33e13ecb54c3076d8e8bb8c2881800a4d972b792045ffae98fdf46df365fed7560405180905060405180910390a2611f27565b847f526441bb6c1aba3c9a4a6ca1d6545da9c2333c8c48343ef398eb858d72b7923660405180905060405180910390a260008460030160006101000a81548160ff0219169083151502179055505b5b5b505b505b505050565b806007600084815260200190815260200160002081905550817f0b237afe65f1514fd7ea3f923ea4fe792bdd07000a912b6cd1602a8e7f573c8d826040518082815260200191505060405180910390a25b5050565b60008360008173ffffffffffffffffffffffffffffffffffffffff161415611faf5760006000fd5b60055491506080604051908101604052808673ffffffffffffffffffffffffffffffffffffffff168152602001858152602001848152602001600015158152506000600084815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160010155604082015181600201908051906020019061206f92919061215e565b5060608201518160030160006101000a81548160ff0219169083151502179055509050506001600560008282540192505081905550817fc0ba8fe4b176c1714197d43b9cc6bcf797a4a7461c5fe8d0ef6e184ae7601e5160405180905060405180910390a25b5b509392505050565b8154818355818115116121055781836000526020600020918201910161210491906121de565b5b505050565b8154818355818115116121315781836000526020600020918201910161213091906121de565b5b505050565b602060405190810160405280600081525090565b602060405190810160405280600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061219f57805160ff19168380011785556121cd565b828001600101855582156121cd579182015b828111156121cc5782518255916020019190600101906121b1565b5b5090506121da91906121de565b5090565b61220091905b808211156121fc5760008160009055506001016121e4565b5090565b905600a165627a7a723058204556921b5aaeabf763e47d995d7dd454b524b39bf1564247a5711e05292a88c10029", + "unlinked_binary": "0x606060405234156200000d57fe5b604051620019bd380380620019bd83398101604090815281516020830151918301519201915b82825b600082518260328211806200004a57508181115b8062000054575080155b806200005e575081155b156200006a5760006000fd5b600092505b84518310156200013f576002600086858151811015156200008c57fe5b6020908102909101810151600160a060020a031682528101919091526040016000205460ff1680620000df57508483815181101515620000c857fe5b90602001906020020151600160a060020a03166000145b15620000eb5760006000fd5b60016002600087868151811015156200010057fe5b602090810291909101810151600160a060020a03168252810191909152604001600020805460ff19169115159190911790555b6001909201916200006f565b84516200015490600390602088019062000170565b5060048490555b5b505050600683905550505b50505062000209565b828054828255906000526020600020908101928215620001c8579160200282015b82811115620001c85782518254600160a060020a031916600160a060020a0390911617825560209092019160019091019062000191565b5b50620001d7929150620001db565b5090565b6200020691905b80821115620001d7578054600160a060020a0319168155600101620001e2565b5090565b90565b6117a480620002196000396000f300606060405236156101225763ffffffff60e060020a600035041663025e7c278114610174578063173825d9146101a357806320ea8d86146101c15780632f54bf6e146101d65780633411c81c1461020657806337bd78a014610239578063547415251461025b5780637065cb4814610287578063784547a7146102a55780637ad28c51146102cc5780638b51d13f146102e15780639ace38c214610306578063a0e67e2b146103c3578063a8abe69a1461042e578063b5dc40c3146104a9578063b77bf60014610517578063ba51a6df14610539578063c01a8c841461054e578063c642747414610563578063d38f2d82146105d8578063d74f8edd146105fd578063dc8452cd1461061f578063e20056e614610641578063ee22610b14610665575b6101725b600034111561016f57604080513481529051600160a060020a033316917fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c919081900360200190a25b5b565b005b341561017c57fe5b61018760043561067a565b60408051600160a060020a039092168252519081900360200190f35b34156101ab57fe5b610172600160a060020a03600435166106ac565b005b34156101c957fe5b61017260043561084b565b005b34156101de57fe5b6101f2600160a060020a036004351661093f565b604080519115158252519081900360200190f35b341561020e57fe5b6101f2600435600160a060020a0360243516610954565b604080519115158252519081900360200190f35b341561024157fe5b610249610974565b60408051918252519081900360200190f35b341561026357fe5b6102496004351515602435151561097a565b60408051918252519081900360200190f35b341561028f57fe5b610172600160a060020a03600435166109e9565b005b34156102ad57fe5b6101f2600435610b0e565b604080519115158252519081900360200190f35b34156102d457fe5b610172600435610ba2565b005b34156102e957fe5b610249600435610c00565b60408051918252519081900360200190f35b341561030e57fe5b610319600435610c7f565b60408051600160a060020a03861681526020810185905282151560608201526080918101828152845460026000196101006001841615020190911604928201839052909160a0830190859080156103b15780601f10610386576101008083540402835291602001916103b1565b820191906000526020600020905b81548152906001019060200180831161039457829003601f168201915b50509550505050505060405180910390f35b34156103cb57fe5b6103d3610cb3565b604080516020808252835181830152835191928392908301918581019102808383821561041b575b80518252602083111561041b57601f1990920191602091820191016103fb565b5050509050019250505060405180910390f35b341561043657fe5b6103d360043560243560443515156064351515610d1c565b604080516020808252835181830152835191928392908301918581019102808383821561041b575b80518252602083111561041b57601f1990920191602091820191016103fb565b5050509050019250505060405180910390f35b34156104b157fe5b6103d3600435610e51565b604080516020808252835181830152835191928392908301918581019102808383821561041b575b80518252602083111561041b57601f1990920191602091820191016103fb565b5050509050019250505060405180910390f35b341561051f57fe5b610249610fd9565b60408051918252519081900360200190f35b341561054157fe5b610172600435610fdf565b005b341561055657fe5b61017260043561106f565b005b341561056b57fe5b604080516020600460443581810135601f8101849004840285018401909552848452610249948235600160a060020a031694602480359560649492939190920191819084018382808284375094965061118495505050505050565b60408051918252519081900360200190f35b34156105e057fe5b6102496004356111a4565b60408051918252519081900360200190f35b341561060557fe5b6102496111b6565b60408051918252519081900360200190f35b341561062757fe5b6102496111bb565b60408051918252519081900360200190f35b341561064957fe5b610172600160a060020a03600435811690602435166111c1565b005b341561066d57fe5b610172600435611359565b005b600380548290811061068857fe5b906000526020600020900160005b915054906101000a9004600160a060020a031681565b600030600160a060020a031633600160a060020a03161415156106cf5760006000fd5b600160a060020a038216600090815260026020526040902054829060ff1615156106f95760006000fd5b600160a060020a0383166000908152600260205260408120805460ff1916905591505b600354600019018210156107f45782600160a060020a031660038381548110151561074357fe5b906000526020600020900160005b9054906101000a9004600160a060020a0316600160a060020a031614156107e85760038054600019810190811061078457fe5b906000526020600020900160005b9054906101000a9004600160a060020a03166003838154811015156107b357fe5b906000526020600020900160005b6101000a815481600160a060020a030219169083600160a060020a031602179055506107f4565b5b60019091019061071c565b6003805460001901906108079082611620565b5060035460045411156108205760035461082090610fdf565b5b604051600160a060020a0384169060008051602061175983398151915290600090a25b5b505b5050565b33600160a060020a03811660009081526002602052604090205460ff1615156108745760006000fd5b600082815260016020908152604080832033600160a060020a038116855292529091205483919060ff1615156108aa5760006000fd5b600084815260208190526040902060030154849060ff16156108cc5760006000fd5b846108d681610b0e565b156108e15760006000fd5b6000868152600160209081526040808320600160a060020a0333168085529252808320805460ff191690555188927ff6a317157440607f36269043eb55f1287a5a19ba2216afeab88cd46cbcfb88e991a35b5b505b505b50505b5050565b60026020526000908152604090205460ff1681565b600160209081526000928352604080842090915290825290205460ff1681565b60065481565b6000805b6005548110156109e1578380156109a7575060008181526020819052604090206003015460ff16155b806109cb57508280156109cb575060008181526020819052604090206003015460ff165b5b156109d8576001820191505b5b60010161097e565b5b5092915050565b30600160a060020a031633600160a060020a0316141515610a0a5760006000fd5b600160a060020a038116600090815260026020526040902054819060ff1615610a335760006000fd5b81600160a060020a0381161515610a4a5760006000fd5b6003805490506001016004546032821180610a6457508181115b80610a6d575080155b80610a76575081155b15610a815760006000fd5b600160a060020a0385166000908152600260205260409020805460ff191660019081179091556003805490918101610ab98382611620565b916000526020600020900160005b8154600160a060020a03808a166101009390930a8381029102199091161790915560405190915060008051602061173983398151915290600090a25b5b50505b505b505b50565b600080805b600354811015610b9a5760008481526001602052604081206003805491929184908110610b3c57fe5b906000526020600020900160005b9054600160a060020a036101009290920a900416815260208101919091526040016000205460ff1615610b7e576001820191505b600454821415610b915760019250610b9a565b5b600101610b13565b5b5050919050565b30600160a060020a031633600160a060020a0316141515610bc35760006000fd5b60068190556040805182815290517fd1c9101a34feff75cccef14a28785a0279cb0b49c1f321f21f5f422e746b43779181900360200190a15b5b50565b6000805b600354811015610c785760008381526001602052604081206003805491929184908110610c2d57fe5b906000526020600020900160005b9054600160a060020a036101009290920a900416815260208101919091526040016000205460ff1615610c6f576001820191505b5b600101610c04565b5b50919050565b6000602081905290815260409020805460018201546003830154600160a060020a0390921692909160029091019060ff1684565b610cbb611674565b6003805480602002602001604051908101604052809291908181526020018280548015610d1157602002820191906000526020600020905b8154600160a060020a03168152600190910190602001808311610cf3575b505050505090505b90565b610d24611674565b610d2c611674565b60006000600554604051805910610d405750595b908082528060200260200182016040525b50925060009150600090505b600554811015610dda57858015610d86575060008181526020819052604090206003015460ff16155b80610daa5750848015610daa575060008181526020819052604090206003015460ff165b5b15610dd157808383815181101515610dbf57fe5b60209081029091010152600191909101905b5b600101610d5d565b878703604051805910610dea5750595b908082528060200260200182016040525b5093508790505b86811015610e45578281815181101515610e1857fe5b9060200190602002015184898303815181101515610e3257fe5b602090810290910101525b600101610e02565b5b505050949350505050565b610e59611674565b610e61611674565b6003546040516000918291805910610e765750595b908082528060200260200182016040525b50925060009150600090505b600354811015610f5b5760008581526001602052604081206003805491929184908110610ebc57fe5b906000526020600020900160005b9054600160a060020a036101009290920a900416815260208101919091526040016000205460ff1615610f52576003805482908110610f0557fe5b906000526020600020900160005b9054906101000a9004600160a060020a03168383815181101515610f3357fe5b600160a060020a03909216602092830290910190910152600191909101905b5b600101610e93565b81604051805910610f695750595b908082528060200260200182016040525b509350600090505b81811015610fd0578281815181101515610f9857fe5b906020019060200201518482815181101515610fb057fe5b600160a060020a039092166020928302909101909101525b600101610f82565b5b505050919050565b60055481565b30600160a060020a031633600160a060020a03161415156110005760006000fd5b60035481603282118061101257508181115b8061101b575080155b80611024575081155b1561102f5760006000fd5b60048390556040805184815290517fa3f1ee9126a074d9326c682f561767f710e927faa811f7a99829d49dc421797a9181900360200190a15b5b50505b50565b33600160a060020a03811660009081526002602052604090205460ff1615156110985760006000fd5b6000828152602081905260409020548290600160a060020a031615156110be5760006000fd5b600083815260016020908152604080832033600160a060020a038116855292529091205484919060ff16156110f35760006000fd5b846110fd81610b0e565b156111085760006000fd5b6000868152600160208181526040808420600160a060020a0333168086529252808420805460ff1916909317909255905188927f4a504a94899432a9846e1aa406dceb1bcfd538bb839071d49d1e5e23f5be30ef91a361116786610b0e565b156109335761093386426114ee565b5b5b5b505b50505b505b5050565b600061119184848461153a565b905061119c8161106f565b5b9392505050565b60076020526000908152604090205481565b603281565b60045481565b600030600160a060020a031633600160a060020a03161415156111e45760006000fd5b600160a060020a038316600090815260026020526040902054839060ff16151561120e5760006000fd5b600160a060020a038316600090815260026020526040902054839060ff16156112375760006000fd5b600092505b6003548310156112df5784600160a060020a031660038481548110151561125f57fe5b906000526020600020900160005b9054906101000a9004600160a060020a0316600160a060020a031614156112d3578360038481548110151561129e57fe5b906000526020600020900160005b6101000a815481600160a060020a030219169083600160a060020a031602179055506112df565b5b60019092019161123c565b600160a060020a03808616600081815260026020526040808220805460ff19908116909155938816825280822080549094166001179093559151909160008051602061175983398151915291a2604051600160a060020a0385169060008051602061173983398151915290600090a25b5b505b505b505050565b600081815260208190526040812060030154829060ff161561137b5760006000fd5b8261138581610b0e565b15156113915760006000fd5b6006546000858152600760205260409020548591014210156113b35760006000fd5b6000858152602081905260409081902060038101805460ff19166001908117909155815481830154935160028085018054959a50600160a060020a039093169594929391928392859260001991831615610100029190910190911604801561145c5780601f106114315761010080835404028352916020019161145c565b820191906000526020600020905b81548152906001019060200180831161143f57829003601f168201915b505091505060006040518083038185876187965a03f192505050156114ab5760405185907f33e13ecb54c3076d8e8bb8c2881800a4d972b792045ffae98fdf46df365fed7590600090a2610936565b60405185907f526441bb6c1aba3c9a4a6ca1d6545da9c2333c8c48343ef398eb858d72b7923690600090a260038401805460ff191690555b5b5b505b505b505050565b6000828152600760209081526040918290208390558151838152915184927f0b237afe65f1514fd7ea3f923ea4fe792bdd07000a912b6cd1602a8e7f573c8d92908290030190a25b5050565b600083600160a060020a03811615156115535760006000fd5b60055460408051608081018252600160a060020a03888116825260208083018981528385018981526000606086018190528781528084529590952084518154600160a060020a031916941693909317835551600183015592518051949650919390926115c6926002850192910190611698565b50606091909101516003909101805460ff191691151591909117905560058054600101905560405182907fc0ba8fe4b176c1714197d43b9cc6bcf797a4a7461c5fe8d0ef6e184ae7601e5190600090a25b5b509392505050565b81548183558181151161084457600083815260209020610844918101908301611717565b5b505050565b81548183558181151161084457600083815260209020610844918101908301611717565b5b505050565b60408051602081019091526000815290565b60408051602081019091526000815290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106116d957805160ff1916838001178555611706565b82800160010185558215611706579182015b828111156117065782518255916020019190600101906116eb565b5b50611713929150611717565b5090565b610d1991905b80821115611713576000815560010161171d565b5090565b905600f39e6e1eb0edcf53c221607b54b00cd28f3196fed0a24994dc308b8f611b682d8001553a916ef2f495d26a907cc54d96ed840d7bda71e73194bf5a9df7a76b90a165627a7a723058205024a3509522313181eded1d65dcc3b2507127d4c31a444ec98bf6a44e4747d00029", "networks": { "50": { "links": {}, @@ -745,10 +745,10 @@ "type": "event" } }, - "updated_at": 1502391794388, - "address": "0x6488c866dd2a8528c2f5a9009a9fcde6fe2a3736" + "updated_at": 1513088404204, + "address": "0x1d7022f5b17d2f8b695918fb48fa1089c9f85401" } }, "schema_version": "0.0.5", - "updated_at": 1502391794388 + "updated_at": 1513088404204 }
\ No newline at end of file diff --git a/packages/contracts/build/contracts/MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress.json b/packages/contracts/build/contracts/MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress.json index a83a284e3..454c07961 100644 --- a/packages/contracts/build/contracts/MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress.json +++ b/packages/contracts/build/contracts/MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress.json @@ -635,7 +635,7 @@ "type": "event" } ], - "unlinked_binary": "0x606060405234156200000d57fe5b60405162002adb38038062002adb833981016040528080518201919060200180519060200190919080519060200190919080519060200190919050505b8383835b82825b600082518260328211806200006557508181115b80620000715750600081145b806200007d5750600082145b15620000895760006000fd5b600092505b8451831015620001c257600260008685815181101515620000ab57fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1680620001375750600085848151811015156200011557fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff16145b15620001435760006000fd5b60016002600087868151811015156200015857fe5b9060200190602002015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505b82806001019350506200008e565b8460039080519060200190620001da92919062000240565b50836004819055505b5b5050505050806006819055505b50505080600860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b5050505062000315565b828054828255906000526020600020908101928215620002bc579160200282015b82811115620002bb5782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509160200191906001019062000261565b5b509050620002cb9190620002cf565b5090565b6200031291905b808211156200030e57600081816101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905550600101620002d6565b5090565b90565b6127b680620003256000396000f3006060604052361561015d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063025e7c27146101be578063173825d91461021e57806320ea8d86146102545780632f54bf6e146102745780633411c81c146102c257806337bd78a014610319578063547415251461033f578063553a48fd146103805780635711b311146103f25780637065cb4814610412578063784547a7146104485780637ad28c51146104805780638b51d13f146104a05780639ace38c2146104d4578063a0e67e2b146105cf578063a8abe69a14610644578063add1cbc5146106e6578063b5dc40c314610738578063b77bf600146107bb578063ba51a6df146107e1578063c01a8c8414610801578063c642747414610821578063d38f2d82146108b7578063d74f8edd146108eb578063dc8452cd14610911578063e20056e614610937578063ee22610b1461098c575b6101bc5b60003411156101b9573373ffffffffffffffffffffffffffffffffffffffff167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c346040518082815260200191505060405180910390a25b5b565b005b34156101c657fe5b6101dc60048080359060200190919050506109ac565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561022657fe5b610252600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506109ec565b005b341561025c57fe5b6102726004808035906020019091905050610c94565b005b341561027c57fe5b6102a8600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610e5e565b604051808215151515815260200191505060405180910390f35b34156102ca57fe5b6102ff600480803590602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610e7e565b604051808215151515815260200191505060405180910390f35b341561032157fe5b610329610ead565b6040518082815260200191505060405180910390f35b341561034757fe5b61036a600480803515159060200190919080351515906020019091905050610eb3565b6040518082815260200191505060405180910390f35b341561038857fe5b6103d8600480803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091905050610f4a565b604051808215151515815260200191505060405180910390f35b34156103fa57fe5b610410600480803590602001909190505061108b565b005b341561041a57fe5b610446600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506113a6565b005b341561045057fe5b61046660048080359060200190919050506115a9565b604051808215151515815260200191505060405180910390f35b341561048857fe5b61049e6004808035906020019091905050611693565b005b34156104a857fe5b6104be6004808035906020019091905050611711565b6040518082815260200191505060405180910390f35b34156104dc57fe5b6104f260048080359060200190919050506117e1565b604051808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200184815260200180602001831515151581526020018281038252848181546001816001161561010002031660029004815260200191508054600181600116156101000203166002900480156105bd5780601f10610592576101008083540402835291602001916105bd565b820191906000526020600020905b8154815290600101906020018083116105a057829003601f168201915b50509550505050505060405180910390f35b34156105d757fe5b6105df61183d565b6040518080602001828103825283818151815260200191508051906020019060200280838360008314610631575b8051825260208311156106315760208201915060208101905060208303925061060d565b5050509050019250505060405180910390f35b341561064c57fe5b6106816004808035906020019091908035906020019091908035151590602001909190803515159060200190919050506118d2565b60405180806020018281038252838181518152602001915080519060200190602002808383600083146106d3575b8051825260208311156106d3576020820191506020810190506020830392506106af565b5050509050019250505060405180910390f35b34156106ee57fe5b6106f6611a36565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561074057fe5b6107566004808035906020019091905050611a5c565b60405180806020018281038252838181518152602001915080519060200190602002808383600083146107a8575b8051825260208311156107a857602082019150602081019050602083039250610784565b5050509050019250505060405180910390f35b34156107c357fe5b6107cb611c8e565b6040518082815260200191505060405180910390f35b34156107e957fe5b6107ff6004808035906020019091905050611c94565b005b341561080957fe5b61081f6004808035906020019091905050611d4b565b005b341561082957fe5b6108a1600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091905050611f59565b6040518082815260200191505060405180910390f35b34156108bf57fe5b6108d56004808035906020019091905050611f79565b6040518082815260200191505060405180910390f35b34156108f357fe5b6108fb611f91565b6040518082815260200191505060405180910390f35b341561091957fe5b610921611f96565b6040518082815260200191505060405180910390f35b341561093f57fe5b61098a600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050611f9c565b005b341561099457fe5b6109aa60048080359060200190919050506122c1565b005b6003818154811015156109bb57fe5b906000526020600020900160005b915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60003073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610a295760006000fd5b81600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161515610a835760006000fd5b6000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600091505b600160038054905003821015610c0f578273ffffffffffffffffffffffffffffffffffffffff16600383815481101515610b1657fe5b906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415610c01576003600160038054905003815481101515610b7657fe5b906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600383815481101515610bb257fe5b906000526020600020900160005b6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610c0f565b5b8180600101925050610ae0565b6001600381818054905003915081610c279190612665565b506003805490506004541115610c4657610c45600380549050611c94565b5b8273ffffffffffffffffffffffffffffffffffffffff167f8001553a916ef2f495d26a907cc54d96ed840d7bda71e73194bf5a9df7a76b9060405180905060405180910390a25b5b505b5050565b33600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161515610cee5760006000fd5b81336001600083815260200190815260200160002060008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161515610d5a5760006000fd5b836000600082815260200190815260200160002060030160009054906101000a900460ff1615610d8a5760006000fd5b84610d94816115a9565b151515610da15760006000fd5b60006001600088815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550853373ffffffffffffffffffffffffffffffffffffffff167ff6a317157440607f36269043eb55f1287a5a19ba2216afeab88cd46cbcfb88e960405180905060405180910390a35b5b505b505b50505b5050565b60026020528060005260406000206000915054906101000a900460ff1681565b60016020528160005260406000206020528060005260406000206000915091509054906101000a900460ff1681565b60065481565b60006000600090505b600554811015610f4257838015610ef457506000600082815260200190815260200160002060030160009054906101000a900460ff16155b80610f285750828015610f2757506000600082815260200190815260200160002060030160009054906101000a900460ff165b5b15610f34576001820191505b5b8080600101915050610ebc565b5b5092915050565b60006000600060405180807f72656d6f7665417574686f72697a656441646472657373286164647265737329815250602001905060405180910390209150600090505b600481101561107f578181600481101515610fa457fe5b1a7f0100000000000000000000000000000000000000000000000000000000000000027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168482815181101515610ff757fe5b9060200101517f010000000000000000000000000000000000000000000000000000000000000090047f0100000000000000000000000000000000000000000000000000000000000000027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161415156110715760006000fd5b5b8080600101915050610f8d565b600192505b5050919050565b6000816000600082815260200190815260200160002060030160009054906101000a900460ff16156110bd5760006000fd5b826110c7816115a9565b15156110d35760006000fd5b836000600060008381526020019081526020016000209050600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561116c5760006000fd5b611211816002018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156112075780601f106111dc57610100808354040283529160200191611207565b820191906000526020600020905b8154815290600101906020018083116111ea57829003601f168201915b5050505050610f4a565b151561121d5760006000fd5b60006000878152602001908152602001600020945060018560030160006101000a81548160ff0219169083151502179055508460000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1685600101548660020160405180828054600181600116156101000203166002900480156112f85780601f106112cd576101008083540402835291602001916112f8565b820191906000526020600020905b8154815290600101906020018083116112db57829003601f168201915b505091505060006040518083038185876185025a03f1925050501561134c57857f33e13ecb54c3076d8e8bb8c2881800a4d972b792045ffae98fdf46df365fed7560405180905060405180910390a261139a565b857f526441bb6c1aba3c9a4a6ca1d6545da9c2333c8c48343ef398eb858d72b7923660405180905060405180910390a260008560030160006101000a81548160ff0219169083151502179055505b5b5b50505b505b505050565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156113e15760006000fd5b80600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161561143a5760006000fd5b8160008173ffffffffffffffffffffffffffffffffffffffff1614156114605760006000fd5b600160038054905001600454603282118061147a57508181115b806114855750600081145b806114905750600082145b1561149b5760006000fd5b6001600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550600380548060010182816115079190612691565b916000526020600020900160005b87909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550508473ffffffffffffffffffffffffffffffffffffffff167ff39e6e1eb0edcf53c221607b54b00cd28f3196fed0a24994dc308b8f611b682d60405180905060405180910390a25b5b50505b505b505b50565b60006000600060009150600090505b60038054905081101561168b576001600085815260200190815260200160002060006003838154811015156115e957fe5b906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161561166a576001820191505b60045482141561167d576001925061168c565b5b80806001019150506115b8565b5b5050919050565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156116ce5760006000fd5b806006819055507fd1c9101a34feff75cccef14a28785a0279cb0b49c1f321f21f5f422e746b4377816040518082815260200191505060405180910390a15b5b50565b60006000600090505b6003805490508110156117da5760016000848152602001908152602001600020600060038381548110151561174b57fe5b906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16156117cc576001820191505b5b808060010191505061171a565b5b50919050565b60006020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169080600101549080600201908060030160009054906101000a900460ff16905084565b6118456126bd565b60038054806020026020016040519081016040528092919081815260200182805480156118c757602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001906001019080831161187d575b505050505090505b90565b6118da6126d1565b6118e26126d1565b600060006005546040518059106118f65750595b908082528060200260200182016040525b50925060009150600090505b6005548110156119b65785801561194b57506000600082815260200190815260200160002060030160009054906101000a900460ff16155b8061197f575084801561197e57506000600082815260200190815260200160002060030160009054906101000a900460ff165b5b156119a85780838381518110151561199357fe5b90602001906020020181815250506001820191505b5b8080600101915050611913565b8787036040518059106119c65750595b908082528060200260200182016040525b5093508790505b86811015611a2a5782818151811015156119f457fe5b9060200190602002015184898303815181101515611a0e57fe5b90602001906020020181815250505b80806001019150506119de565b5b505050949350505050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b611a646126bd565b611a6c6126bd565b60006000600380549050604051805910611a835750595b908082528060200260200182016040525b50925060009150600090505b600380549050811015611be657600160008681526020019081526020016000206000600383815481101515611ad157fe5b906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615611bd857600381815481101515611b5a57fe5b906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff168383815181101515611b9557fe5b9060200190602002019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506001820191505b5b8080600101915050611aa0565b81604051805910611bf45750595b908082528060200260200182016040525b509350600090505b81811015611c85578281815181101515611c2357fe5b906020019060200201518482815181101515611c3b57fe5b9060200190602002019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250505b8080600101915050611c0d565b5b505050919050565b60055481565b3073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515611ccf5760006000fd5b600380549050816032821180611ce457508181115b80611cef5750600081145b80611cfa5750600082145b15611d055760006000fd5b826004819055507fa3f1ee9126a074d9326c682f561767f710e927faa811f7a99829d49dc421797a836040518082815260200191505060405180910390a15b5b50505b50565b33600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161515611da55760006000fd5b8160006000600083815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415611e015760006000fd5b82336001600083815260200190815260200160002060008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615611e6c5760006000fd5b84611e76816115a9565b151515611e835760006000fd5b60016001600088815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550853373ffffffffffffffffffffffffffffffffffffffff167f4a504a94899432a9846e1aa406dceb1bcfd538bb839071d49d1e5e23f5be30ef60405180905060405180910390a3611f3c866115a9565b15611f4c57611f4b86426124b9565b5b5b5b505b50505b505b5050565b6000611f6684848461250e565b9050611f7181611d4b565b5b9392505050565b60076020528060005260406000206000915090505481565b603281565b60045481565b60003073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515611fd95760006000fd5b82600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615156120335760006000fd5b82600260008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff161561208c5760006000fd5b600092505b60038054905083101561217a578473ffffffffffffffffffffffffffffffffffffffff166003848154811015156120c457fe5b906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561216c578360038481548110151561211d57fe5b906000526020600020900160005b6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061217a565b5b8280600101935050612091565b6000600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508473ffffffffffffffffffffffffffffffffffffffff167f8001553a916ef2f495d26a907cc54d96ed840d7bda71e73194bf5a9df7a76b9060405180905060405180910390a28373ffffffffffffffffffffffffffffffffffffffff167ff39e6e1eb0edcf53c221607b54b00cd28f3196fed0a24994dc308b8f611b682d60405180905060405180910390a25b5b505b505b505050565b6000816000600082815260200190815260200160002060030160009054906101000a900460ff16156122f35760006000fd5b826122fd816115a9565b15156123095760006000fd5b8360065460076000838152602001908152602001600020540142101515156123315760006000fd5b60006000868152602001908152602001600020935060018460030160006101000a81548160ff0219169083151502179055508360000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16846001015485600201604051808280546001816001161561010002031660029004801561240c5780601f106123e15761010080835404028352916020019161240c565b820191906000526020600020905b8154815290600101906020018083116123ef57829003601f168201915b505091505060006040518083038185876185025a03f1925050501561246057847f33e13ecb54c3076d8e8bb8c2881800a4d972b792045ffae98fdf46df365fed7560405180905060405180910390a26124ae565b847f526441bb6c1aba3c9a4a6ca1d6545da9c2333c8c48343ef398eb858d72b7923660405180905060405180910390a260008460030160006101000a81548160ff0219169083151502179055505b5b5b505b505b505050565b806007600084815260200190815260200160002081905550817f0b237afe65f1514fd7ea3f923ea4fe792bdd07000a912b6cd1602a8e7f573c8d826040518082815260200191505060405180910390a25b5050565b60008360008173ffffffffffffffffffffffffffffffffffffffff1614156125365760006000fd5b60055491506080604051908101604052808673ffffffffffffffffffffffffffffffffffffffff168152602001858152602001848152602001600015158152506000600084815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506020820151816001015560408201518160020190805190602001906125f69291906126e5565b5060608201518160030160006101000a81548160ff0219169083151502179055509050506001600560008282540192505081905550817fc0ba8fe4b176c1714197d43b9cc6bcf797a4a7461c5fe8d0ef6e184ae7601e5160405180905060405180910390a25b5b509392505050565b81548183558181151161268c5781836000526020600020918201910161268b9190612765565b5b505050565b8154818355818115116126b8578183600052602060002091820191016126b79190612765565b5b505050565b602060405190810160405280600081525090565b602060405190810160405280600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061272657805160ff1916838001178555612754565b82800160010185558215612754579182015b82811115612753578251825591602001919060010190612738565b5b5090506127619190612765565b5090565b61278791905b8082111561278357600081600090555060010161276b565b5090565b905600a165627a7a72305820b0518e85781087b035c1e957799a90f8e67dc45520679ff50b77e0bc71b9cd440029", + "unlinked_binary": "0x606060405234156200000d57fe5b60405162001da438038062001da4833981016040908152815160208301519183015160608401519190930192905b8383835b82825b600082518260328211806200005657508181115b8062000060575080155b806200006a575081155b15620000765760006000fd5b600092505b84518310156200014b576002600086858151811015156200009857fe5b6020908102909101810151600160a060020a031682528101919091526040016000205460ff1680620000eb57508483815181101515620000d457fe5b90602001906020020151600160a060020a03166000145b15620000f75760006000fd5b60016002600087868151811015156200010c57fe5b602090810291909101810151600160a060020a03168252810191909152604001600020805460ff19169115159190911790555b6001909201916200007b565b8451620001609060039060208801906200019c565b5060048490555b5b505050600683905550505b505060088054600160a060020a031916600160a060020a038416179055505b5050505062000235565b828054828255906000526020600020908101928215620001f4579160200282015b82811115620001f45782518254600160a060020a031916600160a060020a03909116178255602090920191600190910190620001bd565b5b506200020392915062000207565b5090565b6200023291905b8082111562000203578054600160a060020a03191681556001016200020e565b5090565b90565b611b5f80620002456000396000f300606060405236156101435763ffffffff60e060020a600035041663025e7c278114610195578063173825d9146101c457806320ea8d86146101e25780632f54bf6e146101f75780633411c81c1461022757806337bd78a01461025a578063547415251461027c578063553a48fd146102a85780635711b311146103125780637065cb4814610327578063784547a7146103455780637ad28c511461036c5780638b51d13f146103815780639ace38c2146103a6578063a0e67e2b14610463578063a8abe69a146104ce578063add1cbc514610549578063b5dc40c314610575578063b77bf600146105e3578063ba51a6df14610605578063c01a8c841461061a578063c64274741461062f578063d38f2d82146106a4578063d74f8edd146106c9578063dc8452cd146106eb578063e20056e61461070d578063ee22610b14610731575b6101935b600034111561019057604080513481529051600160a060020a033316917fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c919081900360200190a25b5b565b005b341561019d57fe5b6101a8600435610746565b60408051600160a060020a039092168252519081900360200190f35b34156101cc57fe5b610193600160a060020a0360043516610778565b005b34156101ea57fe5b610193600435610917565b005b34156101ff57fe5b610213600160a060020a0360043516610a0b565b604080519115158252519081900360200190f35b341561022f57fe5b610213600435600160a060020a0360243516610a20565b604080519115158252519081900360200190f35b341561026257fe5b61026a610a40565b60408051918252519081900360200190f35b341561028457fe5b61026a60043515156024351515610a46565b60408051918252519081900360200190f35b34156102b057fe5b610213600480803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843750949650610ab595505050505050565b604080519115158252519081900360200190f35b341561031a57fe5b610193600435610b5a565b005b341561032f57fe5b610193600160a060020a0360043516610d79565b005b341561034d57fe5b610213600435610e9e565b604080519115158252519081900360200190f35b341561037457fe5b610193600435610f32565b005b341561038957fe5b61026a600435610f90565b60408051918252519081900360200190f35b34156103ae57fe5b6103b960043561100f565b60408051600160a060020a03861681526020810185905282151560608201526080918101828152845460026000196101006001841615020190911604928201839052909160a0830190859080156104515780601f1061042657610100808354040283529160200191610451565b820191906000526020600020905b81548152906001019060200180831161043457829003601f168201915b50509550505050505060405180910390f35b341561046b57fe5b610473611043565b60408051602080825283518183015283519192839290830191858101910280838382156104bb575b8051825260208311156104bb57601f19909201916020918201910161049b565b5050509050019250505060405180910390f35b34156104d657fe5b610473600435602435604435151560643515156110ac565b60408051602080825283518183015283519192839290830191858101910280838382156104bb575b8051825260208311156104bb57601f19909201916020918201910161049b565b5050509050019250505060405180910390f35b341561055157fe5b6101a86111e1565b60408051600160a060020a039092168252519081900360200190f35b341561057d57fe5b6104736004356111f0565b60408051602080825283518183015283519192839290830191858101910280838382156104bb575b8051825260208311156104bb57601f19909201916020918201910161049b565b5050509050019250505060405180910390f35b34156105eb57fe5b61026a611378565b60408051918252519081900360200190f35b341561060d57fe5b61019360043561137e565b005b341561062257fe5b61019360043561140e565b005b341561063757fe5b604080516020600460443581810135601f810184900484028501840190955284845261026a948235600160a060020a031694602480359560649492939190920191819084018382808284375094965061152395505050505050565b60408051918252519081900360200190f35b34156106ac57fe5b61026a600435611543565b60408051918252519081900360200190f35b34156106d157fe5b61026a611555565b60408051918252519081900360200190f35b34156106f357fe5b61026a61155a565b60408051918252519081900360200190f35b341561071557fe5b610193600160a060020a0360043581169060243516611560565b005b341561073957fe5b6101936004356116f8565b005b600380548290811061075457fe5b906000526020600020900160005b915054906101000a9004600160a060020a031681565b600030600160a060020a031633600160a060020a031614151561079b5760006000fd5b600160a060020a038216600090815260026020526040902054829060ff1615156107c55760006000fd5b600160a060020a0383166000908152600260205260408120805460ff1916905591505b600354600019018210156108c05782600160a060020a031660038381548110151561080f57fe5b906000526020600020900160005b9054906101000a9004600160a060020a0316600160a060020a031614156108b45760038054600019810190811061085057fe5b906000526020600020900160005b9054906101000a9004600160a060020a031660038381548110151561087f57fe5b906000526020600020900160005b6101000a815481600160a060020a030219169083600160a060020a031602179055506108c0565b5b6001909101906107e8565b6003805460001901906108d3908261199b565b5060035460045411156108ec576003546108ec9061137e565b5b604051600160a060020a03841690600080516020611b1483398151915290600090a25b5b505b5050565b33600160a060020a03811660009081526002602052604090205460ff1615156109405760006000fd5b600082815260016020908152604080832033600160a060020a038116855292529091205483919060ff1615156109765760006000fd5b600084815260208190526040902060030154849060ff16156109985760006000fd5b846109a281610e9e565b156109ad5760006000fd5b6000868152600160209081526040808320600160a060020a0333168085529252808320805460ff191690555188927ff6a317157440607f36269043eb55f1287a5a19ba2216afeab88cd46cbcfb88e991a35b5b505b505b50505b5050565b60026020526000908152604090205460ff1681565b600160209081526000928352604080842090915290825290205460ff1681565b60065481565b6000805b600554811015610aad57838015610a73575060008181526020819052604090206003015460ff16155b80610a975750828015610a97575060008181526020819052604090206003015460ff165b5b15610aa4576001820191505b5b600101610a4a565b5b5092915050565b604080517f72656d6f7665417574686f72697a65644164647265737328616464726573732981529051908190036020019020600090815b6004811015610b4e57818160048110610b0157fe5b1a60f860020a02600160f860020a0319168482815181101515610b2057fe5b60209101015160f860020a9081900402600160f860020a03191614610b455760006000fd5b5b600101610aec565b600192505b5050919050565b600081815260208190526040812060030154829060ff1615610b7c5760006000fd5b82610b8681610e9e565b1515610b925760006000fd5b60008481526020819052604090206008548154869291600160a060020a03918216911614610bc05760006000fd5b600281810180546040805160206001841615610100026000190190931694909404601f8101839004830285018301909152808452610c55939291830182828015610c4b5780601f10610c2057610100808354040283529160200191610c4b565b820191906000526020600020905b815481529060010190602001808311610c2e57829003601f168201915b5050505050610ab5565b1515610c615760006000fd5b6000868152602081905260409081902060038101805460ff19166001908117909155815481830154935160028085018054959b50600160a060020a0390931695949293919283928592600019918316156101000291909101909116048015610d0a5780601f10610cdf57610100808354040283529160200191610d0a565b820191906000526020600020905b815481529060010190602001808311610ced57829003601f168201915b505091505060006040518083038185876187965a03f19250505015610d47576040518690600080516020611af483398151915290600090a26109ff565b6040518690600080516020611ab483398151915290600090a260038501805460ff191690555b5b5b50505b505b505050565b30600160a060020a031633600160a060020a0316141515610d9a5760006000fd5b600160a060020a038116600090815260026020526040902054819060ff1615610dc35760006000fd5b81600160a060020a0381161515610dda5760006000fd5b6003805490506001016004546032821180610df457508181115b80610dfd575080155b80610e06575081155b15610e115760006000fd5b600160a060020a0385166000908152600260205260409020805460ff191660019081179091556003805490918101610e49838261199b565b916000526020600020900160005b8154600160a060020a03808a166101009390930a83810291021990911617909155604051909150600080516020611ad483398151915290600090a25b5b50505b505b505b50565b600080805b600354811015610b535760008481526001602052604081206003805491929184908110610ecc57fe5b906000526020600020900160005b9054600160a060020a036101009290920a900416815260208101919091526040016000205460ff1615610f0e576001820191505b600454821415610f215760019250610b53565b5b600101610ea3565b5b5050919050565b30600160a060020a031633600160a060020a0316141515610f535760006000fd5b60068190556040805182815290517fd1c9101a34feff75cccef14a28785a0279cb0b49c1f321f21f5f422e746b43779181900360200190a15b5b50565b6000805b6003548110156110085760008381526001602052604081206003805491929184908110610fbd57fe5b906000526020600020900160005b9054600160a060020a036101009290920a900416815260208101919091526040016000205460ff1615610fff576001820191505b5b600101610f94565b5b50919050565b6000602081905290815260409020805460018201546003830154600160a060020a0390921692909160029091019060ff1684565b61104b6119ef565b60038054806020026020016040519081016040528092919081815260200182805480156110a157602002820191906000526020600020905b8154600160a060020a03168152600190910190602001808311611083575b505050505090505b90565b6110b46119ef565b6110bc6119ef565b600060006005546040518059106110d05750595b908082528060200260200182016040525b50925060009150600090505b60055481101561116a57858015611116575060008181526020819052604090206003015460ff16155b8061113a575084801561113a575060008181526020819052604090206003015460ff165b5b156111615780838381518110151561114f57fe5b60209081029091010152600191909101905b5b6001016110ed565b87870360405180591061117a5750595b908082528060200260200182016040525b5093508790505b868110156111d55782818151811015156111a857fe5b90602001906020020151848983038151811015156111c257fe5b602090810290910101525b600101611192565b5b505050949350505050565b600854600160a060020a031681565b6111f86119ef565b6112006119ef565b60035460405160009182918059106112155750595b908082528060200260200182016040525b50925060009150600090505b6003548110156112fa576000858152600160205260408120600380549192918490811061125b57fe5b906000526020600020900160005b9054600160a060020a036101009290920a900416815260208101919091526040016000205460ff16156112f15760038054829081106112a457fe5b906000526020600020900160005b9054906101000a9004600160a060020a031683838151811015156112d257fe5b600160a060020a03909216602092830290910190910152600191909101905b5b600101611232565b816040518059106113085750595b908082528060200260200182016040525b509350600090505b8181101561136f57828181518110151561133757fe5b90602001906020020151848281518110151561134f57fe5b600160a060020a039092166020928302909101909101525b600101611321565b5b505050919050565b60055481565b30600160a060020a031633600160a060020a031614151561139f5760006000fd5b6003548160328211806113b157508181115b806113ba575080155b806113c3575081155b156113ce5760006000fd5b60048390556040805184815290517fa3f1ee9126a074d9326c682f561767f710e927faa811f7a99829d49dc421797a9181900360200190a15b5b50505b50565b33600160a060020a03811660009081526002602052604090205460ff1615156114375760006000fd5b6000828152602081905260409020548290600160a060020a0316151561145d5760006000fd5b600083815260016020908152604080832033600160a060020a038116855292529091205484919060ff16156114925760006000fd5b8461149c81610e9e565b156114a75760006000fd5b6000868152600160208181526040808420600160a060020a0333168086529252808420805460ff1916909317909255905188927f4a504a94899432a9846e1aa406dceb1bcfd538bb839071d49d1e5e23f5be30ef91a361150686610e9e565b156109ff576109ff8642611869565b5b5b5b505b50505b505b5050565b60006115308484846118b5565b905061153b8161140e565b5b9392505050565b60076020526000908152604090205481565b603281565b60045481565b600030600160a060020a031633600160a060020a03161415156115835760006000fd5b600160a060020a038316600090815260026020526040902054839060ff1615156115ad5760006000fd5b600160a060020a038316600090815260026020526040902054839060ff16156115d65760006000fd5b600092505b60035483101561167e5784600160a060020a03166003848154811015156115fe57fe5b906000526020600020900160005b9054906101000a9004600160a060020a0316600160a060020a03161415611672578360038481548110151561163d57fe5b906000526020600020900160005b6101000a815481600160a060020a030219169083600160a060020a0316021790555061167e565b5b6001909201916115db565b600160a060020a03808616600081815260026020526040808220805460ff199081169091559388168252808220805490941660011790935591519091600080516020611b1483398151915291a2604051600160a060020a03851690600080516020611ad483398151915290600090a25b5b505b505b505050565b600081815260208190526040812060030154829060ff161561171a5760006000fd5b8261172481610e9e565b15156117305760006000fd5b6006546000858152600760205260409020548591014210156117525760006000fd5b6000858152602081905260409081902060038101805460ff19166001908117909155815481830154935160028085018054959a50600160a060020a03909316959492939192839285926000199183161561010002919091019091160480156117fb5780601f106117d0576101008083540402835291602001916117fb565b820191906000526020600020905b8154815290600101906020018083116117de57829003601f168201915b505091505060006040518083038185876187965a03f19250505015611838576040518590600080516020611af483398151915290600090a2610a02565b6040518590600080516020611ab483398151915290600090a260038401805460ff191690555b5b5b505b505b505050565b6000828152600760209081526040918290208390558151838152915184927f0b237afe65f1514fd7ea3f923ea4fe792bdd07000a912b6cd1602a8e7f573c8d92908290030190a25b5050565b600083600160a060020a03811615156118ce5760006000fd5b60055460408051608081018252600160a060020a03888116825260208083018981528385018981526000606086018190528781528084529590952084518154600160a060020a03191694169390931783555160018301559251805194965091939092611941926002850192910190611a13565b50606091909101516003909101805460ff191691151591909117905560058054600101905560405182907fc0ba8fe4b176c1714197d43b9cc6bcf797a4a7461c5fe8d0ef6e184ae7601e5190600090a25b5b509392505050565b81548183558181151161091057600083815260209020610910918101908301611a92565b5b505050565b81548183558181151161091057600083815260209020610910918101908301611a92565b5b505050565b60408051602081019091526000815290565b60408051602081019091526000815290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611a5457805160ff1916838001178555611a81565b82800160010185558215611a81579182015b82811115611a81578251825591602001919060010190611a66565b5b50611a8e929150611a92565b5090565b6110a991905b80821115611a8e5760008155600101611a98565b5090565b905600526441bb6c1aba3c9a4a6ca1d6545da9c2333c8c48343ef398eb858d72b79236f39e6e1eb0edcf53c221607b54b00cd28f3196fed0a24994dc308b8f611b682d33e13ecb54c3076d8e8bb8c2881800a4d972b792045ffae98fdf46df365fed758001553a916ef2f495d26a907cc54d96ed840d7bda71e73194bf5a9df7a76b90a165627a7a723058204c9f0a36ec2dc83e3665c5e5ca7acb6417fd7a59062273d0351efee676bb280c0029", "networks": { "50": { "links": {}, @@ -793,9 +793,9 @@ "type": "event" } }, - "updated_at": 1502391794394 + "updated_at": 1513088404209 } }, "schema_version": "0.0.5", - "updated_at": 1502391794394 + "updated_at": 1513088404209 }
\ No newline at end of file diff --git a/packages/contracts/build/contracts/Ownable.json b/packages/contracts/build/contracts/Ownable.json index ebe5a1804..d0e73d497 100644 --- a/packages/contracts/build/contracts/Ownable.json +++ b/packages/contracts/build/contracts/Ownable.json @@ -33,8 +33,8 @@ "type": "constructor" } ], - "unlinked_binary": "0x6060604052341561000c57fe5b5b60008054600160a060020a03191633600160a060020a03161790555b5b60f3806100386000396000f300606060405263ffffffff60e060020a6000350416638da5cb5b8114602a578063f2fde38b146053575bfe5b3415603157fe5b6037606e565b60408051600160a060020a039092168252519081900360200190f35b3415605a57fe5b606c600160a060020a0360043516607d565b005b600054600160a060020a031681565b60005433600160a060020a0390811691161460985760006000fd5b600160a060020a0381161560c25760008054600160a060020a031916600160a060020a0383161790555b5b5b505600a165627a7a7230582009515308d7738f55dd8ba99e29943dc01d4a032197af5f4e1adc20b93fb927f20029", + "unlinked_binary": "0x6060604052341561000c57fe5b5b60008054600160a060020a03191633600160a060020a03161790555b5b60f3806100386000396000f300606060405263ffffffff60e060020a6000350416638da5cb5b8114602a578063f2fde38b146053575bfe5b3415603157fe5b6037606e565b60408051600160a060020a039092168252519081900360200190f35b3415605a57fe5b606c600160a060020a0360043516607d565b005b600054600160a060020a031681565b60005433600160a060020a0390811691161460985760006000fd5b600160a060020a0381161560c25760008054600160a060020a031916600160a060020a0383161790555b5b5b505600a165627a7a7230582048ccfb6ebb285c80c8b4030a0e4f2e6ec2a0619b363a2d7cd20692a0cfb170550029", "networks": {}, "schema_version": "0.0.5", - "updated_at": 1502391792217 + "updated_at": 1513088402049 }
\ No newline at end of file diff --git a/packages/contracts/build/contracts/SafeMath.json b/packages/contracts/build/contracts/SafeMath.json index 86782f47a..fe15df18b 100644 --- a/packages/contracts/build/contracts/SafeMath.json +++ b/packages/contracts/build/contracts/SafeMath.json @@ -1,8 +1,8 @@ { "contract_name": "SafeMath", "abi": [], - "unlinked_binary": "0x60606040523415600b57fe5b5b60338060196000396000f30060606040525bfe00a165627a7a723058201f432ae32cd7cc9a0efb0b70b25524cf42d165202875a497f8b0122d77a6a5ba0029", + "unlinked_binary": "0x60606040523415600b57fe5b5b60338060196000396000f30060606040525bfe00a165627a7a72305820becdc80300a4dbf834bb9ab115616eb459f82b51a9133d360eb1e6e5402072eb0029", "networks": {}, "schema_version": "0.0.5", - "updated_at": 1502391792217 + "updated_at": 1513088402049 }
\ No newline at end of file diff --git a/packages/contracts/build/contracts/StandardToken.json b/packages/contracts/build/contracts/StandardToken.json index 4f67b8772..3f3f3921f 100644 --- a/packages/contracts/build/contracts/StandardToken.json +++ b/packages/contracts/build/contracts/StandardToken.json @@ -169,8 +169,8 @@ "type": "event" } ], - "unlinked_binary": "0x6060604052341561000c57fe5b5b6104388061001c6000396000f3006060604052361561005c5763ffffffff60e060020a600035041663095ea7b3811461005e57806318160ddd1461009157806323b872dd146100b357806370a08231146100ec578063a9059cbb1461011a578063dd62ed3e1461014d575bfe5b341561006657fe5b61007d600160a060020a0360043516602435610181565b604080519115158252519081900360200190f35b341561009957fe5b6100a16101ec565b60408051918252519081900360200190f35b34156100bb57fe5b61007d600160a060020a03600435811690602435166044356101f2565b604080519115158252519081900360200190f35b34156100f457fe5b6100a1600160a060020a03600435166102ee565b60408051918252519081900360200190f35b341561012257fe5b61007d600160a060020a036004351660243561030d565b604080519115158252519081900360200190f35b341561015557fe5b6100a1600160a060020a03600435811690602435166103bf565b60408051918252519081900360200190f35b600160a060020a03338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60025481565b600160a060020a0383166000908152602081905260408120548290108015906102425750600160a060020a0380851660009081526001602090815260408083203390941683529290522054829010155b80156102685750600160a060020a03831660009081526020819052604090205482810110155b156102e257600160a060020a0380841660008181526020818152604080832080548801905588851680845281842080548990039055600183528184203390961684529482529182902080548790039055815186815291519293926000805160206103ed8339815191529281900390910190a35060016102e6565b5060005b5b9392505050565b600160a060020a0381166000908152602081905260409020545b919050565b600160a060020a0333166000908152602081905260408120548290108015906103505750600160a060020a03831660009081526020819052604090205482810110155b156103b057600160a060020a0333811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191936000805160206103ed833981519152929081900390910190a35060016101e6565b5060006101e6565b5b92915050565b600160a060020a038083166000908152600160209081526040808320938516835292905220545b929150505600ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a723058208bbb664bbcb187b9a351ec93e9763b53c0157b40e7ee3033bb5b59eddd9e575e0029", + "unlinked_binary": "0x6060604052341561000c57fe5b5b6104388061001c6000396000f3006060604052361561005c5763ffffffff60e060020a600035041663095ea7b3811461005e57806318160ddd1461009157806323b872dd146100b357806370a08231146100ec578063a9059cbb1461011a578063dd62ed3e1461014d575bfe5b341561006657fe5b61007d600160a060020a0360043516602435610181565b604080519115158252519081900360200190f35b341561009957fe5b6100a16101ec565b60408051918252519081900360200190f35b34156100bb57fe5b61007d600160a060020a03600435811690602435166044356101f2565b604080519115158252519081900360200190f35b34156100f457fe5b6100a1600160a060020a03600435166102ee565b60408051918252519081900360200190f35b341561012257fe5b61007d600160a060020a036004351660243561030d565b604080519115158252519081900360200190f35b341561015557fe5b6100a1600160a060020a03600435811690602435166103bf565b60408051918252519081900360200190f35b600160a060020a03338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60025481565b600160a060020a0383166000908152602081905260408120548290108015906102425750600160a060020a0380851660009081526001602090815260408083203390941683529290522054829010155b80156102685750600160a060020a03831660009081526020819052604090205482810110155b156102e257600160a060020a0380841660008181526020818152604080832080548801905588851680845281842080548990039055600183528184203390961684529482529182902080548790039055815186815291519293926000805160206103ed8339815191529281900390910190a35060016102e6565b5060005b5b9392505050565b600160a060020a0381166000908152602081905260409020545b919050565b600160a060020a0333166000908152602081905260408120548290108015906103505750600160a060020a03831660009081526020819052604090205482810110155b156103b057600160a060020a0333811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191936000805160206103ed833981519152929081900390910190a35060016101e6565b5060006101e6565b5b92915050565b600160a060020a038083166000908152600160209081526040808320938516835292905220545b929150505600ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a7230582056d411baf4691cc9a0a55ffa6b4a4e9308ea12187fd2fa738228bbd266709d4d0029", "networks": {}, "schema_version": "0.0.5", - "updated_at": 1502391449723 + "updated_at": 1513088402049 }
\ No newline at end of file diff --git a/packages/contracts/build/contracts/Token.json b/packages/contracts/build/contracts/Token.json index 9487c0782..c16f36d98 100644 --- a/packages/contracts/build/contracts/Token.json +++ b/packages/contracts/build/contracts/Token.json @@ -169,8 +169,8 @@ "type": "event" } ], - "unlinked_binary": "0x6060604052341561000c57fe5b5b6101e08061001c6000396000f3006060604052361561005c5763ffffffff60e060020a600035041663095ea7b3811461005e57806318160ddd1461009157806323b872dd146100b357806370a08231146100ec578063a9059cbb1461005e578063dd62ed3e1461014d575bfe5b341561006657fe5b61007d600160a060020a0360043516602435610181565b604080519115158252519081900360200190f35b341561009957fe5b6100a161018a565b60408051918252519081900360200190f35b34156100bb57fe5b61007d600160a060020a0360043581169060243516604435610190565b604080519115158252519081900360200190f35b34156100f457fe5b6100a1600160a060020a036004351661019a565b60408051918252519081900360200190f35b341561006657fe5b61007d600160a060020a0360043516602435610181565b604080519115158252519081900360200190f35b341561015557fe5b6100a1600160a060020a0360043581169060243516610181565b60408051918252519081900360200190f35b60005b92915050565b60005b90565b60005b9392505050565b60005b919050565b60005b92915050565b60005b929150505600a165627a7a7230582082d46fcd9caa49348b3932d5c18807e1d10d0105371a8bce147cc647f3762a500029", + "unlinked_binary": "0x6060604052341561000c57fe5b5b6101e08061001c6000396000f3006060604052361561005c5763ffffffff60e060020a600035041663095ea7b3811461005e57806318160ddd1461009157806323b872dd146100b357806370a08231146100ec578063a9059cbb1461005e578063dd62ed3e1461014d575bfe5b341561006657fe5b61007d600160a060020a0360043516602435610181565b604080519115158252519081900360200190f35b341561009957fe5b6100a161018a565b60408051918252519081900360200190f35b34156100bb57fe5b61007d600160a060020a0360043581169060243516604435610190565b604080519115158252519081900360200190f35b34156100f457fe5b6100a1600160a060020a036004351661019a565b60408051918252519081900360200190f35b341561006657fe5b61007d600160a060020a0360043516602435610181565b604080519115158252519081900360200190f35b341561015557fe5b6100a1600160a060020a0360043581169060243516610181565b60408051918252519081900360200190f35b60005b92915050565b60005b90565b60005b9392505050565b60005b919050565b60005b92915050565b60005b929150505600a165627a7a72305820107c1e9e7aa669d21343c42639b4bb080602c349d00c1da14b8ea6b6dcc0b0f80029", "networks": {}, "schema_version": "0.0.5", - "updated_at": 1502391792217 + "updated_at": 1513088402049 }
\ No newline at end of file diff --git a/packages/contracts/build/contracts/TokenRegistry.json b/packages/contracts/build/contracts/TokenRegistry.json index f7989ef8f..1dda2dc74 100644 --- a/packages/contracts/build/contracts/TokenRegistry.json +++ b/packages/contracts/build/contracts/TokenRegistry.json @@ -527,9 +527,9 @@ "type": "event" } ], - "unlinked_binary": "0x60606040525b60008054600160a060020a03191633600160a060020a03161790555b5b612cc5806100316000396000f300606060405236156100ca5763ffffffff60e060020a60003504166313baf1e681146100cc5780632fbfeba9146100ed5780633550b6d91461015f57806356318820146101d15780637abccac9146102335780638da5cb5b1461044d578063a880319d14610479578063c370c86d1461059a578063e4860339146105fc578063e5df8b841461082b578063e73fc0c31461085a578063ee8c24b814610aae578063eef05f6514610b19578063efa74f1f14610b7b578063f036417f14610dcf578063f2fde38b14610e31575bfe5b34156100d457fe5b6100eb600160a060020a0360043516602435610e4f565b005b34156100f557fe5b610143600480803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284375094965061134895505050505050565b60408051600160a060020a039092168252519081900360200190f35b341561016757fe5b610143600480803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437509496506113bb95505050505050565b60408051600160a060020a039092168252519081900360200190f35b34156101d957fe5b60408051602060046024803582810135601f81018590048502860185019096528585526100eb958335600160a060020a0316959394604494939290920191819084018382808284375094965061142e95505050505050565b005b341561023b57fe5b61024f600160a060020a03600435166115cf565b6040518087600160a060020a0316600160a060020a0316815260200180602001806020018660ff1660ff168152602001806020018060200185810385528a8181518152602001915080519060200190808383600083146102ca575b8051825260208311156102ca57601f1990920191602091820191016102aa565b505050905090810190601f1680156102f65780820380516001836020036101000a031916815260200191505b5085810384528951815289516020918201918b01908083838215610335575b80518252602083111561033557601f199092019160209182019101610315565b505050905090810190601f1680156103615780820380516001836020036101000a031916815260200191505b50858103835287518152875160209182019189019080838382156103a0575b8051825260208311156103a057601f199092019160209182019101610380565b505050905090810190601f1680156103cc5780820380516001836020036101000a031916815260200191505b508581038252865181528651602091820191880190808383821561040b575b80518252602083111561040b57601f1990920191602091820191016103eb565b505050905090810190601f1680156104375780820380516001836020036101000a031916815260200191505b509a505050505050505050505060405180910390f35b341561045557fe5b6101436118ba565b60408051600160a060020a039092168252519081900360200190f35b341561048157fe5b60408051602060046024803582810135601f81018590048502860185019096528585526100eb958335600160a060020a0316959394604494939290920191819084018382808284375050604080516020601f89358b0180359182018390048302840183019094528083529799988101979196509182019450925082915084018382808284375050604080516020601f818a01358b0180359182018390048302840183018552818452989a60ff8b35169a90999401975091955091820193509150819084018382808284375050604080516020601f89358b018035918201839004830284018301909452808352979998810197919650918201945092508291508401838280828437509496506118c995505050505050565b005b34156105a257fe5b60408051602060046024803582810135601f81018590048502860185019096528585526100eb958335600160a060020a03169593946044949392909201918190840183828082843750949650611e7a95505050505050565b005b341561060457fe5b610618600160a060020a03600435166121a1565b60408051600160a060020a038816815260ff8516606082015260c0602082018181528854600260001961010060018416150201909116049183018290529192830190608084019060a085019060e08601908b9080156106b85780601f1061068d576101008083540402835291602001916106b8565b820191906000526020600020905b81548152906001019060200180831161069b57829003601f168201915b505085810384528954600260001961010060018416150201909116048082526020909101908a90801561072c5780601f106107015761010080835404028352916020019161072c565b820191906000526020600020905b81548152906001019060200180831161070f57829003601f168201915b50508581038352875460026000196101006001841615020190911604808252602090910190889080156107a05780601f10610775576101008083540402835291602001916107a0565b820191906000526020600020905b81548152906001019060200180831161078357829003601f168201915b50508581038252865460026000196101006001841615020190911604808252602090910190879080156108145780601f106107e957610100808354040283529160200191610814565b820191906000526020600020905b8154815290600101906020018083116107f757829003601f168201915b50509a505050505050505050505060405180910390f35b341561083357fe5b6101436004356121dc565b60408051600160a060020a039092168252519081900360200190f35b341561086257fe5b61024f600480803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284375094965061220e95505050505050565b6040518087600160a060020a0316600160a060020a0316815260200180602001806020018660ff1660ff168152602001806020018060200185810385528a8181518152602001915080519060200190808383600083146102ca575b8051825260208311156102ca57601f1990920191602091820191016102aa565b505050905090810190601f1680156102f65780820380516001836020036101000a031916815260200191505b5085810384528951815289516020918201918b01908083838215610335575b80518252602083111561033557601f199092019160209182019101610315565b505050905090810190601f1680156103615780820380516001836020036101000a031916815260200191505b50858103835287518152875160209182019189019080838382156103a0575b8051825260208311156103a057601f199092019160209182019101610380565b505050905090810190601f1680156103cc5780820380516001836020036101000a031916815260200191505b508581038252865181528651602091820191880190808383821561040b575b80518252602083111561040b57601f1990920191602091820191016103eb565b505050905090810190601f1680156104375780820380516001836020036101000a031916815260200191505b509a505050505050505050505060405180910390f35b3415610ab657fe5b610abe6122c1565b6040805160208082528351818301528351919283929083019185810191028083838215610b06575b805182526020831115610b0657601f199092019160209182019101610ae6565b5050509050019250505060405180910390f35b3415610b2157fe5b60408051602060046024803582810135601f81018590048502860185019096528585526100eb958335600160a060020a0316959394604494939290920191819084018382808284375094965061232a95505050505050565b005b3415610b8357fe5b61024f600480803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437509496506124cb95505050505050565b6040518087600160a060020a0316600160a060020a0316815260200180602001806020018660ff1660ff168152602001806020018060200185810385528a8181518152602001915080519060200190808383600083146102ca575b8051825260208311156102ca57601f1990920191602091820191016102aa565b505050905090810190601f1680156102f65780820380516001836020036101000a031916815260200191505b5085810384528951815289516020918201918b01908083838215610335575b80518252602083111561033557601f199092019160209182019101610315565b505050905090810190601f1680156103615780820380516001836020036101000a031916815260200191505b50858103835287518152875160209182019189019080838382156103a0575b8051825260208311156103a057601f199092019160209182019101610380565b505050905090810190601f1680156103cc5780820380516001836020036101000a031916815260200191505b508581038252865181528651602091820191880190808383821561040b575b80518252602083111561040b57601f1990920191602091820191016103eb565b505050905090810190601f1680156104375780820380516001836020036101000a031916815260200191505b509a505050505050505050505060405180910390f35b3415610dd757fe5b60408051602060046024803582810135601f81018590048502860185019096528585526100eb958335600160a060020a0316959394604494939290920191819084018382808284375094965061257e95505050505050565b005b3415610e3957fe5b6100eb600160a060020a03600435166128a4565b005b6000805433600160a060020a03908116911614610e6c5760006000fd5b600160a060020a038084166000908152600160205260409020548491161515610e955760006000fd5b83600160a060020a0316600484815481101515610eae57fe5b906000526020600020900160005b9054600160a060020a036101009290920a90041614610edb5760006000fd5b600480546000198101908110610eed57fe5b906000526020600020900160005b9054906101000a9004600160a060020a0316600484815481101515610f1c57fe5b906000526020600020900160005b6101000a815481600160a060020a030219169083600160a060020a031602179055506001600481818054905003915081610f6491906128f0565b50600160a060020a0380851660009081526001602081815260409283902080546003820154855160ff90911695810186905260a0808252838601805460026000199882161561010002989098011687900491830182905293995091909616957f32c54f1e2ea75844ded7517e7dbcd3895da7cd0c28f9ab9f9cf6ecf5f83762c695929489019360048a019260058b0192918291908201906060830190608084019060c08501908b9080156110595780601f1061102e57610100808354040283529160200191611059565b820191906000526020600020905b81548152906001019060200180831161103c57829003601f168201915b505085810384528954600260001961010060018416150201909116048082526020909101908a9080156110cd5780601f106110a2576101008083540402835291602001916110cd565b820191906000526020600020905b8154815290600101906020018083116110b057829003601f168201915b50508581038352875460026000196101006001841615020190911604808252602090910190889080156111415780601f1061111657610100808354040283529160200191611141565b820191906000526020600020905b81548152906001019060200180831161112457829003601f168201915b50508581038252865460026000196101006001841615020190911604808252602090910190879080156111b55780601f1061118a576101008083540402835291602001916111b5565b820191906000526020600020905b81548152906001019060200180831161119857829003601f168201915b5050995050505050505050505060405180910390a2600282600201604051808280546001816001161561010002031660029004801561122b5780601f1061120957610100808354040283529182019161122b565b820191906000526020600020905b815481529060010190602001808311611217575b5050915050908152602001604051809103902060006101000a815490600160a060020a03021916905560038260010160405180828054600181600116156101000203166002900480156112b55780601f106112935761010080835404028352918201916112b5565b820191906000526020600020905b8154815290600101906020018083116112a1575b5050928352505060408051602092819003830190208054600160a060020a0319908116909155600160a060020a038716600090815260019384905291822080549091168155916113079083018261291a565b61131560028301600061291a565b60038201805460ff1916905561132f60048301600061291a565b61133d60058301600061291a565b50505b5b505b505050565b60006003826040518082805190602001908083835b6020831061137c5780518252601f19909201916020918201910161135d565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054600160a060020a0316925050505b919050565b60006002826040518082805190602001908083835b6020831061137c5780518252601f19909201916020918201910161135d565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054600160a060020a0316925050505b919050565b6000805433600160a060020a0390811691161461144b5760006000fd5b600160a060020a0380841660009081526001602052604090205484911615156114745760006000fd5b600160a060020a0384166000818152600160208181526040928390208351848152600582018054600295811615610100026000190116949094049481018590529096507fc3168fdc13112e44a031057dbf6c609b33353addb4d8037d24543e22cbfe2acd9388928291908201906060830190869080156115355780601f1061150a57610100808354040283529160200191611535565b820191906000526020600020905b81548152906001019060200180831161151857829003601f168201915b505083810382528451815284516020918201918601908083838215611575575b80518252602083111561157557601f199092019160209182019101611555565b505050905090810190601f1680156115a15780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a282516115c590600584019060208601906129aa565b505b5b505b505050565b60006115d9612a29565b6115e1612a29565b60006115eb612a29565b6115f3612a29565b6115fb612a4d565b600160a060020a03888116600090815260016020818152604092839020835160c0810185528154909516855280830180548551600261010096831615969096026000190190911694909404601f8101849004840285018401909552848452909385830193928301828280156116b15780601f10611686576101008083540402835291602001916116b1565b820191906000526020600020905b81548152906001019060200180831161169457829003601f168201915b5050509183525050600282810180546040805160206001841615610100026000190190931694909404601f810183900483028501830190915280845293810193908301828280156117435780601f1061171857610100808354040283529160200191611743565b820191906000526020600020905b81548152906001019060200180831161172657829003601f168201915b5050509183525050600382015460ff1660208083019190915260048301805460408051601f600260001960018616156101000201909416939093049283018590048502810185018252828152940193928301828280156117e45780601f106117b9576101008083540402835291602001916117e4565b820191906000526020600020905b8154815290600101906020018083116117c757829003601f168201915b505050918352505060058201805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529382019392918301828280156118785780601f1061184d57610100808354040283529160200191611878565b820191906000526020600020905b81548152906001019060200180831161185b57829003601f168201915b5050509190925250508151602083015160408401516060850151608086015160a0870151949d50929b50909950975095509350909150505b5091939550919395565b600054600160a060020a031681565b60005433600160a060020a039081169116146118e55760006000fd5b600160a060020a038087166000908152600160205260409020548791161561190d5760006000fd5b86600160a060020a03811615156119245760006000fd5b856000600160a060020a03166002826040518082805190602001908083835b602083106119625780518252601f199092019160209182019101611943565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054600160a060020a03169290921491506119a990505760006000fd5b876000600160a060020a03166003826040518082805190602001908083835b602083106119e75780518252601f1990920191602091820191016119c8565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054600160a060020a0316929092149150611a2e90505760006000fd5b6040805160c081018252600160a060020a038c811680835260208084018e81528486018e905260ff8d166060860152608085018c905260a085018b9052600092835260018083529590922084518154600160a060020a03191694169390931783559051805193949293611aa89385019291909101906129aa565b5060408201518051611ac49160028401916020909101906129aa565b50606082015160038201805460ff191660ff90921691909117905560808201518051611afa9160048401916020909101906129aa565b5060a08201518051611b169160058401916020909101906129aa565b50506004805490915060018101611b2d83826128f0565b916000526020600020900160005b8c909190916101000a815481600160a060020a030219169083600160a060020a0316021790555050896002896040518082805190602001908083835b60208310611b965780518252601f199092019160209182019101611b77565b51815160209384036101000a600019018019909216911617905292019485525060405193849003810184208054600160a060020a031916600160a060020a03969096169590951790945550508a518c926003928d9290918291908401908083835b60208310611c165780518252601f199092019160209182019101611bf7565b51815160209384036101000a60001901801990921691161790529201948552506040805194859003820185208054600160a060020a031916600160a060020a0397881617905560ff8d169085015260a08085528e51908501528d51948f16947fd8d928b0b50ca11d9dc273236b46f3526515b03602f71f3a6af4f45bd9fa9144948f94508e93508d928d928d92918291828201916060840191608085019160c0860191908c01908083838215611ce7575b805182526020831115611ce757601f199092019160209182019101611cc7565b505050905090810190601f168015611d135780820380516001836020036101000a031916815260200191505b5085810384528951815289516020918201918b01908083838215611d52575b805182526020831115611d5257601f199092019160209182019101611d32565b505050905090810190601f168015611d7e5780820380516001836020036101000a031916815260200191505b5085810383528751815287516020918201918901908083838215611dbd575b805182526020831115611dbd57601f199092019160209182019101611d9d565b505050905090810190601f168015611de95780820380516001836020036101000a031916815260200191505b5085810382528651815286516020918201918801908083838215611e28575b805182526020831115611e2857601f199092019160209182019101611e08565b505050905090810190601f168015611e545780820380516001836020036101000a031916815260200191505b50995050505050505050505060405180910390a25b5b505b505b505b505b505050505050565b6000805433600160a060020a03908116911614611e975760006000fd5b600160a060020a038084166000908152600160205260409020548491161515611ec05760006000fd5b826000600160a060020a03166003826040518082805190602001908083835b60208310611efe5780518252601f199092019160209182019101611edf565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054600160a060020a0316929092149150611f4590505760006000fd5b600160a060020a03851660008181526001602081815260409283902083518481528184018054600295811615610100026000190116949094049481018590529097507f4a6dbfc867b179991dec22ff19960f0a94d8d9d891fc556f547764670340e8ae9389928291908201906060830190869080156120055780601f10611fda57610100808354040283529160200191612005565b820191906000526020600020905b815481529060010190602001808311611fe857829003601f168201915b505083810382528451815284516020918201918601908083838215612045575b80518252602083111561204557601f199092019160209182019101612025565b505050905090810190601f1680156120715780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a260038360010160405180828054600181600116156101000203166002900480156120e15780601f106120bf5761010080835404028352918201916120e1565b820191906000526020600020905b8154815290600101906020018083116120cd575b5050928352505060405190819003602090810182208054600160a060020a031916905585518792600392889282918401908083835b602083106121355780518252601f199092019160209182019101612116565b51815160209384036101000a60001901801990921691161790529201948552506040519384900381019093208054600160a060020a031916600160a060020a03959095169490941790935550855161133d925060018601918701906129aa565b505b5b505b505b505050565b600160208190526000918252604090912080546003820154600160a060020a0390911692820191600281019160ff1690600481019060050186565b60048054829081106121ea57fe5b906000526020600020900160005b915054906101000a9004600160a060020a031681565b6000612218612a29565b612220612a29565b600061222a612a29565b612232612a29565b60006003886040518082805190602001908083835b602083106122665780518252601f199092019160209182019101612247565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054600160a060020a031692506122aa91508290506115cf565b9650965096509650965096505b5091939550919395565b6122c9612a29565b600480548060200260200160405190810160405280929190818152602001828054801561231f57602002820191906000526020600020905b8154600160a060020a03168152600190910190602001808311612301575b505050505090505b90565b6000805433600160a060020a039081169116146123475760006000fd5b600160a060020a0380841660009081526001602052604090205484911615156123705760006000fd5b600160a060020a0384166000818152600160208181526040928390208351848152600482018054600295811615610100026000190116949094049481018590529096507f5b19f79ac4e8cfa820815502e11615f1a449e28155dc289ec5cac1a11f9086949388928291908201906060830190869080156124315780601f1061240657610100808354040283529160200191612431565b820191906000526020600020905b81548152906001019060200180831161241457829003601f168201915b505083810382528451815284516020918201918601908083838215612471575b80518252602083111561247157601f199092019160209182019101612451565b505050905090810190601f16801561249d5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a282516115c590600484019060208601906129aa565b505b5b505b505050565b60006124d5612a29565b6124dd612a29565b60006124e7612a29565b6124ef612a29565b60006002886040518082805190602001908083835b602083106122665780518252601f199092019160209182019101612247565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054600160a060020a031692506122aa91508290506115cf565b9650965096509650965096505b5091939550919395565b6000805433600160a060020a0390811691161461259b5760006000fd5b600160a060020a0380841660009081526001602052604090205484911615156125c45760006000fd5b826000600160a060020a03166002826040518082805190602001908083835b602083106126025780518252601f1990920191602091820191016125e3565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054600160a060020a031692909214915061264990505760006000fd5b600160a060020a038516600081815260016020818152604092839020835184815260028083018054958616156101000260001901909516049481018590529097507f53d878a6530e56c9bc96548fa0a8cae4f1d1f49c86b0e934c086b992ebb6998f9389928291908201906060830190869080156127085780601f106126dd57610100808354040283529160200191612708565b820191906000526020600020905b8154815290600101906020018083116126eb57829003601f168201915b505083810382528451815284516020918201918601908083838215612748575b80518252602083111561274857601f199092019160209182019101612728565b505050905090810190601f1680156127745780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a260028360020160405180828054600181600116156101000203166002900480156127e45780601f106127c25761010080835404028352918201916127e4565b820191906000526020600020905b8154815290600101906020018083116127d0575b5050928352505060405190819003602090810182208054600160a060020a031916905585518792600292889282918401908083835b602083106128385780518252601f199092019160209182019101612819565b51815160209384036101000a60001901801990921691161790529201948552506040519384900381019093208054600160a060020a031916600160a060020a03959095169490941790935550855161133d925060028601918701906129aa565b505b5b505b505b505050565b60005433600160a060020a039081169116146128c05760006000fd5b600160a060020a038116156128eb5760008054600160a060020a031916600160a060020a0383161790555b5b5b50565b81548183558181151161134357600083815260209020611343918101908301612c54565b5b505050565b50805460018160011615610100020316600290046000825580601f1061294057506128eb565b601f0160209004906000526020600020908101906128eb9190612c54565b5b50565b50805460018160011615610100020316600290046000825580601f1061294057506128eb565b601f0160209004906000526020600020908101906128eb9190612c54565b5b50565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106129eb57805160ff1916838001178555612a18565b82800160010185558215612a18579182015b82811115612a185782518255916020019190600101906129fd565b5b50612a25929150612c54565b5090565b60408051602081019091526000815290565b60408051602081019091526000815290565b6040805160c081019091526000815260208101612a68612a29565b8152602001612a75612a29565b815260006020820152604001612a89612a29565b8152602001612a96612a29565b905290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106129eb57805160ff1916838001178555612a18565b82800160010185558215612a18579182015b82811115612a185782518255916020019190600101906129fd565b5b50612a25929150612c54565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106129eb57805160ff1916838001178555612a18565b82800160010185558215612a18579182015b82811115612a185782518255916020019190600101906129fd565b5b50612a25929150612c54565b5090565b81548183558181151161134357600083815260209020611343918101908301612c54565b5b505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106129eb57805160ff1916838001178555612a18565b82800160010185558215612a18579182015b82811115612a185782518255916020019190600101906129fd565b5b50612a25929150612c54565b5090565b60408051602081019091526000815290565b61232791905b80821115612a255760008155600101612c5a565b5090565b90565b60408051602081019091526000815290565b604080516020810190915260008152905600a165627a7a723058202e91668072bb23c9d4066cdaabf7329783952016e7a08006744ebe0d0eb96f5d0029", + "unlinked_binary": "0x60606040525b60008054600160a060020a03191633600160a060020a03161790555b5b612cc5806100316000396000f300606060405236156100ca5763ffffffff60e060020a60003504166313baf1e681146100cc5780632fbfeba9146100ed5780633550b6d91461015f57806356318820146101d15780637abccac9146102335780638da5cb5b1461044d578063a880319d14610479578063c370c86d1461059a578063e4860339146105fc578063e5df8b841461082b578063e73fc0c31461085a578063ee8c24b814610aae578063eef05f6514610b19578063efa74f1f14610b7b578063f036417f14610dcf578063f2fde38b14610e31575bfe5b34156100d457fe5b6100eb600160a060020a0360043516602435610e4f565b005b34156100f557fe5b610143600480803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284375094965061134895505050505050565b60408051600160a060020a039092168252519081900360200190f35b341561016757fe5b610143600480803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437509496506113bb95505050505050565b60408051600160a060020a039092168252519081900360200190f35b34156101d957fe5b60408051602060046024803582810135601f81018590048502860185019096528585526100eb958335600160a060020a0316959394604494939290920191819084018382808284375094965061142e95505050505050565b005b341561023b57fe5b61024f600160a060020a03600435166115cf565b6040518087600160a060020a0316600160a060020a0316815260200180602001806020018660ff1660ff168152602001806020018060200185810385528a8181518152602001915080519060200190808383600083146102ca575b8051825260208311156102ca57601f1990920191602091820191016102aa565b505050905090810190601f1680156102f65780820380516001836020036101000a031916815260200191505b5085810384528951815289516020918201918b01908083838215610335575b80518252602083111561033557601f199092019160209182019101610315565b505050905090810190601f1680156103615780820380516001836020036101000a031916815260200191505b50858103835287518152875160209182019189019080838382156103a0575b8051825260208311156103a057601f199092019160209182019101610380565b505050905090810190601f1680156103cc5780820380516001836020036101000a031916815260200191505b508581038252865181528651602091820191880190808383821561040b575b80518252602083111561040b57601f1990920191602091820191016103eb565b505050905090810190601f1680156104375780820380516001836020036101000a031916815260200191505b509a505050505050505050505060405180910390f35b341561045557fe5b6101436118ba565b60408051600160a060020a039092168252519081900360200190f35b341561048157fe5b60408051602060046024803582810135601f81018590048502860185019096528585526100eb958335600160a060020a0316959394604494939290920191819084018382808284375050604080516020601f89358b0180359182018390048302840183019094528083529799988101979196509182019450925082915084018382808284375050604080516020601f818a01358b0180359182018390048302840183018552818452989a60ff8b35169a90999401975091955091820193509150819084018382808284375050604080516020601f89358b018035918201839004830284018301909452808352979998810197919650918201945092508291508401838280828437509496506118c995505050505050565b005b34156105a257fe5b60408051602060046024803582810135601f81018590048502860185019096528585526100eb958335600160a060020a03169593946044949392909201918190840183828082843750949650611e7a95505050505050565b005b341561060457fe5b610618600160a060020a03600435166121a1565b60408051600160a060020a038816815260ff8516606082015260c0602082018181528854600260001961010060018416150201909116049183018290529192830190608084019060a085019060e08601908b9080156106b85780601f1061068d576101008083540402835291602001916106b8565b820191906000526020600020905b81548152906001019060200180831161069b57829003601f168201915b505085810384528954600260001961010060018416150201909116048082526020909101908a90801561072c5780601f106107015761010080835404028352916020019161072c565b820191906000526020600020905b81548152906001019060200180831161070f57829003601f168201915b50508581038352875460026000196101006001841615020190911604808252602090910190889080156107a05780601f10610775576101008083540402835291602001916107a0565b820191906000526020600020905b81548152906001019060200180831161078357829003601f168201915b50508581038252865460026000196101006001841615020190911604808252602090910190879080156108145780601f106107e957610100808354040283529160200191610814565b820191906000526020600020905b8154815290600101906020018083116107f757829003601f168201915b50509a505050505050505050505060405180910390f35b341561083357fe5b6101436004356121dc565b60408051600160a060020a039092168252519081900360200190f35b341561086257fe5b61024f600480803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284375094965061220e95505050505050565b6040518087600160a060020a0316600160a060020a0316815260200180602001806020018660ff1660ff168152602001806020018060200185810385528a8181518152602001915080519060200190808383600083146102ca575b8051825260208311156102ca57601f1990920191602091820191016102aa565b505050905090810190601f1680156102f65780820380516001836020036101000a031916815260200191505b5085810384528951815289516020918201918b01908083838215610335575b80518252602083111561033557601f199092019160209182019101610315565b505050905090810190601f1680156103615780820380516001836020036101000a031916815260200191505b50858103835287518152875160209182019189019080838382156103a0575b8051825260208311156103a057601f199092019160209182019101610380565b505050905090810190601f1680156103cc5780820380516001836020036101000a031916815260200191505b508581038252865181528651602091820191880190808383821561040b575b80518252602083111561040b57601f1990920191602091820191016103eb565b505050905090810190601f1680156104375780820380516001836020036101000a031916815260200191505b509a505050505050505050505060405180910390f35b3415610ab657fe5b610abe6122c1565b6040805160208082528351818301528351919283929083019185810191028083838215610b06575b805182526020831115610b0657601f199092019160209182019101610ae6565b5050509050019250505060405180910390f35b3415610b2157fe5b60408051602060046024803582810135601f81018590048502860185019096528585526100eb958335600160a060020a0316959394604494939290920191819084018382808284375094965061232a95505050505050565b005b3415610b8357fe5b61024f600480803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437509496506124cb95505050505050565b6040518087600160a060020a0316600160a060020a0316815260200180602001806020018660ff1660ff168152602001806020018060200185810385528a8181518152602001915080519060200190808383600083146102ca575b8051825260208311156102ca57601f1990920191602091820191016102aa565b505050905090810190601f1680156102f65780820380516001836020036101000a031916815260200191505b5085810384528951815289516020918201918b01908083838215610335575b80518252602083111561033557601f199092019160209182019101610315565b505050905090810190601f1680156103615780820380516001836020036101000a031916815260200191505b50858103835287518152875160209182019189019080838382156103a0575b8051825260208311156103a057601f199092019160209182019101610380565b505050905090810190601f1680156103cc5780820380516001836020036101000a031916815260200191505b508581038252865181528651602091820191880190808383821561040b575b80518252602083111561040b57601f1990920191602091820191016103eb565b505050905090810190601f1680156104375780820380516001836020036101000a031916815260200191505b509a505050505050505050505060405180910390f35b3415610dd757fe5b60408051602060046024803582810135601f81018590048502860185019096528585526100eb958335600160a060020a0316959394604494939290920191819084018382808284375094965061257e95505050505050565b005b3415610e3957fe5b6100eb600160a060020a03600435166128a4565b005b6000805433600160a060020a03908116911614610e6c5760006000fd5b600160a060020a038084166000908152600160205260409020548491161515610e955760006000fd5b83600160a060020a0316600484815481101515610eae57fe5b906000526020600020900160005b9054600160a060020a036101009290920a90041614610edb5760006000fd5b600480546000198101908110610eed57fe5b906000526020600020900160005b9054906101000a9004600160a060020a0316600484815481101515610f1c57fe5b906000526020600020900160005b6101000a815481600160a060020a030219169083600160a060020a031602179055506001600481818054905003915081610f6491906128f0565b50600160a060020a0380851660009081526001602081815260409283902080546003820154855160ff90911695810186905260a0808252838601805460026000199882161561010002989098011687900491830182905293995091909616957f32c54f1e2ea75844ded7517e7dbcd3895da7cd0c28f9ab9f9cf6ecf5f83762c695929489019360048a019260058b0192918291908201906060830190608084019060c08501908b9080156110595780601f1061102e57610100808354040283529160200191611059565b820191906000526020600020905b81548152906001019060200180831161103c57829003601f168201915b505085810384528954600260001961010060018416150201909116048082526020909101908a9080156110cd5780601f106110a2576101008083540402835291602001916110cd565b820191906000526020600020905b8154815290600101906020018083116110b057829003601f168201915b50508581038352875460026000196101006001841615020190911604808252602090910190889080156111415780601f1061111657610100808354040283529160200191611141565b820191906000526020600020905b81548152906001019060200180831161112457829003601f168201915b50508581038252865460026000196101006001841615020190911604808252602090910190879080156111b55780601f1061118a576101008083540402835291602001916111b5565b820191906000526020600020905b81548152906001019060200180831161119857829003601f168201915b5050995050505050505050505060405180910390a2600282600201604051808280546001816001161561010002031660029004801561122b5780601f1061120957610100808354040283529182019161122b565b820191906000526020600020905b815481529060010190602001808311611217575b5050915050908152602001604051809103902060006101000a815490600160a060020a03021916905560038260010160405180828054600181600116156101000203166002900480156112b55780601f106112935761010080835404028352918201916112b5565b820191906000526020600020905b8154815290600101906020018083116112a1575b5050928352505060408051602092819003830190208054600160a060020a0319908116909155600160a060020a038716600090815260019384905291822080549091168155916113079083018261291a565b61131560028301600061291a565b60038201805460ff1916905561132f60048301600061291a565b61133d60058301600061291a565b50505b5b505b505050565b60006003826040518082805190602001908083835b6020831061137c5780518252601f19909201916020918201910161135d565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054600160a060020a0316925050505b919050565b60006002826040518082805190602001908083835b6020831061137c5780518252601f19909201916020918201910161135d565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054600160a060020a0316925050505b919050565b6000805433600160a060020a0390811691161461144b5760006000fd5b600160a060020a0380841660009081526001602052604090205484911615156114745760006000fd5b600160a060020a0384166000818152600160208181526040928390208351848152600582018054600295811615610100026000190116949094049481018590529096507fc3168fdc13112e44a031057dbf6c609b33353addb4d8037d24543e22cbfe2acd9388928291908201906060830190869080156115355780601f1061150a57610100808354040283529160200191611535565b820191906000526020600020905b81548152906001019060200180831161151857829003601f168201915b505083810382528451815284516020918201918601908083838215611575575b80518252602083111561157557601f199092019160209182019101611555565b505050905090810190601f1680156115a15780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a282516115c590600584019060208601906129aa565b505b5b505b505050565b60006115d9612a29565b6115e1612a29565b60006115eb612a29565b6115f3612a29565b6115fb612a4d565b600160a060020a03888116600090815260016020818152604092839020835160c0810185528154909516855280830180548551600261010096831615969096026000190190911694909404601f8101849004840285018401909552848452909385830193928301828280156116b15780601f10611686576101008083540402835291602001916116b1565b820191906000526020600020905b81548152906001019060200180831161169457829003601f168201915b5050509183525050600282810180546040805160206001841615610100026000190190931694909404601f810183900483028501830190915280845293810193908301828280156117435780601f1061171857610100808354040283529160200191611743565b820191906000526020600020905b81548152906001019060200180831161172657829003601f168201915b5050509183525050600382015460ff1660208083019190915260048301805460408051601f600260001960018616156101000201909416939093049283018590048502810185018252828152940193928301828280156117e45780601f106117b9576101008083540402835291602001916117e4565b820191906000526020600020905b8154815290600101906020018083116117c757829003601f168201915b505050918352505060058201805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529382019392918301828280156118785780601f1061184d57610100808354040283529160200191611878565b820191906000526020600020905b81548152906001019060200180831161185b57829003601f168201915b5050509190925250508151602083015160408401516060850151608086015160a0870151949d50929b50909950975095509350909150505b5091939550919395565b600054600160a060020a031681565b60005433600160a060020a039081169116146118e55760006000fd5b600160a060020a038087166000908152600160205260409020548791161561190d5760006000fd5b86600160a060020a03811615156119245760006000fd5b856000600160a060020a03166002826040518082805190602001908083835b602083106119625780518252601f199092019160209182019101611943565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054600160a060020a03169290921491506119a990505760006000fd5b876000600160a060020a03166003826040518082805190602001908083835b602083106119e75780518252601f1990920191602091820191016119c8565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054600160a060020a0316929092149150611a2e90505760006000fd5b6040805160c081018252600160a060020a038c811680835260208084018e81528486018e905260ff8d166060860152608085018c905260a085018b9052600092835260018083529590922084518154600160a060020a03191694169390931783559051805193949293611aa89385019291909101906129aa565b5060408201518051611ac49160028401916020909101906129aa565b50606082015160038201805460ff191660ff90921691909117905560808201518051611afa9160048401916020909101906129aa565b5060a08201518051611b169160058401916020909101906129aa565b50506004805490915060018101611b2d83826128f0565b916000526020600020900160005b8c909190916101000a815481600160a060020a030219169083600160a060020a0316021790555050896002896040518082805190602001908083835b60208310611b965780518252601f199092019160209182019101611b77565b51815160209384036101000a600019018019909216911617905292019485525060405193849003810184208054600160a060020a031916600160a060020a03969096169590951790945550508a518c926003928d9290918291908401908083835b60208310611c165780518252601f199092019160209182019101611bf7565b51815160209384036101000a60001901801990921691161790529201948552506040805194859003820185208054600160a060020a031916600160a060020a0397881617905560ff8d169085015260a08085528e51908501528d51948f16947fd8d928b0b50ca11d9dc273236b46f3526515b03602f71f3a6af4f45bd9fa9144948f94508e93508d928d928d92918291828201916060840191608085019160c0860191908c01908083838215611ce7575b805182526020831115611ce757601f199092019160209182019101611cc7565b505050905090810190601f168015611d135780820380516001836020036101000a031916815260200191505b5085810384528951815289516020918201918b01908083838215611d52575b805182526020831115611d5257601f199092019160209182019101611d32565b505050905090810190601f168015611d7e5780820380516001836020036101000a031916815260200191505b5085810383528751815287516020918201918901908083838215611dbd575b805182526020831115611dbd57601f199092019160209182019101611d9d565b505050905090810190601f168015611de95780820380516001836020036101000a031916815260200191505b5085810382528651815286516020918201918801908083838215611e28575b805182526020831115611e2857601f199092019160209182019101611e08565b505050905090810190601f168015611e545780820380516001836020036101000a031916815260200191505b50995050505050505050505060405180910390a25b5b505b505b505b505b505050505050565b6000805433600160a060020a03908116911614611e975760006000fd5b600160a060020a038084166000908152600160205260409020548491161515611ec05760006000fd5b826000600160a060020a03166003826040518082805190602001908083835b60208310611efe5780518252601f199092019160209182019101611edf565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054600160a060020a0316929092149150611f4590505760006000fd5b600160a060020a03851660008181526001602081815260409283902083518481528184018054600295811615610100026000190116949094049481018590529097507f4a6dbfc867b179991dec22ff19960f0a94d8d9d891fc556f547764670340e8ae9389928291908201906060830190869080156120055780601f10611fda57610100808354040283529160200191612005565b820191906000526020600020905b815481529060010190602001808311611fe857829003601f168201915b505083810382528451815284516020918201918601908083838215612045575b80518252602083111561204557601f199092019160209182019101612025565b505050905090810190601f1680156120715780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a260038360010160405180828054600181600116156101000203166002900480156120e15780601f106120bf5761010080835404028352918201916120e1565b820191906000526020600020905b8154815290600101906020018083116120cd575b5050928352505060405190819003602090810182208054600160a060020a031916905585518792600392889282918401908083835b602083106121355780518252601f199092019160209182019101612116565b51815160209384036101000a60001901801990921691161790529201948552506040519384900381019093208054600160a060020a031916600160a060020a03959095169490941790935550855161133d925060018601918701906129aa565b505b5b505b505b505050565b600160208190526000918252604090912080546003820154600160a060020a0390911692820191600281019160ff1690600481019060050186565b60048054829081106121ea57fe5b906000526020600020900160005b915054906101000a9004600160a060020a031681565b6000612218612a29565b612220612a29565b600061222a612a29565b612232612a29565b60006003886040518082805190602001908083835b602083106122665780518252601f199092019160209182019101612247565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054600160a060020a031692506122aa91508290506115cf565b9650965096509650965096505b5091939550919395565b6122c9612a29565b600480548060200260200160405190810160405280929190818152602001828054801561231f57602002820191906000526020600020905b8154600160a060020a03168152600190910190602001808311612301575b505050505090505b90565b6000805433600160a060020a039081169116146123475760006000fd5b600160a060020a0380841660009081526001602052604090205484911615156123705760006000fd5b600160a060020a0384166000818152600160208181526040928390208351848152600482018054600295811615610100026000190116949094049481018590529096507f5b19f79ac4e8cfa820815502e11615f1a449e28155dc289ec5cac1a11f9086949388928291908201906060830190869080156124315780601f1061240657610100808354040283529160200191612431565b820191906000526020600020905b81548152906001019060200180831161241457829003601f168201915b505083810382528451815284516020918201918601908083838215612471575b80518252602083111561247157601f199092019160209182019101612451565b505050905090810190601f16801561249d5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a282516115c590600484019060208601906129aa565b505b5b505b505050565b60006124d5612a29565b6124dd612a29565b60006124e7612a29565b6124ef612a29565b60006002886040518082805190602001908083835b602083106122665780518252601f199092019160209182019101612247565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054600160a060020a031692506122aa91508290506115cf565b9650965096509650965096505b5091939550919395565b6000805433600160a060020a0390811691161461259b5760006000fd5b600160a060020a0380841660009081526001602052604090205484911615156125c45760006000fd5b826000600160a060020a03166002826040518082805190602001908083835b602083106126025780518252601f1990920191602091820191016125e3565b51815160209384036101000a6000190180199092169116179052920194855250604051938490030190922054600160a060020a031692909214915061264990505760006000fd5b600160a060020a038516600081815260016020818152604092839020835184815260028083018054958616156101000260001901909516049481018590529097507f53d878a6530e56c9bc96548fa0a8cae4f1d1f49c86b0e934c086b992ebb6998f9389928291908201906060830190869080156127085780601f106126dd57610100808354040283529160200191612708565b820191906000526020600020905b8154815290600101906020018083116126eb57829003601f168201915b505083810382528451815284516020918201918601908083838215612748575b80518252602083111561274857601f199092019160209182019101612728565b505050905090810190601f1680156127745780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a260028360020160405180828054600181600116156101000203166002900480156127e45780601f106127c25761010080835404028352918201916127e4565b820191906000526020600020905b8154815290600101906020018083116127d0575b5050928352505060405190819003602090810182208054600160a060020a031916905585518792600292889282918401908083835b602083106128385780518252601f199092019160209182019101612819565b51815160209384036101000a60001901801990921691161790529201948552506040519384900381019093208054600160a060020a031916600160a060020a03959095169490941790935550855161133d925060028601918701906129aa565b505b5b505b505b505050565b60005433600160a060020a039081169116146128c05760006000fd5b600160a060020a038116156128eb5760008054600160a060020a031916600160a060020a0383161790555b5b5b50565b81548183558181151161134357600083815260209020611343918101908301612c54565b5b505050565b50805460018160011615610100020316600290046000825580601f1061294057506128eb565b601f0160209004906000526020600020908101906128eb9190612c54565b5b50565b50805460018160011615610100020316600290046000825580601f1061294057506128eb565b601f0160209004906000526020600020908101906128eb9190612c54565b5b50565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106129eb57805160ff1916838001178555612a18565b82800160010185558215612a18579182015b82811115612a185782518255916020019190600101906129fd565b5b50612a25929150612c54565b5090565b60408051602081019091526000815290565b60408051602081019091526000815290565b6040805160c081019091526000815260208101612a68612a29565b8152602001612a75612a29565b815260006020820152604001612a89612a29565b8152602001612a96612a29565b905290565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106129eb57805160ff1916838001178555612a18565b82800160010185558215612a18579182015b82811115612a185782518255916020019190600101906129fd565b5b50612a25929150612c54565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106129eb57805160ff1916838001178555612a18565b82800160010185558215612a18579182015b82811115612a185782518255916020019190600101906129fd565b5b50612a25929150612c54565b5090565b81548183558181151161134357600083815260209020611343918101908301612c54565b5b505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106129eb57805160ff1916838001178555612a18565b82800160010185558215612a18579182015b82811115612a185782518255916020019190600101906129fd565b5b50612a25929150612c54565b5090565b60408051602081019091526000815290565b61232791905b80821115612a255760008155600101612c5a565b5090565b90565b60408051602081019091526000815290565b604080516020810190915260008152905600a165627a7a72305820eea167af82f9fa569e6816bc55cad0ce2239725a9d14f6aa5372ae5c886835ae0029", "networks": { - "50": { + "1": { "links": {}, "events": { "0xd8d928b0b50ca11d9dc273236b46f3526515b03602f71f3a6af4f45bd9fa9144": { @@ -695,8 +695,8 @@ "type": "event" } }, - "updated_at": 1502391794385, - "address": "0xf7c37d12f3355d052ef9ca60131118af615f5653" + "updated_at": 1502488442000, + "address": "0x926a74c5c36adf004c87399e65f75628b0f98d2c" }, "42": { "links": {}, @@ -867,7 +867,7 @@ "updated_at": 1502391794385, "address": "0xf18e504561f4347bea557f3d4558f559dddbae7f" }, - "1": { + "50": { "links": {}, "events": { "0xd8d928b0b50ca11d9dc273236b46f3526515b03602f71f3a6af4f45bd9fa9144": { @@ -1033,10 +1033,10 @@ "type": "event" } }, - "updated_at": 1502488442000, - "address": "0x926a74c5c36adf004c87399e65f75628b0f98d2c" + "updated_at": 1513088404203, + "address": "0x0b1ba0af832d7c05fd64161e0db78e85978e8082" } }, "schema_version": "0.0.5", - "updated_at": 1502391794385 -} + "updated_at": 1513088404203 +}
\ No newline at end of file diff --git a/packages/contracts/build/contracts/TokenTransferProxy.json b/packages/contracts/build/contracts/TokenTransferProxy.json index dc2c13f0c..4dd37f0bc 100644 --- a/packages/contracts/build/contracts/TokenTransferProxy.json +++ b/packages/contracts/build/contracts/TokenTransferProxy.json @@ -167,9 +167,9 @@ "type": "event" } ], - "unlinked_binary": "0x60606040525b60008054600160a060020a03191633600160a060020a03161790555b5b6106e6806100316000396000f300606060405236156100725763ffffffff60e060020a60003504166315dacbea811461007457806342f1181e146100b3578063494503d4146100d157806370712939146101005780638da5cb5b1461011e578063b91816111461014a578063d39de6e91461017a578063f2fde38b146101e5575bfe5b341561007c57fe5b61009f600160a060020a0360043581169060243581169060443516606435610203565b604080519115158252519081900360200190f35b34156100bb57fe5b6100cf600160a060020a03600435166102ae565b005b34156100d957fe5b6100e4600435610390565b60408051600160a060020a039092168252519081900360200190f35b341561010857fe5b6100cf600160a060020a03600435166103c2565b005b341561012657fe5b6100e461055a565b60408051600160a060020a039092168252519081900360200190f35b341561015257fe5b61009f600160a060020a0360043516610569565b604080519115158252519081900360200190f35b341561018257fe5b61018a61057e565b60408051602080825283518183015283519192839290830191858101910280838382156101d2575b8051825260208311156101d257601f1990920191602091820191016101b2565b5050509050019250505060405180910390f35b34156101ed57fe5b6100cf600160a060020a03600435166105e7565b005b600160a060020a03331660009081526001602052604081205460ff16151561022b5760006000fd5b6040805160006020918201819052825160e060020a6323b872dd028152600160a060020a0388811660048301528781166024830152604482018790529351938916936323b872dd9360648084019491938390030190829087803b151561028d57fe5b6102c65a03f1151561029b57fe5b5050604051519150505b5b949350505050565b60005433600160a060020a039081169116146102ca5760006000fd5b600160a060020a038116600090815260016020526040902054819060ff16156102f35760006000fd5b600160a060020a0382166000908152600160208190526040909120805460ff191682179055600280549091810161032a8382610633565b916000526020600020900160005b81546101009190910a600160a060020a0381810219909216868316918202179092556040513390911692507f94bb87f4c15c4587ff559a7584006fa01ddf9299359be6b512b94527aa961aca90600090a35b5b505b50565b600280548290811061039e57fe5b906000526020600020900160005b915054906101000a9004600160a060020a031681565b6000805433600160a060020a039081169116146103df5760006000fd5b600160a060020a038216600090815260016020526040902054829060ff1615156104095760006000fd5b600160a060020a0383166000908152600160205260408120805460ff1916905591505b6002548210156105195782600160a060020a031660028381548110151561044f57fe5b906000526020600020900160005b9054906101000a9004600160a060020a0316600160a060020a0316141561050d5760028054600019810190811061049057fe5b906000526020600020900160005b9054906101000a9004600160a060020a03166002838154811015156104bf57fe5b906000526020600020900160005b6101000a815481600160a060020a030219169083600160a060020a0316021790555060016002818180549050039150816105079190610633565b50610519565b5b60019091019061042c565b604051600160a060020a0333811691908516907ff5b347a1e40749dd050f5f07fbdbeb7e3efa9756903044dd29401fd1d4bb4a1c90600090a35b5b505b5050565b600054600160a060020a031681565b60016020526000908152604090205460ff1681565b610586610687565b60028054806020026020016040519081016040528092919081815260200182805480156105dc57602002820191906000526020600020905b8154600160a060020a031681526001909101906020018083116105be575b505050505090505b90565b60005433600160a060020a039081169116146106035760006000fd5b600160a060020a0381161561038d5760008054600160a060020a031916600160a060020a0383161790555b5b5b50565b81548183558181151161055357600083815260209020610553918101908301610699565b5b505050565b81548183558181151161055357600083815260209020610553918101908301610699565b5b505050565b60408051602081019091526000815290565b6105e491905b808211156106b3576000815560010161069f565b5090565b905600a165627a7a723058200355c2e534da7274d090b5a2209d5fbe4679ee2760a73c55c16e6d0ff1af016c0029", + "unlinked_binary": "0x60606040525b60008054600160a060020a03191633600160a060020a03161790555b5b6106e6806100316000396000f300606060405236156100725763ffffffff60e060020a60003504166315dacbea811461007457806342f1181e146100b3578063494503d4146100d157806370712939146101005780638da5cb5b1461011e578063b91816111461014a578063d39de6e91461017a578063f2fde38b146101e5575bfe5b341561007c57fe5b61009f600160a060020a0360043581169060243581169060443516606435610203565b604080519115158252519081900360200190f35b34156100bb57fe5b6100cf600160a060020a03600435166102ae565b005b34156100d957fe5b6100e4600435610390565b60408051600160a060020a039092168252519081900360200190f35b341561010857fe5b6100cf600160a060020a03600435166103c2565b005b341561012657fe5b6100e461055a565b60408051600160a060020a039092168252519081900360200190f35b341561015257fe5b61009f600160a060020a0360043516610569565b604080519115158252519081900360200190f35b341561018257fe5b61018a61057e565b60408051602080825283518183015283519192839290830191858101910280838382156101d2575b8051825260208311156101d257601f1990920191602091820191016101b2565b5050509050019250505060405180910390f35b34156101ed57fe5b6100cf600160a060020a03600435166105e7565b005b600160a060020a03331660009081526001602052604081205460ff16151561022b5760006000fd5b6040805160006020918201819052825160e060020a6323b872dd028152600160a060020a0388811660048301528781166024830152604482018790529351938916936323b872dd9360648084019491938390030190829087803b151561028d57fe5b6102c65a03f1151561029b57fe5b5050604051519150505b5b949350505050565b60005433600160a060020a039081169116146102ca5760006000fd5b600160a060020a038116600090815260016020526040902054819060ff16156102f35760006000fd5b600160a060020a0382166000908152600160208190526040909120805460ff191682179055600280549091810161032a8382610633565b916000526020600020900160005b81546101009190910a600160a060020a0381810219909216868316918202179092556040513390911692507f94bb87f4c15c4587ff559a7584006fa01ddf9299359be6b512b94527aa961aca90600090a35b5b505b50565b600280548290811061039e57fe5b906000526020600020900160005b915054906101000a9004600160a060020a031681565b6000805433600160a060020a039081169116146103df5760006000fd5b600160a060020a038216600090815260016020526040902054829060ff1615156104095760006000fd5b600160a060020a0383166000908152600160205260408120805460ff1916905591505b6002548210156105195782600160a060020a031660028381548110151561044f57fe5b906000526020600020900160005b9054906101000a9004600160a060020a0316600160a060020a0316141561050d5760028054600019810190811061049057fe5b906000526020600020900160005b9054906101000a9004600160a060020a03166002838154811015156104bf57fe5b906000526020600020900160005b6101000a815481600160a060020a030219169083600160a060020a0316021790555060016002818180549050039150816105079190610633565b50610519565b5b60019091019061042c565b604051600160a060020a0333811691908516907ff5b347a1e40749dd050f5f07fbdbeb7e3efa9756903044dd29401fd1d4bb4a1c90600090a35b5b505b5050565b600054600160a060020a031681565b60016020526000908152604090205460ff1681565b610586610687565b60028054806020026020016040519081016040528092919081815260200182805480156105dc57602002820191906000526020600020905b8154600160a060020a031681526001909101906020018083116105be575b505050505090505b90565b60005433600160a060020a039081169116146106035760006000fd5b600160a060020a0381161561038d5760008054600160a060020a031916600160a060020a0383161790555b5b5b50565b81548183558181151161055357600083815260209020610553918101908301610699565b5b505050565b81548183558181151161055357600083815260209020610553918101908301610699565b5b505050565b60408051602081019091526000815290565b6105e491905b808211156106b3576000815560010161069f565b5090565b905600a165627a7a72305820f53c9547789a008ccb8f24999a7b6fb4c8fb20655522030c87ba624e1fdb67ea0029", "networks": { - "50": { + "1": { "links": {}, "events": { "0x94bb87f4c15c4587ff559a7584006fa01ddf9299359be6b512b94527aa961aca": { @@ -207,8 +207,8 @@ "type": "event" } }, - "updated_at": 1502391794384, - "address": "0x168ead2eadb6b3b8f47d6ae0ff418451c1087239" + "updated_at": 1502478966000, + "address": "0x8da0d80f5007ef1e431dd2127178d224e32c2ef4" }, "42": { "links": {}, @@ -251,7 +251,7 @@ "updated_at": 1502391794384, "address": "0x087Eed4Bc1ee3DE49BeFbd66C662B434B15d49d4" }, - "1": { + "50": { "links": {}, "events": { "0x94bb87f4c15c4587ff559a7584006fa01ddf9299359be6b512b94527aa961aca": { @@ -289,10 +289,10 @@ "type": "event" } }, - "updated_at": 1502478966000, - "address": "0x8da0d80f5007ef1e431dd2127178d224e32c2ef4" + "updated_at": 1513088404202, + "address": "0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c" } }, "schema_version": "0.0.5", - "updated_at": 1502391794384 -} + "updated_at": 1513088404202 +}
\ No newline at end of file diff --git a/packages/contracts/build/contracts/ZRXToken.json b/packages/contracts/build/contracts/ZRXToken.json index 3aac50ace..37a576c93 100644 --- a/packages/contracts/build/contracts/ZRXToken.json +++ b/packages/contracts/build/contracts/ZRXToken.json @@ -213,9 +213,9 @@ "type": "event" } ], - "unlinked_binary": "0x60606040526b033b2e3c9fd0803ce8000000600355341561001c57fe5b5b600354600160a060020a0333166000908152602081905260409020555b5b6106198061004a6000396000f3006060604052361561007d5763ffffffff60e060020a60003504166306fdde03811461007f578063095ea7b31461010f57806318160ddd1461014257806323b872dd14610164578063313ce5671461019d57806370a08231146101c357806395d89b41146101f1578063a9059cbb14610281578063dd62ed3e146102b4575bfe5b341561008757fe5b61008f6102e8565b6040805160208082528351818301528351919283929083019185019080838382156100d5575b8051825260208311156100d557601f1990920191602091820191016100b5565b505050905090810190601f1680156101015780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561011757fe5b61012e600160a060020a0360043516602435610316565b604080519115158252519081900360200190f35b341561014a57fe5b610152610381565b60408051918252519081900360200190f35b341561016c57fe5b61012e600160a060020a0360043581169060243516604435610387565b604080519115158252519081900360200190f35b34156101a557fe5b6101ad6104aa565b6040805160ff9092168252519081900360200190f35b34156101cb57fe5b610152600160a060020a03600435166104af565b60408051918252519081900360200190f35b34156101f957fe5b61008f6104ce565b6040805160208082528351818301528351919283929083019185019080838382156100d5575b8051825260208311156100d557601f1990920191602091820191016100b5565b505050905090810190601f1680156101015780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561028957fe5b61012e600160a060020a03600435166024356104ee565b604080519115158252519081900360200190f35b34156102bc57fe5b610152600160a060020a03600435811690602435166105a0565b60408051918252519081900360200190f35b6040805180820190915260118152607960020a70183c10283937ba37b1b7b6102a37b5b2b702602082015281565b600160a060020a03338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60035481565b600160a060020a03808416600081815260016020908152604080832033909516835293815283822054928252819052918220548390108015906103ca5750828110155b80156103f05750600160a060020a03841660009081526020819052604090205483810110155b1561049c57600160a060020a038085166000908152602081905260408082208054870190559187168152208054849003905560001981101561045a57600160a060020a03808616600090815260016020908152604080832033909416835292905220805484900390555b83600160a060020a031685600160a060020a03166000805160206105ce833981519152856040518082815260200191505060405180910390a3600191506104a1565b600091505b5b509392505050565b601281565b600160a060020a0381166000908152602081905260409020545b919050565b604080518082019091526003815260eb60020a620b4a4b02602082015281565b600160a060020a0333166000908152602081905260408120548290108015906105315750600160a060020a03831660009081526020819052604090205482810110155b1561059157600160a060020a0333811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191936000805160206105ce833981519152929081900390910190a350600161037b565b50600061037b565b5b92915050565b600160a060020a038083166000908152600160209081526040808320938516835292905220545b929150505600ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a72305820c3b32a51a49bb8e7b08cb40d70b018590761113b8e17709dace660ef94b069e30029", + "unlinked_binary": "0x60606040526b033b2e3c9fd0803ce8000000600355341561001c57fe5b5b600354600160a060020a0333166000908152602081905260409020555b5b6106198061004a6000396000f3006060604052361561007d5763ffffffff60e060020a60003504166306fdde03811461007f578063095ea7b31461010f57806318160ddd1461014257806323b872dd14610164578063313ce5671461019d57806370a08231146101c357806395d89b41146101f1578063a9059cbb14610281578063dd62ed3e146102b4575bfe5b341561008757fe5b61008f6102e8565b6040805160208082528351818301528351919283929083019185019080838382156100d5575b8051825260208311156100d557601f1990920191602091820191016100b5565b505050905090810190601f1680156101015780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561011757fe5b61012e600160a060020a0360043516602435610316565b604080519115158252519081900360200190f35b341561014a57fe5b610152610381565b60408051918252519081900360200190f35b341561016c57fe5b61012e600160a060020a0360043581169060243516604435610387565b604080519115158252519081900360200190f35b34156101a557fe5b6101ad6104aa565b6040805160ff9092168252519081900360200190f35b34156101cb57fe5b610152600160a060020a03600435166104af565b60408051918252519081900360200190f35b34156101f957fe5b61008f6104ce565b6040805160208082528351818301528351919283929083019185019080838382156100d5575b8051825260208311156100d557601f1990920191602091820191016100b5565b505050905090810190601f1680156101015780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561028957fe5b61012e600160a060020a03600435166024356104ee565b604080519115158252519081900360200190f35b34156102bc57fe5b610152600160a060020a03600435811690602435166105a0565b60408051918252519081900360200190f35b6040805180820190915260118152607960020a70183c10283937ba37b1b7b6102a37b5b2b702602082015281565b600160a060020a03338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60035481565b600160a060020a03808416600081815260016020908152604080832033909516835293815283822054928252819052918220548390108015906103ca5750828110155b80156103f05750600160a060020a03841660009081526020819052604090205483810110155b1561049c57600160a060020a038085166000908152602081905260408082208054870190559187168152208054849003905560001981101561045a57600160a060020a03808616600090815260016020908152604080832033909416835292905220805484900390555b83600160a060020a031685600160a060020a03166000805160206105ce833981519152856040518082815260200191505060405180910390a3600191506104a1565b600091505b5b509392505050565b601281565b600160a060020a0381166000908152602081905260409020545b919050565b604080518082019091526003815260eb60020a620b4a4b02602082015281565b600160a060020a0333166000908152602081905260408120548290108015906105315750600160a060020a03831660009081526020819052604090205482810110155b1561059157600160a060020a0333811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191936000805160206105ce833981519152929081900390910190a350600161037b565b50600061037b565b5b92915050565b600160a060020a038083166000908152600160209081526040808320938516835292905220545b929150505600ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a723058206964b3cfca2af9b1d1448e45eb8b04a5c1df55275a172242166d69e576e2a3b70029", "networks": { - "50": { + "1": { "links": {}, "events": { "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef": { @@ -263,7 +263,8 @@ "type": "event" } }, - "updated_at": 1502391794391 + "updated_at": 1502477311000, + "address": "0xe41d2489571d322189246dafa5ebde1f4699f498" }, "42": { "links": {}, @@ -315,8 +316,8 @@ }, "updated_at": 1502391794391, "address": "0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570" - }, - "1": { + }, + "50": { "links": {}, "events": { "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef": { @@ -364,10 +365,9 @@ "type": "event" } }, - "updated_at": 1502477311000, - "address": "0xe41d2489571d322189246dafa5ebde1f4699f498" + "updated_at": 1513088404207 } }, "schema_version": "0.0.5", - "updated_at": 1502391794391 -} + "updated_at": 1513088404207 +}
\ No newline at end of file diff --git a/packages/contracts/contracts/Exchange.sol b/packages/contracts/contracts/Exchange.sol index 02deee967..a402e7ca5 100644 --- a/packages/contracts/contracts/Exchange.sol +++ b/packages/contracts/contracts/Exchange.sol @@ -16,11 +16,11 @@ */ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; import "./TokenTransferProxy.sol"; -import "./base/Token.sol"; -import "./base/SafeMath.sol"; +import "./tokens/Token.sol"; +import "./utils/SafeMath.sol"; /// @title Exchange - Facilitates exchange of ERC20 tokens. /// @author Amir Bandeali - <amir@0xProject.com>, Will Warren - <will@0xProject.com> @@ -600,3 +600,4 @@ contract Exchange is SafeMath { return Token(token).allowance.gas(EXTERNAL_QUERY_GAS_LIMIT)(owner, TOKEN_TRANSFER_PROXY_CONTRACT); // Limit gas to prevent reentrancy } } + diff --git a/packages/contracts/contracts/TokenRegistry.sol b/packages/contracts/contracts/TokenRegistry.sol index d370f8cfe..d2570e71d 100644 --- a/packages/contracts/contracts/TokenRegistry.sol +++ b/packages/contracts/contracts/TokenRegistry.sol @@ -16,9 +16,9 @@ */ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; -import "./base/Ownable.sol"; +import "./utils/Ownable.sol"; /// @title Token Registry - Stores metadata associated with ERC20 tokens. See ERC22 https://github.com/ethereum/EIPs/issues/22 /// @author Amir Bandeali - <amir@0xProject.com>, Will Warren - <will@0xProject.com> @@ -306,3 +306,4 @@ contract TokenRegistry is Ownable { return tokenAddresses; } } + diff --git a/packages/contracts/contracts/TokenTransferProxy.sol b/packages/contracts/contracts/TokenTransferProxy.sol index 23b0b9e6d..fd2358496 100644 --- a/packages/contracts/contracts/TokenTransferProxy.sol +++ b/packages/contracts/contracts/TokenTransferProxy.sol @@ -16,10 +16,10 @@ */ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; -import "./base/Token.sol"; -import "./base/Ownable.sol"; +import "./tokens/Token.sol"; +import "./utils/Ownable.sol"; /// @title TokenTransferProxy - Transfers tokens on behalf of contracts that have been approved via decentralized governance. /// @author Amir Bandeali - <amir@0xProject.com>, Will Warren - <will@0xProject.com> @@ -113,3 +113,4 @@ contract TokenTransferProxy is Ownable { return authorities; } } + diff --git a/packages/contracts/contracts/base/SafeMath.sol b/packages/contracts/contracts/base/SafeMath.sol deleted file mode 100644 index fac674a20..000000000 --- a/packages/contracts/contracts/base/SafeMath.sol +++ /dev/null @@ -1,41 +0,0 @@ -pragma solidity 0.4.11; - -contract SafeMath { - function safeMul(uint a, uint b) internal constant returns (uint256) { - uint c = a * b; - assert(a == 0 || c / a == b); - return c; - } - - function safeDiv(uint a, uint b) internal constant returns (uint256) { - uint c = a / b; - return c; - } - - function safeSub(uint a, uint b) internal constant returns (uint256) { - assert(b <= a); - return a - b; - } - - function safeAdd(uint a, uint b) internal constant returns (uint256) { - uint c = a + b; - assert(c >= a); - return c; - } - - function max64(uint64 a, uint64 b) internal constant returns (uint64) { - return a >= b ? a : b; - } - - function min64(uint64 a, uint64 b) internal constant returns (uint64) { - return a < b ? a : b; - } - - function max256(uint256 a, uint256 b) internal constant returns (uint256) { - return a >= b ? a : b; - } - - function min256(uint256 a, uint256 b) internal constant returns (uint256) { - return a < b ? a : b; - } -} diff --git a/packages/contracts/contracts/base/MultiSigWallet.sol b/packages/contracts/contracts/multisig/MultiSigWallet.sol index 7531224ea..ae7ef06fd 100644 --- a/packages/contracts/contracts/base/MultiSigWallet.sol +++ b/packages/contracts/contracts/multisig/MultiSigWallet.sol @@ -1,4 +1,4 @@ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; /// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution. /// @author Stefan George - <stefan.george@consensys.net> @@ -363,3 +363,4 @@ contract MultiSigWallet { _transactionIds[i - from] = transactionIdsTemp[i]; } } + diff --git a/packages/contracts/contracts/MultiSigWalletWithTimeLock.sol b/packages/contracts/contracts/multisig/MultiSigWalletWithTimeLock.sol index 70123e6b6..62273eba3 100644 --- a/packages/contracts/contracts/MultiSigWalletWithTimeLock.sol +++ b/packages/contracts/contracts/multisig/MultiSigWalletWithTimeLock.sol @@ -16,9 +16,9 @@ */ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; -import "./base/MultiSigWallet.sol"; +import "./MultiSigWallet.sol"; /// @title Multisignature wallet with time lock- Allows multiple parties to execute a transaction after a time lock has passed. /// @author Amir Bandeali - <amir@0xProject.com> @@ -130,3 +130,4 @@ contract MultiSigWalletWithTimeLock is MultiSigWallet { ConfirmationTimeSet(transactionId, confirmationTime); } } + diff --git a/packages/contracts/contracts/MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress.sol b/packages/contracts/contracts/multisig/MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress.sol index 15fdb1d07..07beb9f5b 100644 --- a/packages/contracts/contracts/MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress.sol +++ b/packages/contracts/contracts/multisig/MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; import "./MultiSigWalletWithTimeLock.sol"; @@ -80,3 +80,4 @@ contract MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress is MultiSigWall return true; } } + diff --git a/packages/contracts/contracts/test/DummyToken.sol b/packages/contracts/contracts/test/DummyToken.sol index 414c17b2a..046af3059 100644 --- a/packages/contracts/contracts/test/DummyToken.sol +++ b/packages/contracts/contracts/test/DummyToken.sol @@ -1,7 +1,7 @@ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; import "./Mintable.sol"; -import "./../base/Ownable.sol"; +import "./../utils/Ownable.sol"; contract DummyToken is Mintable, Ownable { string public name; @@ -21,7 +21,9 @@ contract DummyToken is Mintable, Ownable { balances[msg.sender] = _totalSupply; } - function setBalance(address _target, uint _value) onlyOwner { + function setBalance(address _target, uint _value) + onlyOwner + { uint currBalance = balanceOf(_target); if (_value < currBalance) { totalSupply = safeSub(totalSupply, safeSub(currBalance, _value)); @@ -31,3 +33,4 @@ contract DummyToken is Mintable, Ownable { balances[_target] = _value; } } + diff --git a/packages/contracts/contracts/test/DummyToken_v2.sol b/packages/contracts/contracts/test/DummyToken_v2.sol new file mode 100644 index 000000000..bd4d06be9 --- /dev/null +++ b/packages/contracts/contracts/test/DummyToken_v2.sol @@ -0,0 +1,38 @@ +pragma solidity 0.4.18; + +import "./Mintable_v2.sol"; +import "./../utils/Ownable_v2.sol"; + +contract DummyToken_v2 is Mintable_v2, Ownable_v2 { + string public name; + string public symbol; + uint public decimals; + + function DummyToken_v2( + string _name, + string _symbol, + uint _decimals, + uint _totalSupply) + public + { + name = _name; + symbol = _symbol; + decimals = _decimals; + totalSupply = _totalSupply; + balances[msg.sender] = _totalSupply; + } + + function setBalance(address _target, uint _value) + public + onlyOwner + { + uint currBalance = balanceOf(_target); + if (_value < currBalance) { + totalSupply = safeSub(totalSupply, safeSub(currBalance, _value)); + } else { + totalSupply = safeAdd(totalSupply, safeSub(_value, currBalance)); + } + balances[_target] = _value; + } +} + diff --git a/packages/contracts/contracts/test/MaliciousToken.sol b/packages/contracts/contracts/test/MaliciousToken.sol index 3c1a53612..3e7d5d1a5 100644 --- a/packages/contracts/contracts/test/MaliciousToken.sol +++ b/packages/contracts/contracts/test/MaliciousToken.sol @@ -1,11 +1,13 @@ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; -import "./../base/StandardToken.sol"; +import "./../tokens/StandardToken.sol"; contract MaliciousToken is StandardToken { uint8 stateToUpdate = 1; // Not null so that change only requires 5000 gas - function updateState() internal { + function updateState() + internal + { stateToUpdate++; } @@ -27,3 +29,4 @@ contract MaliciousToken is StandardToken { return allowed[_owner][_spender]; } } + diff --git a/packages/contracts/contracts/test/Mintable.sol b/packages/contracts/contracts/test/Mintable.sol index c0438f304..3b91415ef 100644 --- a/packages/contracts/contracts/test/Mintable.sol +++ b/packages/contracts/contracts/test/Mintable.sol @@ -1,16 +1,19 @@ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; import "./../tokens/UnlimitedAllowanceToken.sol"; -import "./../base/SafeMath.sol"; +import "./../utils/SafeMath.sol"; /* * Mintable * Base contract that creates a mintable UnlimitedAllowanceToken */ contract Mintable is UnlimitedAllowanceToken, SafeMath { - function mint(uint _value) { + function mint(uint _value) + public + { require(_value <= 100000000000000000000); balances[msg.sender] = safeAdd(_value, balances[msg.sender]); totalSupply = safeAdd(totalSupply, _value); } } + diff --git a/packages/contracts/contracts/test/Mintable_v2.sol b/packages/contracts/contracts/test/Mintable_v2.sol new file mode 100644 index 000000000..829145cfb --- /dev/null +++ b/packages/contracts/contracts/test/Mintable_v2.sol @@ -0,0 +1,19 @@ +pragma solidity 0.4.18; + +import "./../tokens/UnlimitedAllowanceToken_v2.sol"; +import "./../utils/SafeMath_v2.sol"; + +/* + * Mintable + * Base contract that creates a mintable UnlimitedAllowanceToken + */ +contract Mintable_v2 is UnlimitedAllowanceToken_v2, SafeMath_v2 { + function mint(uint _value) + public + { + require(_value <= 100000000000000000000); + balances[msg.sender] = safeAdd(_value, balances[msg.sender]); + totalSupply = safeAdd(totalSupply, _value); + } +} + diff --git a/packages/contracts/contracts/tokens/ERC20Token.sol b/packages/contracts/contracts/tokens/ERC20Token.sol new file mode 100644 index 000000000..318da8c01 --- /dev/null +++ b/packages/contracts/contracts/tokens/ERC20Token.sol @@ -0,0 +1,59 @@ +pragma solidity 0.4.18; + +import "./Token_v2.sol"; + +contract ERC20Token is Token_v2 { + + function transfer(address _to, uint _value) + public + returns (bool) + { + require(balances[msg.sender] >= _value && balances[_to] + _value >= balances[_to]); + balances[msg.sender] -= _value; + balances[_to] += _value; + Transfer(msg.sender, _to, _value); + return true; + } + + function transferFrom(address _from, address _to, uint _value) + public + returns (bool) + { + require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value >= balances[_to]); + balances[_to] += _value; + balances[_from] -= _value; + allowed[_from][msg.sender] -= _value; + Transfer(_from, _to, _value); + return true; + } + + function approve(address _spender, uint _value) + public + returns (bool) + { + allowed[msg.sender][_spender] = _value; + Approval(msg.sender, _spender, _value); + return true; + } + + function balanceOf(address _owner) + public + view + returns (uint) + { + return balances[_owner]; + } + + function allowance(address _owner, address _spender) + public + view + returns (uint) + { + return allowed[_owner][_spender]; + } + + mapping (address => uint) balances; + mapping (address => mapping (address => uint)) allowed; + uint public totalSupply; +} + diff --git a/packages/contracts/contracts/tokens/EtherToken.sol b/packages/contracts/contracts/tokens/EtherToken.sol deleted file mode 100644 index 68148e095..000000000 --- a/packages/contracts/contracts/tokens/EtherToken.sol +++ /dev/null @@ -1,56 +0,0 @@ -/* - - Copyright 2017 ZeroEx Intl. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -pragma solidity 0.4.11; - -import "./UnlimitedAllowanceToken.sol"; -import "./../base/SafeMath.sol"; - -contract EtherToken is UnlimitedAllowanceToken, SafeMath { - - string constant public name = "Ether Token"; - string constant public symbol = "WETH"; - uint8 constant public decimals = 18; - - /// @dev Fallback to calling deposit when ether is sent directly to contract. - function() - public - payable - { - deposit(); - } - - /// @dev Buys tokens with Ether, exchanging them 1:1. - function deposit() - public - payable - { - balances[msg.sender] = safeAdd(balances[msg.sender], msg.value); - totalSupply = safeAdd(totalSupply, msg.value); - } - - /// @dev Sells tokens in exchange for Ether, exchanging them 1:1. - /// @param amount Number of tokens to sell. - function withdraw(uint amount) - public - { - balances[msg.sender] = safeSub(balances[msg.sender], amount); - totalSupply = safeSub(totalSupply, amount); - require(msg.sender.send(amount)); - } -} diff --git a/packages/contracts/contracts/base/StandardToken.sol b/packages/contracts/contracts/tokens/StandardToken.sol index e0719d89a..9cd53d94a 100644 --- a/packages/contracts/contracts/base/StandardToken.sol +++ b/packages/contracts/contracts/tokens/StandardToken.sol @@ -1,4 +1,4 @@ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; import "./Token.sol"; @@ -42,3 +42,4 @@ contract StandardToken is Token { mapping (address => mapping (address => uint)) allowed; uint public totalSupply; } + diff --git a/packages/contracts/contracts/base/Token.sol b/packages/contracts/contracts/tokens/Token.sol index c6a55c2c0..507de9b12 100644 --- a/packages/contracts/contracts/base/Token.sol +++ b/packages/contracts/contracts/tokens/Token.sol @@ -1,4 +1,4 @@ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; contract Token { @@ -36,3 +36,4 @@ contract Token { event Transfer(address indexed _from, address indexed _to, uint _value); event Approval(address indexed _owner, address indexed _spender, uint _value); } + diff --git a/packages/contracts/contracts/tokens/Token_v2.sol b/packages/contracts/contracts/tokens/Token_v2.sol new file mode 100644 index 000000000..e1088c560 --- /dev/null +++ b/packages/contracts/contracts/tokens/Token_v2.sol @@ -0,0 +1,36 @@ +pragma solidity 0.4.18; + +contract Token_v2 { + + /// @notice send `_value` token to `_to` from `msg.sender` + /// @param _to The address of the recipient + /// @param _value The amount of token to be transferred + /// @return Whether the transfer was successful or not + function transfer(address _to, uint _value) public returns (bool) {} + + /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from` + /// @param _from The address of the sender + /// @param _to The address of the recipient + /// @param _value The amount of token to be transferred + /// @return Whether the transfer was successful or not + function transferFrom(address _from, address _to, uint _value) public returns (bool) {} + + /// @notice `msg.sender` approves `_addr` to spend `_value` tokens + /// @param _spender The address of the account able to transfer the tokens + /// @param _value The amount of wei to be approved for transfer + /// @return Whether the approval was successful or not + function approve(address _spender, uint _value) public returns (bool) {} + + /// @param _owner The address from which the balance will be retrieved + /// @return The balance + function balanceOf(address _owner) public view returns (uint) {} + + /// @param _owner The address of the account owning tokens + /// @param _spender The address of the account able to transfer the tokens + /// @return Amount of remaining tokens allowed to spent + function allowance(address _owner, address _spender) public view returns (uint) {} + + event Transfer(address indexed _from, address indexed _to, uint _value); + event Approval(address indexed _owner, address indexed _spender, uint _value); +} + diff --git a/packages/contracts/contracts/tokens/UnlimitedAllowanceToken.sol b/packages/contracts/contracts/tokens/UnlimitedAllowanceToken.sol index 40e01b360..0994cfae4 100644 --- a/packages/contracts/contracts/tokens/UnlimitedAllowanceToken.sol +++ b/packages/contracts/contracts/tokens/UnlimitedAllowanceToken.sol @@ -16,9 +16,9 @@ */ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; -import "./../base/StandardToken.sol"; +import "./StandardToken.sol"; contract UnlimitedAllowanceToken is StandardToken { @@ -50,3 +50,4 @@ contract UnlimitedAllowanceToken is StandardToken { } } } + diff --git a/packages/contracts/contracts/tokens/UnlimitedAllowanceToken_v2.sol b/packages/contracts/contracts/tokens/UnlimitedAllowanceToken_v2.sol new file mode 100644 index 000000000..b2caab8af --- /dev/null +++ b/packages/contracts/contracts/tokens/UnlimitedAllowanceToken_v2.sol @@ -0,0 +1,47 @@ +/* + + Copyright 2017 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity 0.4.18; + +import "./ERC20Token.sol"; + +contract UnlimitedAllowanceToken_v2 is ERC20Token { + + uint constant MAX_UINT = 2**256 - 1; + + /// @dev ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance. See https://github.com/ethereum/EIPs/issues/717 + /// @param _from Address to transfer from. + /// @param _to Address to transfer to. + /// @param _value Amount to transfer. + /// @return Success of transfer. + function transferFrom(address _from, address _to, uint _value) + public + returns (bool) + { + uint allowance = allowed[_from][msg.sender]; + require(balances[_from] >= _value && allowance >= _value && balances[_to] + _value >= balances[_to]); + balances[_to] += _value; + balances[_from] -= _value; + if (allowance < MAX_UINT) { + allowed[_from][msg.sender] -= _value; + } + Transfer(_from, _to, _value); + return true; + } +} + diff --git a/packages/contracts/contracts/tokens/WETH9.sol b/packages/contracts/contracts/tokens/WETH9.sol new file mode 100644 index 000000000..733ca414b --- /dev/null +++ b/packages/contracts/contracts/tokens/WETH9.sol @@ -0,0 +1,756 @@ +// Copyright (C) 2015, 2016, 2017 Dapphub + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +pragma solidity ^0.4.18; + +contract WETH9 { + string public name = "Wrapped Ether"; + string public symbol = "WETH"; + uint8 public decimals = 18; + + event Approval(address indexed src, address indexed guy, uint wad); + event Transfer(address indexed src, address indexed dst, uint wad); + event Deposit(address indexed dst, uint wad); + event Withdrawal(address indexed src, uint wad); + + mapping (address => uint) public balanceOf; + mapping (address => mapping (address => uint)) public allowance; + + function() public payable { + deposit(); + } + function deposit() public payable { + balanceOf[msg.sender] += msg.value; + Deposit(msg.sender, msg.value); + } + function withdraw(uint wad) public { + require(balanceOf[msg.sender] >= wad); + balanceOf[msg.sender] -= wad; + msg.sender.transfer(wad); + Withdrawal(msg.sender, wad); + } + + function totalSupply() public view returns (uint) { + return this.balance; + } + + function approve(address guy, uint wad) public returns (bool) { + allowance[msg.sender][guy] = wad; + Approval(msg.sender, guy, wad); + return true; + } + + function transfer(address dst, uint wad) public returns (bool) { + return transferFrom(msg.sender, dst, wad); + } + + function transferFrom(address src, address dst, uint wad) + public + returns (bool) + { + require(balanceOf[src] >= wad); + + if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) { + require(allowance[src][msg.sender] >= wad); + allowance[src][msg.sender] -= wad; + } + + balanceOf[src] -= wad; + balanceOf[dst] += wad; + + Transfer(src, dst, wad); + + return true; + } +} + + +/* + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. + +*/ diff --git a/packages/contracts/contracts/tokens/ZRXToken.sol b/packages/contracts/contracts/tokens/ZRXToken.sol index c8b9c08ab..af1dfac99 100644 --- a/packages/contracts/contracts/tokens/ZRXToken.sol +++ b/packages/contracts/contracts/tokens/ZRXToken.sol @@ -16,7 +16,7 @@ */ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; import "./UnlimitedAllowanceToken.sol"; @@ -31,3 +31,4 @@ contract ZRXToken is UnlimitedAllowanceToken { balances[msg.sender] = totalSupply; } } + diff --git a/packages/contracts/contracts/base/Ownable.sol b/packages/contracts/contracts/utils/Ownable.sol index b7d6ac71c..77fdaf085 100644 --- a/packages/contracts/contracts/base/Ownable.sol +++ b/packages/contracts/contracts/utils/Ownable.sol @@ -1,4 +1,4 @@ -pragma solidity 0.4.11; +pragma solidity ^0.4.11; /* * Ownable @@ -25,3 +25,4 @@ contract Ownable { } } } + diff --git a/packages/contracts/contracts/utils/Ownable_v2.sol b/packages/contracts/contracts/utils/Ownable_v2.sol new file mode 100644 index 000000000..77e1fed08 --- /dev/null +++ b/packages/contracts/contracts/utils/Ownable_v2.sol @@ -0,0 +1,33 @@ +pragma solidity 0.4.18; + +/* + * Ownable + * + * Base contract with an owner. + * Provides onlyOwner modifier, which prevents function from running if it is called by anyone other than the owner. + */ + +contract Ownable_v2 { + address public owner; + + function Ownable_v2() + public + { + owner = msg.sender; + } + + modifier onlyOwner() { + require(msg.sender == owner); + _; + } + + function transferOwnership(address newOwner) + public + onlyOwner + { + if (newOwner != address(0)) { + owner = newOwner; + } + } +} + diff --git a/packages/contracts/contracts/utils/SafeMath.sol b/packages/contracts/contracts/utils/SafeMath.sol new file mode 100644 index 000000000..a7891a7af --- /dev/null +++ b/packages/contracts/contracts/utils/SafeMath.sol @@ -0,0 +1,74 @@ +pragma solidity ^0.4.11; + +contract SafeMath { + function safeMul(uint a, uint b) + internal + constant + returns (uint256) + { + uint c = a * b; + assert(a == 0 || c / a == b); + return c; + } + + function safeDiv(uint a, uint b) + internal + constant + returns (uint256) + { + uint c = a / b; + return c; + } + + function safeSub(uint a, uint b) + internal + constant + returns (uint256) + { + assert(b <= a); + return a - b; + } + + function safeAdd(uint a, uint b) + internal + constant + returns (uint256) + { + uint c = a + b; + assert(c >= a); + return c; + } + + function max64(uint64 a, uint64 b) + internal + constant + returns (uint64) + { + return a >= b ? a : b; + } + + function min64(uint64 a, uint64 b) + internal + constant + returns (uint64) + { + return a < b ? a : b; + } + + function max256(uint256 a, uint256 b) + internal + constant + returns (uint256) + { + return a >= b ? a : b; + } + + function min256(uint256 a, uint256 b) + internal + constant + returns (uint256) + { + return a < b ? a : b; + } +} + diff --git a/packages/contracts/contracts/utils/SafeMath_v2.sol b/packages/contracts/contracts/utils/SafeMath_v2.sol new file mode 100644 index 000000000..6eda03999 --- /dev/null +++ b/packages/contracts/contracts/utils/SafeMath_v2.sol @@ -0,0 +1,74 @@ +pragma solidity 0.4.18; + +contract SafeMath_v2 { + function safeMul(uint a, uint b) + internal + pure + returns (uint256) + { + uint c = a * b; + assert(a == 0 || c / a == b); + return c; + } + + function safeDiv(uint a, uint b) + internal + pure + returns (uint256) + { + uint c = a / b; + return c; + } + + function safeSub(uint a, uint b) + internal + pure + returns (uint256) + { + assert(b <= a); + return a - b; + } + + function safeAdd(uint a, uint b) + internal + pure + returns (uint256) + { + uint c = a + b; + assert(c >= a); + return c; + } + + function max64(uint64 a, uint64 b) + internal + pure + returns (uint256) + { + return a >= b ? a : b; + } + + function min64(uint64 a, uint64 b) + internal + pure + returns (uint256) + { + return a < b ? a : b; + } + + function max256(uint256 a, uint256 b) + internal + pure + returns (uint256) + { + return a >= b ? a : b; + } + + function min256(uint256 a, uint256 b) + internal + pure + returns (uint256) + { + return a < b ? a : b; + } +} + diff --git a/packages/contracts/deploy/migrations/migrate.ts b/packages/contracts/deploy/migrations/migrate.ts deleted file mode 100644 index c3d38875e..000000000 --- a/packages/contracts/deploy/migrations/migrate.ts +++ /dev/null @@ -1,106 +0,0 @@ -import {Web3Wrapper} from '@0xproject/web3-wrapper'; -import {BigNumber} from 'bignumber.js'; -import * as _ from 'lodash'; -import * as Web3 from 'web3'; - -import {Deployer} from './../src/deployer'; -import {constants} from './../src/utils/constants'; -import {Token} from './../src/utils/types'; -import {tokenInfo} from './config/token_info'; - -export const migrator = { - /** - * Custom migrations should be defined in this function. This will be called with the CLI 'migrate' command. - * @param deployer Deployer instance. - */ - async runMigrationsAsync(deployer: Deployer): Promise<void> { - const web3Wrapper: Web3Wrapper = deployer.web3Wrapper; - const accounts: string[] = await web3Wrapper.getAvailableAddressesAsync(); - - const independentContracts: Web3.ContractInstance[] = await Promise.all([ - deployer.deployAndSaveAsync('TokenTransferProxy'), - deployer.deployAndSaveAsync('ZRXToken'), - deployer.deployAndSaveAsync('EtherToken'), - deployer.deployAndSaveAsync('TokenRegistry'), - ]); - const [tokenTransferProxy, zrxToken, etherToken, tokenReg] = independentContracts; - - const exchangeArgs = [zrxToken.address, tokenTransferProxy.address]; - const owners = [accounts[0], accounts[1]]; - const confirmationsRequired = new BigNumber(2); - const secondsRequired = new BigNumber(0); - const multiSigArgs = [owners, confirmationsRequired, secondsRequired, tokenTransferProxy.address]; - const dependentContracts: Web3.ContractInstance[] = await Promise.all([ - deployer.deployAndSaveAsync('Exchange', exchangeArgs), - deployer.deployAndSaveAsync('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', multiSigArgs), - ]); - const [exchange, multiSig] = dependentContracts; - - const owner = accounts[0]; - await tokenTransferProxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {from: owner}); - await tokenTransferProxy.transferOwnership.sendTransactionAsync(multiSig.address, {from: owner}); - - const tokensToRegister: Web3.ContractInstance[] = await Promise.all( - _.map(tokenInfo, async (token: Token): Promise<Web3.ContractInstance> => { - const totalSupply = new BigNumber(0); - const args = [ - token.name, - token.symbol, - token.decimals, - totalSupply, - ]; - return deployer.deployAsync('DummyToken', args); - }), - ); - const addTokenGasEstimate = await tokenReg.addToken.estimateGasAsync( - tokensToRegister[0].address, - tokenInfo[0].name, - tokenInfo[0].symbol, - tokenInfo[0].decimals, - tokenInfo[0].ipfsHash, - tokenInfo[0].swarmHash, - {from: owner}, - ); - const addTokenPromises = [ - tokenReg.addToken.sendTransactionAsync( - zrxToken.address, - '0x Protocol Token', - 'ZRX', - 18, - constants.NULL_BYTES, - constants.NULL_BYTES, - { - from: owner, - gas: addTokenGasEstimate, - }, - ), - tokenReg.addToken.sendTransactionAsync( - etherToken.address, - 'Ether Token', - 'WETH', - 18, - constants.NULL_BYTES, - constants.NULL_BYTES, - { - from: owner, - gas: addTokenGasEstimate, - }, - ), - ]; - const addDummyTokenPromises = _.map(tokenInfo, async (token: Token, i: number): Promise<void> => { - return tokenReg.addToken.sendTransactionAsync( - tokensToRegister[i].address, - token.name, - token.symbol, - token.decimals, - token.ipfsHash, - token.swarmHash, - { - from: owner, - gas: addTokenGasEstimate, - }, - ); - }); - await Promise.all([...addDummyTokenPromises, ...addTokenPromises]); - }, -}; diff --git a/packages/contracts/deploy/test/fixtures/exchange_bin.ts b/packages/contracts/deploy/test/fixtures/exchange_bin.ts deleted file mode 100644 index 0ca87760e..000000000 --- a/packages/contracts/deploy/test/fixtures/exchange_bin.ts +++ /dev/null @@ -1,4 +0,0 @@ -// tslint:disable-next-line:max-line-length -export const constructor_args = '0x000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f4980000000000000000000000008da0d80f5007ef1e431dd2127178d224e32c2ef4'; -// tslint:disable-next-line:max-line-length -export const exchange_binary = '0x6060604052341561000f57600080fd5b604051604080612c4d833981016040528080519060200190919080519060200190919050505b816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b50505b612b84806100c96000396000f300606060405236156100fa576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806314df96ee146100ff578063288cdc911461014c5780632ac1262214610187578063363349be146101c2578063394c21e7146103bc5780633b30ba591461044b5780634f150787146104a0578063741bcc93146106b25780637e9abb50146107535780638163681e1461078e57806398024a8b14610812578063add1cbc51461085b578063b7b2c7d6146108b0578063baa0181d14610acd578063bc61394a14610c1f578063cfc4d0ec14610cdf578063f06bbf7514610d6d578063ffa1ad7414610d9e575b600080fd5b341561010a57600080fd5b6101326004808035906020019091908035906020019091908035906020019091905050610e2d565b604051808215151515815260200191505060405180910390f35b341561015757600080fd5b610171600480803560001916906020019091905050610e7c565b6040518082815260200191505060405180910390f35b341561019257600080fd5b6101ac600480803560001916906020019091905050610e94565b6040518082815260200191505060405180910390f35b34156101cd57600080fd5b6103a660048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b8282101561024857848483905060a002016005806020026040519081016040528092919082600560200280828437820191505050505081526020019060010190610203565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156102c457848483905060c00201600680602002604051908101604052809291908260066020028082843782019150505050508152602001906001019061027f565b5050505050919080359060200190919080351515906020019091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050610eac565b6040518082815260200191505060405180910390f35b34156103c757600080fd5b6104356004808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091908060c001906006806020026040519081016040528092919082600660200280828437820191505050505091908035906020019091905050611013565b6040518082815260200191505060405180910390f35b341561045657600080fd5b61045e6114fb565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156104ab57600080fd5b6106b060048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b8282101561052657848483905060a0020160058060200260405190810160405280929190826005602002808284378201915050505050815260200190600101906104e1565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156105a257848483905060c00201600680602002604051908101604052809291908260066020028082843782019150505050508152602001906001019061055d565b50505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050611520565b005b34156106bd57600080fd5b6107516004808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091908060c00190600680602002604051908101604052809291908260066020028082843782019150505050509190803590602001909190803560ff1690602001909190803560001916906020019091908035600019169060200190919050506115df565b005b341561075e57600080fd5b610778600480803560001916906020019091905050611605565b6040518082815260200191505060405180910390f35b341561079957600080fd5b6107f8600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080356000191690602001909190803560ff16906020019091908035600019169060200190919080356000191690602001909190505061164f565b604051808215151515815260200191505060405180910390f35b341561081d57600080fd5b6108456004808035906020019091908035906020019091908035906020019091905050611757565b6040518082815260200191505060405180910390f35b341561086657600080fd5b61086e611776565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156108bb57600080fd5b610acb60048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b8282101561093657848483905060a0020160058060200260405190810160405280929190826005602002808284378201915050505050815260200190600101906108f1565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156109b257848483905060c00201600680602002604051908101604052809291908260066020028082843782019150505050508152602001906001019061096d565b50505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091908035151590602001909190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190505061179c565b005b3415610ad857600080fd5b610c1d60048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610b5357848483905060a002016005806020026040519081016040528092919082600560200280828437820191505050505081526020019060010190610b0e565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610bcf57848483905060c002016006806020026040519081016040528092919082600660200280828437820191505050505081526020019060010190610b8a565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190505061185e565b005b3415610c2a57600080fd5b610cc96004808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091908060c001906006806020026040519081016040528092919082600660200280828437820191505050505091908035906020019091908035151590602001909190803560ff1690602001909190803560001916906020019091908035600019169060200190919050506118d3565b6040518082815260200191505060405180910390f35b3415610cea57600080fd5b610d4f6004808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091908060c001906006806020026040519081016040528092919082600660200280828437820191505050505091905050612073565b60405180826000191660001916815260200191505060405180910390f35b3415610d7857600080fd5b610d8061231f565b604051808261ffff1661ffff16815260200191505060405180910390f35b3415610da957600080fd5b610db1612325565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610df25780820151818401525b602081019050610dd6565b50505050905090810190601f168015610e1f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60008060008486850991506000821415610e4a5760009250610e73565b610e69610e5a83620f424061235e565b610e64888761235e565b612392565b90506103e8811192505b50509392505050565b60026020528060005260406000206000915090505481565b60036020528060005260406000206000915090505481565b6000806000809150600090505b895181101561100257896000815181101515610ed157fe5b906020019060200201516003600581101515610ee957fe5b602002015173ffffffffffffffffffffffffffffffffffffffff168a82815181101515610f1257fe5b906020019060200201516003600581101515610f2a57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16141515610f5157600080fd5b610fe582610fe08c84815181101515610f6657fe5b906020019060200201518c85815181101515610f7e57fe5b90602001906020020151610f928d886123ae565b8c8c88815181101515610fa157fe5b906020019060200201518c89815181101515610fb957fe5b906020019060200201518c8a815181101515610fd157fe5b906020019060200201516118d3565b6123c8565b915087821415610ff457611002565b5b8080600101915050610eb9565b8192505b5050979650505050505050565b600061101d612a8c565b6000806101606040519081016040528088600060058110151561103c57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200188600160058110151561106b57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200188600260058110151561109a57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018860036005811015156110c957fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018860046005811015156110f857fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200187600060068110151561112757fe5b6020020151815260200187600160068110151561114057fe5b6020020151815260200187600260068110151561115957fe5b6020020151815260200187600360068110151561117257fe5b6020020151815260200187600460068110151561118b57fe5b6020020151815260200161119f8989612073565b6000191681525092503373ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff161415156111e657600080fd5b60008360a001511180156111fe575060008360c00151115b801561120a5750600085115b151561121557600080fd5b8261012001514210151561127257826101400151600019166000600381111561123a57fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a3600093506114f1565b61128d8360c00151611288856101400151611605565b6123ae565b915061129985836123e7565b905060008114156112f35782610140015160001916600160038111156112bb57fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a3600093506114f1565b61131d600360008561014001516000191660001916815260200190815260200160002054826123c8565b60036000856101400151600019166000191681526020019081526020016000208190555082604001518360600151604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140192505050604051809103902060001916836080015173ffffffffffffffffffffffffffffffffffffffff16846000015173ffffffffffffffffffffffffffffffffffffffff167f67d66f160bc93d925d05dae1794c90d2d6d6688b29b84ff069398a9b0458713186604001518760600151611455878a60c001518b60a00151611757565b878a6101400151604051808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200184815260200183815260200182600019166000191681526020019550505050505060405180910390a48093505b5050509392505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008090505b86518110156115d5576115c7878281518110151561154057fe5b90602001906020020151878381518110151561155857fe5b90602001906020020151878481518110151561157057fe5b90602001906020020151878581518110151561158857fe5b9060200190602002015187868151811015156115a057fe5b9060200190602002015187878151811015156115b857fe5b906020019060200201516115df565b5b8080600101915050611526565b5b50505050505050565b836115f087878760008888886118d3565b1415156115fc57600080fd5b5b505050505050565b600061164760026000846000191660001916815260200190815260200160002054600360008560001916600019168152602001908152602001600020546123c8565b90505b919050565b600060018560405180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c0182600019166000191681526020019150506040518091039020858585604051600081526020016040526000604051602001526040518085600019166000191681526020018460ff1660ff16815260200183600019166000191681526020018260001916600019168152602001945050505050602060405160208103908084039060008661646e5a03f1151561171457600080fd5b50506020604051035173ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161490505b95945050505050565b600061176c611766858461235e565b84612392565b90505b9392505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008090505b87518110156118535761184488828151811015156117bc57fe5b9060200190602002015188838151811015156117d457fe5b9060200190602002015188848151811015156117ec57fe5b9060200190602002015188888681518110151561180557fe5b90602001906020020151888781518110151561181d57fe5b90602001906020020151888881518110151561183557fe5b906020019060200201516118d3565b505b80806001019150506117a2565b5b5050505050505050565b60008090505b83518110156118cc576118bd848281518110151561187e57fe5b90602001906020020151848381518110151561189657fe5b9060200190602002015184848151811015156118ae57fe5b90602001906020020151611013565b505b8080600101915050611864565b5b50505050565b60006118dd612a8c565b600080600080610160604051908101604052808e60006005811015156118ff57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e600160058110151561192e57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e600260058110151561195d57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e600360058110151561198c57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e60046005811015156119bb57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018d60006006811015156119ea57fe5b602002015181526020018d6001600681101515611a0357fe5b602002015181526020018d6002600681101515611a1c57fe5b602002015181526020018d6003600681101515611a3557fe5b602002015181526020018d6004600681101515611a4e57fe5b60200201518152602001611a628f8f612073565b600019168152509450600073ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff161480611ad957503373ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff16145b1515611ae457600080fd5b60008560a00151118015611afc575060008560c00151115b8015611b08575060008b115b1515611b1357600080fd5b611b2985600001518661014001518b8b8b61164f565b1515611b3457600080fd5b84610120015142101515611b91578461014001516000191660006003811115611b5957fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612063565b611bac8560c00151611ba7876101400151611605565b6123ae565b9350611bb88b856123e7565b95506000861415611c12578461014001516000191660016003811115611bda57fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612063565b611c25868660c001518760a00151610e2d565b15611c79578461014001516000191660026003811115611c4157fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612063565b89158015611c8e5750611c8c8587612401565b155b15611ce15784610140015160001916600380811115611ca957fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612063565b611cf4868660c001518760a00151611757565b9250611d20600260008761014001516000191660001916815260200190815260200160002054876123c8565b600260008761014001516000191660001916815260200190815260200160002081905550611d58856040015186600001513386612751565b1515611d6357600080fd5b611d77856060015133876000015189612751565b1515611d8257600080fd5b600073ffffffffffffffffffffffffffffffffffffffff16856080015173ffffffffffffffffffffffffffffffffffffffff16141515611e815760008560e001511115611e1f57611ddc868660c001518760e00151611757565b9150611e136000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168660000151876080015185612751565b1515611e1e57600080fd5b5b60008561010001511115611e8057611e41868660c00151876101000151611757565b9050611e746000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1633876080015184612751565b1515611e7f57600080fd5b5b5b84604001518560600151604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140192505050604051809103902060001916856080015173ffffffffffffffffffffffffffffffffffffffff16866000015173ffffffffffffffffffffffffffffffffffffffff167f0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb33389604001518a60600151898d8a8a8f6101400151604051808973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200186815260200185815260200184815260200183815260200182600019166000191681526020019850505050505050505060405180910390a48595505b5050505050979650505050505050565b60003083600060058110151561208557fe5b602002015184600160058110151561209957fe5b60200201518560026005811015156120ad57fe5b60200201518660036005811015156120c157fe5b60200201518760046005811015156120d557fe5b60200201518760006006811015156120e957fe5b60200201518860016006811015156120fd57fe5b602002015189600260068110151561211157fe5b60200201518a600360068110151561212557fe5b60200201518b600460068110151561213957fe5b60200201518c600560068110151561214d57fe5b6020020151604051808d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018781526020018681526020018581526020018481526020018381526020018281526020019c50505050505050505050505050604051809103902090505b92915050565b61138781565b6040805190810160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b6000808284029050600084148061237f575082848281151561237c57fe5b04145b151561238757fe5b8091505b5092915050565b60008082848115156123a057fe5b0490508091505b5092915050565b60008282111515156123bc57fe5b81830390505b92915050565b60008082840190508381101515156123dc57fe5b8091505b5092915050565b60008183106123f657816123f8565b825b90505b92915050565b60008060008060008060008060003397506124258a8c60c001518d60a00151611757565b9650600073ffffffffffffffffffffffffffffffffffffffff168b6080015173ffffffffffffffffffffffffffffffffffffffff161415156126d2576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168b6040015173ffffffffffffffffffffffffffffffffffffffff161495506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168b6060015173ffffffffffffffffffffffffffffffffffffffff161494506125208a8c60c001518d60e00151611757565b93506125368a8c60c001518d6101000151611757565b925085612543578361254e565b61254d87856123c8565b5b91508461255b5782612566565b6125658a846123c8565b5b9050816125986000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168d600001516128ae565b10806125d15750816125cf6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168d60000151612972565b105b806126055750806126036000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168a6128ae565b105b806126395750806126376000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168a612972565b105b156126475760009850612743565b851580156126805750866126638c604001518d600001516128ae565b108061267f57508661267d8c604001518d60000151612972565b105b5b1561268e5760009850612743565b841580156126bf5750896126a68c606001518a6128ae565b10806126be5750896126bc8c606001518a612972565b105b5b156126cd5760009850612743565b61273e565b866126e58c604001518d600001516128ae565b10806127015750866126ff8c604001518d60000151612972565b105b806127185750896127168c606001518a6128ae565b105b8061272f57508961272d8c606001518a612972565b105b1561273d5760009850612743565b5b600198505b505050505050505092915050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166315dacbea868686866000604051602001526040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001945050505050602060405180830381600087803b151561288857600080fd5b6102c65a03f1151561289957600080fd5b5050506040518051905090505b949350505050565b60008273ffffffffffffffffffffffffffffffffffffffff166370a0823161138761ffff16846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600088803b151561295157600080fd5b87f1151561295e57600080fd5b505050506040518051905090505b92915050565b60008273ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e61138761ffff1684600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600088803b1515612a6b57600080fd5b87f11515612a7857600080fd5b505050506040518051905090505b92915050565b61016060405190810160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000801916815250905600a165627a7a72305820df5cabdc3a116e993e10bfb14823d18d9b798038d4c463a1703f9a584c456b7e0029'; diff --git a/packages/contracts/globals.d.ts b/packages/contracts/globals.d.ts index df53e9372..2e5827324 100644 --- a/packages/contracts/globals.d.ts +++ b/packages/contracts/globals.d.ts @@ -1,8 +1,5 @@ -declare module 'bn.js'; -declare module 'ethereumjs-abi'; declare module 'chai-bignumber'; declare module 'dirty-chai'; -declare module 'yargs'; // HACK: In order to merge the bignumber declaration added by chai-bignumber to the chai Assertion // interface we must use `namespace` as the Chai definitelyTyped definition does. Since we otherwise @@ -31,6 +28,11 @@ declare module 'web3-eth-abi' { export function encodeParameters(typesArray: string[], parameters: any[]): string; } +declare module 'ethereumjs-abi' { + const soliditySHA3: (argTypes: string[], args: any[]) => Buffer; + const methodID: (name: string, types: string[]) => Buffer; +} + // Truffle injects the following into the global scope declare var artifacts: any; declare var contract: any; diff --git a/packages/contracts/globalsAugment.d.ts b/packages/contracts/globalsAugment.d.ts index 21f3742ae..9b16ce2ad 100644 --- a/packages/contracts/globalsAugment.d.ts +++ b/packages/contracts/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 @@ -16,4 +16,4 @@ declare global { } } /* tslint:enable */ -}
\ No newline at end of file +} diff --git a/packages/contracts/migrations/1_initial_migration.ts b/packages/contracts/migrations/1_initial_migration.ts index b34bbc2a1..8661ee218 100644 --- a/packages/contracts/migrations/1_initial_migration.ts +++ b/packages/contracts/migrations/1_initial_migration.ts @@ -1,5 +1,5 @@ -import {Artifacts} from '../util/artifacts'; -const {Migrations} = new Artifacts(artifacts); +import { Artifacts } from '../util/artifacts'; +const { Migrations } = new Artifacts(artifacts); module.exports = (deployer: any) => { deployer.deploy(Migrations); diff --git a/packages/contracts/migrations/2_deploy_independent_contracts.ts b/packages/contracts/migrations/2_deploy_independent_contracts.ts index 878860eb6..ac1752347 100644 --- a/packages/contracts/migrations/2_deploy_independent_contracts.ts +++ b/packages/contracts/migrations/2_deploy_independent_contracts.ts @@ -1,11 +1,6 @@ -import {Artifacts} from '../util/artifacts'; -import {ContractInstance, MultiSigConfigByNetwork} from '../util/types'; -const { - MultiSigWalletWithTimeLock, - TokenTransferProxy, - EtherToken, - TokenRegistry, -} = new Artifacts(artifacts); +import { Artifacts } from '../util/artifacts'; +import { MultiSigConfigByNetwork } from '../util/types'; +const { MultiSigWalletWithTimeLock, TokenTransferProxy, EtherToken, TokenRegistry } = new Artifacts(artifacts); let multiSigConfigByNetwork: MultiSigConfigByNetwork; try { @@ -25,14 +20,16 @@ module.exports = (deployer: any, network: string, accounts: string[]) => { }; const config = multiSigConfigByNetwork[network] || defaultConfig; if (network !== 'live') { - deployer.deploy(MultiSigWalletWithTimeLock, config.owners, - config.confirmationsRequired, config.secondsRequired) + deployer + .deploy(MultiSigWalletWithTimeLock, config.owners, config.confirmationsRequired, config.secondsRequired) .then(() => { - return deployer.deploy(TokenTransferProxy); - }).then(() => { - return deployer.deploy(TokenRegistry); - }).then(() => { - return deployer.deploy(EtherToken); + return deployer.deploy(TokenTransferProxy); + }) + .then(() => { + return deployer.deploy(TokenRegistry); + }) + .then(() => { + return deployer.deploy(EtherToken); }); } else { deployer.deploy([ diff --git a/packages/contracts/migrations/3_register_tokens.ts b/packages/contracts/migrations/3_register_tokens.ts index c72ac1510..d5cf63f94 100644 --- a/packages/contracts/migrations/3_register_tokens.ts +++ b/packages/contracts/migrations/3_register_tokens.ts @@ -1,86 +1,95 @@ import * as Bluebird from 'bluebird'; import * as _ from 'lodash'; -import {Artifacts} from '../util/artifacts'; -import {constants} from '../util/constants'; -import {ContractInstance, Token, TokenInfoByNetwork} from '../util/types'; +import { Artifacts } from '../util/artifacts'; +import { constants } from '../util/constants'; +import { ContractInstance, Token } from '../util/types'; -import {tokenInfo} from './config/token_info'; -const { - DummyToken, - EtherToken, - ZRXToken, - TokenRegistry, -} = new Artifacts(artifacts); +import { tokenInfo } from './config/token_info'; +const { DummyToken, EtherToken, ZRXToken, TokenRegistry } = new Artifacts(artifacts); module.exports = (deployer: any, network: string) => { const tokens = network === 'live' ? tokenInfo.live : tokenInfo.development; - deployer.then(() => { - return TokenRegistry.deployed(); - }).then((tokenRegistry: ContractInstance) => { - if (network !== 'live') { - const totalSupply = Math.pow(10, 18) * 1000000000; - return Bluebird.each(tokens.map((token: Token) => DummyToken.new( - token.name, - token.symbol, - token.decimals, - totalSupply, - )), _.noop).then((dummyTokens: ContractInstance[]) => { - const weth = { - address: EtherToken.address, - name: 'Ether Token', - symbol: 'WETH', - url: '', + deployer + .then(() => { + return TokenRegistry.deployed(); + }) + .then((tokenRegistry: ContractInstance) => { + if (network !== 'live') { + const totalSupply = Math.pow(10, 18) * 1000000000; + return Bluebird.each( + tokens.map((token: Token) => DummyToken.new(token.name, token.symbol, token.decimals, totalSupply)), + _.noop, + ).then((dummyTokens: ContractInstance[]) => { + const weth = { + address: EtherToken.address, + name: 'Ether Token', + symbol: 'WETH', + url: '', + decimals: 18, + ipfsHash: constants.NULL_BYTES, + swarmHash: constants.NULL_BYTES, + }; + return Bluebird.each( + dummyTokens + .map((tokenContract: ContractInstance, i: number) => { + const token = tokens[i]; + return tokenRegistry.addToken( + tokenContract.address, + token.name, + token.symbol, + token.decimals, + token.ipfsHash, + token.swarmHash, + ); + }) + .concat( + tokenRegistry.addToken( + weth.address, + weth.name, + weth.symbol, + weth.decimals, + weth.ipfsHash, + weth.swarmHash, + ), + ), + _.noop, + ); + }); + } else { + const zrx = { + address: ZRXToken.address, + name: '0x Protocol Token', + symbol: 'ZRX', + url: 'https://www.0xproject.com/', decimals: 18, ipfsHash: constants.NULL_BYTES, swarmHash: constants.NULL_BYTES, }; - return Bluebird.each(dummyTokens.map((tokenContract: ContractInstance, i: number) => { - const token = tokens[i]; - return tokenRegistry.addToken( - tokenContract.address, - token.name, - token.symbol, - token.decimals, - token.ipfsHash, - token.swarmHash, - ); - }).concat(tokenRegistry.addToken( - weth.address, - weth.name, - weth.symbol, - weth.decimals, - weth.ipfsHash, - weth.swarmHash, - )), _.noop); - }); - } else { - const zrx = { - address: ZRXToken.address, - name: '0x Protocol Token', - symbol: 'ZRX', - url: 'https://www.0xproject.com/', - decimals: 18, - ipfsHash: constants.NULL_BYTES, - swarmHash: constants.NULL_BYTES, - }; - return Bluebird.each(tokens.map((token: Token) => { - return tokenRegistry.addToken( - token.address, - token.name, - token.symbol, - token.decimals, - token.ipfsHash, - token.swarmHash, + return Bluebird.each( + tokens + .map((token: Token) => { + return tokenRegistry.addToken( + token.address, + token.name, + token.symbol, + token.decimals, + token.ipfsHash, + token.swarmHash, + ); + }) + .concat( + tokenRegistry.addToken( + zrx.address, + zrx.name, + zrx.symbol, + zrx.decimals, + zrx.ipfsHash, + zrx.swarmHash, + ), + ), + _.noop, ); - }).concat(tokenRegistry.addToken( - zrx.address, - zrx.name, - zrx.symbol, - zrx.decimals, - zrx.ipfsHash, - zrx.swarmHash, - )), _.noop); - } - }); + } + }); }; diff --git a/packages/contracts/migrations/4_configure_proxy.ts b/packages/contracts/migrations/4_configure_proxy.ts index f4c4a725b..ff3b844d6 100644 --- a/packages/contracts/migrations/4_configure_proxy.ts +++ b/packages/contracts/migrations/4_configure_proxy.ts @@ -1,27 +1,22 @@ -import {Artifacts} from '../util/artifacts'; -import {ContractInstance} from '../util/types'; -const { - TokenTransferProxy, - Exchange, - TokenRegistry, -} = new Artifacts(artifacts); +import { Artifacts } from '../util/artifacts'; +import { ContractInstance } from '../util/types'; +const { TokenTransferProxy, Exchange, TokenRegistry } = new Artifacts(artifacts); let tokenTransferProxy: ContractInstance; module.exports = (deployer: any) => { - deployer.then(async () => { - return Promise.all([ - TokenTransferProxy.deployed(), - TokenRegistry.deployed(), - ]); - }) - .then((instances: ContractInstance[]) => { - let tokenRegistry: ContractInstance; - [tokenTransferProxy, tokenRegistry] = instances; - return tokenRegistry.getTokenAddressBySymbol('ZRX'); - }) - .then((ptAddress: string) => { - return deployer.deploy(Exchange, ptAddress, tokenTransferProxy.address); - }).then(() => { - return tokenTransferProxy.addAuthorizedAddress(Exchange.address); - }); + deployer + .then(async () => { + return Promise.all([TokenTransferProxy.deployed(), TokenRegistry.deployed()]); + }) + .then((instances: ContractInstance[]) => { + let tokenRegistry: ContractInstance; + [tokenTransferProxy, tokenRegistry] = instances; + return tokenRegistry.getTokenAddressBySymbol('ZRX'); + }) + .then((ptAddress: string) => { + return deployer.deploy(Exchange, ptAddress, tokenTransferProxy.address); + }) + .then(() => { + return tokenTransferProxy.addAuthorizedAddress(Exchange.address); + }); }; diff --git a/packages/contracts/migrations/5_transfer_ownership.ts b/packages/contracts/migrations/5_transfer_ownership.ts index 17de9bc7b..a27801de3 100644 --- a/packages/contracts/migrations/5_transfer_ownership.ts +++ b/packages/contracts/migrations/5_transfer_ownership.ts @@ -1,25 +1,20 @@ -import {Artifacts} from '../util/artifacts'; -import {ContractInstance} from '../util/types'; -const { - TokenTransferProxy, - MultiSigWalletWithTimeLock, - TokenRegistry, -} = new Artifacts(artifacts); +import { Artifacts } from '../util/artifacts'; +import { ContractInstance } from '../util/types'; +const { TokenTransferProxy, MultiSigWalletWithTimeLock, TokenRegistry } = new Artifacts(artifacts); let tokenRegistry: ContractInstance; module.exports = (deployer: any, network: string) => { if (network !== 'development') { deployer.then(async () => { - return Promise.all([ - TokenTransferProxy.deployed(), - TokenRegistry.deployed(), - ]).then((instances: ContractInstance[]) => { - let tokenTransferProxy: ContractInstance; - [tokenTransferProxy, tokenRegistry] = instances; - return tokenTransferProxy.transferOwnership(MultiSigWalletWithTimeLock.address); - }).then(() => { - return tokenRegistry.transferOwnership(MultiSigWalletWithTimeLock.address); - }); + return Promise.all([TokenTransferProxy.deployed(), TokenRegistry.deployed()]) + .then((instances: ContractInstance[]) => { + let tokenTransferProxy: ContractInstance; + [tokenTransferProxy, tokenRegistry] = instances; + return tokenTransferProxy.transferOwnership(MultiSigWalletWithTimeLock.address); + }) + .then(() => { + return tokenRegistry.transferOwnership(MultiSigWalletWithTimeLock.address); + }); }); } }; diff --git a/packages/contracts/migrations/config/multisig_sample.ts b/packages/contracts/migrations/config/multisig_sample.ts index eca54ba28..97cdc2eae 100644 --- a/packages/contracts/migrations/config/multisig_sample.ts +++ b/packages/contracts/migrations/config/multisig_sample.ts @@ -1,4 +1,4 @@ -import {MultiSigConfigByNetwork} from '../../util/types'; +import { MultiSigConfigByNetwork } from '../../util/types'; // Make a copy of this file named `multisig.js` and input custom params as needed export const multiSig: MultiSigConfigByNetwork = { diff --git a/packages/contracts/migrations/config/token_info.ts b/packages/contracts/migrations/config/token_info.ts index 766a28664..6ae67175e 100644 --- a/packages/contracts/migrations/config/token_info.ts +++ b/packages/contracts/migrations/config/token_info.ts @@ -1,5 +1,5 @@ -import {constants} from '../../util/constants'; -import {TokenInfoByNetwork} from '../../util/types'; +import { constants } from '../../util/constants'; +import { TokenInfoByNetwork } from '../../util/types'; export const tokenInfo: TokenInfoByNetwork = { development: [ diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 92a9da53e..5a76bbf7f 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -1,71 +1,72 @@ { - "name": "contracts", - "version": "1.0.0", - "description": "Smart contract components of 0x protocol", - "main": "index.js", - "directories": { - "test": "test" - }, - "scripts": { - "build": "rm -rf ./lib; copyfiles ./build/**/* ./deploy/solc/solc_bin/* ./deploy/test/fixtures/contracts/**/* ./deploy/test/fixtures/contracts/* ./lib; tsc;", - "test": "npm run build; truffle test", - "compile": "npm run build; node lib/deploy/cli.js compile", - "clean": "rm -rf ./lib", - "migrate:truffle": "npm run build; truffle migrate", - "migrate": "npm run build; node lib/deploy/cli.js migrate", - "lint": "tslint --project . 'migrations/**/*.ts' 'test/**/*.ts' 'util/**/*.ts' 'deploy/**/*.ts'", - "test:deployer": "npm run build; mocha lib/deploy/test/*_test.js" - }, - "repository": { - "type": "git", - "url": "https://github.com/0xProject/0x.js.git" - }, - "author": "Amir Bandeali", - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/0xProject/0x.js/issues" - }, - "homepage": "https://github.com/0xProject/0x.js/packages/contracts/README.md", - "devDependencies": { - "@0xproject/tslint-config": "^0.2.0", - "@0xproject/types": "^0.0.1", - "@types/bluebird": "^3.5.3", - "@types/isomorphic-fetch": "^0.0.34", - "@types/lodash": "^4.14.86", - "@types/node": "^8.0.53", - "@types/request-promise-native": "^1.0.2", - "@types/yargs": "^8.0.2", - "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", - "dirty-chai": "^2.0.1", - "mocha": "^4.0.1", - "solc": "^0.4.18", - "truffle": "3.4.3", - "tslint": "5.8.0", - "types-bn": "^0.0.1", - "types-ethereumjs-util": "0xProject/types-ethereumjs-util", - "typescript": "~2.6.1", - "web3-typescript-typings": "^0.7.2", - "yargs": "^10.0.3" - }, - "dependencies": { - "0x.js": "^0.22.6", - "@0xproject/web3-wrapper": "^0.0.1", - "@0xproject/json-schemas": "^0.6.9", - "@0xproject/utils": "^0.0.1", - "bignumber.js": "~4.1.0", - "bluebird": "^3.5.0", - "bn.js": "^4.11.8", - "ethereumjs-abi": "^0.6.4", - "ethereumjs-util": "^5.1.1", - "isomorphic-fetch": "^2.2.1", - "lodash": "^4.17.4", - "request": "^2.81.0", - "web3": "^0.20.0", - "web3-eth-abi": "^1.0.0-beta.24" - } + "private": true, + "name": "contracts", + "version": "2.1.5", + "description": "Smart contract components of 0x protocol", + "main": "index.js", + "directories": { + "test": "test" + }, + "scripts": { + "build": "rm -rf ./lib; copyfiles ./build/**/* ./deploy/solc/solc_bin/* ./deploy/test/fixtures/contracts/**/* ./deploy/test/fixtures/contracts/* ./lib; tsc;", + "test": "npm run build; truffle test", + "compile:comment": "Yarn workspaces do not link binaries correctly so we need to reference them directly https://github.com/yarnpkg/yarn/issues/3846", + "compile": "node ../deployer/lib/src/cli.js compile", + "clean": "rm -rf ./lib", + "migrate": "node ../deployer/lib/src/cli.js migrate", + "lint": "tslint --project . 'migrations/**/*.ts' 'test/**/*.ts' 'util/**/*.ts' 'deploy/**/*.ts'", + "test:circleci": "yarn test" + }, + "repository": { + "type": "git", + "url": "https://github.com/0xProject/0x.js.git" + }, + "author": "Amir Bandeali", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/0xProject/0x.js/issues" + }, + "homepage": "https://github.com/0xProject/0x.js/packages/contracts/README.md", + "devDependencies": { + "@0xproject/dev-utils": "^0.0.6", + "@0xproject/tslint-config": "^0.4.3", + "@0xproject/types": "^0.1.5", + "@types/bluebird": "^3.5.3", + "@types/lodash": "^4.14.86", + "@types/node": "^8.0.53", + "@types/request-promise-native": "^1.0.2", + "@types/yargs": "^10.0.0", + "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", + "dirty-chai": "^2.0.1", + "mocha": "^4.0.1", + "solc": "^0.4.18", + "truffle": "^4.0.1", + "tslint": "5.8.0", + "types-bn": "^0.0.1", + "types-ethereumjs-util": "0xProject/types-ethereumjs-util", + "typescript": "~2.6.1", + "web3-typescript-typings": "^0.9.5", + "yargs": "^10.0.3" + }, + "dependencies": { + "0x.js": "^0.30.1", + "@0xproject/deployer": "^0.0.2", + "@0xproject/json-schemas": "^0.7.4", + "@0xproject/utils": "^0.2.1", + "@0xproject/web3-wrapper": "^0.1.6", + "bluebird": "^3.5.0", + "bn.js": "^4.11.8", + "ethereumjs-abi": "^0.6.4", + "ethereumjs-util": "^5.1.1", + "isomorphic-fetch": "^2.2.1", + "lodash": "^4.17.4", + "request": "^2.81.0", + "web3": "^0.20.0", + "web3-eth-abi": "^1.0.0-beta.24" + } } diff --git a/packages/contracts/test/ts/ether_token.ts b/packages/contracts/test/ts/ether_token.ts index dbb4d2ee6..f807cdaa3 100644 --- a/packages/contracts/test/ts/ether_token.ts +++ b/packages/contracts/test/ts/ether_token.ts @@ -1,14 +1,14 @@ -import {ZeroEx, ZeroExError} from '0x.js'; -import {promisify} from '@0xproject/utils'; -import {BigNumber} from 'bignumber.js'; +import { ZeroEx, ZeroExError } from '0x.js'; +import { BigNumber, promisify } from '@0xproject/utils'; import * as chai from 'chai'; import Web3 = require('web3'); -import {Artifacts} from '../../util/artifacts'; +import { Artifacts } from '../../util/artifacts'; +import { constants } from '../../util/constants'; -import {chaiSetup} from './utils/chai_setup'; +import { chaiSetup } from './utils/chai_setup'; -const {EtherToken} = new Artifacts(artifacts); +const { EtherToken } = new Artifacts(artifacts); chaiSetup.configure(); const expect = chai.expect; @@ -22,11 +22,12 @@ contract('EtherToken', (accounts: string[]) => { const gasPrice = ZeroEx.toBaseUnitAmount(new BigNumber(20), 9); let zeroEx: ZeroEx; let etherTokenAddress: string; + before(async () => { etherTokenAddress = EtherToken.address; zeroEx = new ZeroEx(web3.currentProvider, { - gasPrice, - etherTokenContractAddress: etherTokenAddress, + gasPrice, + networkId: constants.TESTRPC_NETWORK_ID, }); }); @@ -42,8 +43,9 @@ contract('EtherToken', (accounts: string[]) => { const initEthBalance = await getEthBalanceAsync(account); const ethToDeposit = initEthBalance.plus(1); - return expect(zeroEx.etherToken.depositAsync(ethToDeposit, account)) - .to.be.rejectedWith(ZeroExError.InsufficientEthBalanceForDeposit); + return expect(zeroEx.etherToken.depositAsync(etherTokenAddress, ethToDeposit, account)).to.be.rejectedWith( + ZeroExError.InsufficientEthBalanceForDeposit, + ); }); it('should convert deposited Ether to wrapped Ether tokens', async () => { @@ -52,7 +54,7 @@ contract('EtherToken', (accounts: string[]) => { const ethToDeposit = new BigNumber(web3.toWei(1, 'ether')); - const txHash = await zeroEx.etherToken.depositAsync(ethToDeposit, account); + const txHash = await zeroEx.etherToken.depositAsync(etherTokenAddress, ethToDeposit, account); const receipt = await zeroEx.awaitTransactionMinedAsync(txHash); const ethSpentOnGas = gasPrice.times(receipt.gasUsed); @@ -69,8 +71,9 @@ contract('EtherToken', (accounts: string[]) => { const initEthTokenBalance = await zeroEx.token.getBalanceAsync(etherTokenAddress, account); const ethTokensToWithdraw = initEthTokenBalance.plus(1); - return expect(zeroEx.etherToken.withdrawAsync(ethTokensToWithdraw, account)) - .to.be.rejectedWith(ZeroExError.InsufficientWEthBalanceForWithdrawal); + return expect( + zeroEx.etherToken.withdrawAsync(etherTokenAddress, ethTokensToWithdraw, account), + ).to.be.rejectedWith(ZeroExError.InsufficientWEthBalanceForWithdrawal); }); it('should convert ether tokens to ether with sufficient balance', async () => { @@ -78,15 +81,18 @@ contract('EtherToken', (accounts: string[]) => { const initEthBalance = await getEthBalanceAsync(account); const ethTokensToWithdraw = initEthTokenBalance; expect(ethTokensToWithdraw).to.not.be.bignumber.equal(0); - const txHash = await zeroEx.etherToken.withdrawAsync(ethTokensToWithdraw, account); + const txHash = await zeroEx.etherToken.withdrawAsync(etherTokenAddress, ethTokensToWithdraw, account, { + gasLimit: constants.MAX_ETHERTOKEN_WITHDRAW_GAS, + }); const receipt = await zeroEx.awaitTransactionMinedAsync(txHash); const ethSpentOnGas = gasPrice.times(receipt.gasUsed); const finalEthBalance = await getEthBalanceAsync(account); const finalEthTokenBalance = await zeroEx.token.getBalanceAsync(etherTokenAddress, account); - expect(finalEthBalance).to.be.bignumber - .equal(initEthBalance.plus(ethTokensToWithdraw.minus(ethSpentOnGas))); + expect(finalEthBalance).to.be.bignumber.equal( + initEthBalance.plus(ethTokensToWithdraw.minus(ethSpentOnGas)), + ); expect(finalEthTokenBalance).to.be.bignumber.equal(initEthTokenBalance.minus(ethTokensToWithdraw)); }); }); diff --git a/packages/contracts/test/ts/exchange/core.ts b/packages/contracts/test/ts/exchange/core.ts index daf46ca37..770ef0c43 100644 --- a/packages/contracts/test/ts/exchange/core.ts +++ b/packages/contracts/test/ts/exchange/core.ts @@ -1,28 +1,22 @@ -import {ZeroEx} from '0x.js'; -import {BigNumber} from 'bignumber.js'; +import { ZeroEx } from '0x.js'; +import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import ethUtil = require('ethereumjs-util'); import * as Web3 from 'web3'; -import {Artifacts} from '../../../util/artifacts'; -import {Balances} from '../../../util/balances'; -import {constants} from '../../../util/constants'; -import {crypto} from '../../../util/crypto'; -import {ExchangeWrapper} from '../../../util/exchange_wrapper'; -import {Order} from '../../../util/order'; -import {OrderFactory} from '../../../util/order_factory'; -import {BalancesByOwner, ContractInstance, ExchangeContractErrs} from '../../../util/types'; -import {chaiSetup} from '../utils/chai_setup'; +import { Artifacts } from '../../../util/artifacts'; +import { Balances } from '../../../util/balances'; +import { constants } from '../../../util/constants'; +import { crypto } from '../../../util/crypto'; +import { ExchangeWrapper } from '../../../util/exchange_wrapper'; +import { Order } from '../../../util/order'; +import { OrderFactory } from '../../../util/order_factory'; +import { BalancesByOwner, ContractInstance, ExchangeContractErrs } from '../../../util/types'; +import { chaiSetup } from '../utils/chai_setup'; chaiSetup.configure(); const expect = chai.expect; -const { - Exchange, - TokenTransferProxy, - DummyToken, - TokenRegistry, - MaliciousToken, -} = new Artifacts(artifacts); +const { Exchange, TokenTransferProxy, DummyToken, TokenRegistry, MaliciousToken } = new Artifacts(artifacts); // In order to benefit from type-safety, we re-assign the global web3 instance injected by Truffle // with type `any` to a variable of type `Web3`. @@ -52,13 +46,11 @@ contract('Exchange', (accounts: string[]) => { let zeroEx: ZeroEx; before(async () => { - [tokenRegistry, exchange] = await Promise.all([ - TokenRegistry.deployed(), - Exchange.deployed(), - ]); + [tokenRegistry, exchange] = await Promise.all([TokenRegistry.deployed(), Exchange.deployed()]); exWrapper = new ExchangeWrapper(exchange); zeroEx = new ZeroEx(web3.currentProvider, { exchangeContractAddress: exchange.address, + networkId: constants.TESTRPC_NETWORK_ID, }); const [repAddress, dgdAddress, zrxAddress] = await Promise.all([ @@ -87,18 +79,30 @@ contract('Exchange', (accounts: string[]) => { ]); dmyBalances = new Balances([rep, dgd, zrx], [maker, taker, feeRecipient]); await Promise.all([ - rep.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {from: maker}), - rep.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {from: taker}), - rep.setBalance(maker, INITIAL_BALANCE, {from: tokenOwner}), - rep.setBalance(taker, INITIAL_BALANCE, {from: tokenOwner}), - dgd.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {from: maker}), - dgd.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {from: taker}), - dgd.setBalance(maker, INITIAL_BALANCE, {from: tokenOwner}), - dgd.setBalance(taker, INITIAL_BALANCE, {from: tokenOwner}), - zrx.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {from: maker}), - zrx.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {from: taker}), - zrx.setBalance(maker, INITIAL_BALANCE, {from: tokenOwner}), - zrx.setBalance(taker, INITIAL_BALANCE, {from: tokenOwner}), + rep.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, { + from: maker, + }), + rep.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, { + from: taker, + }), + rep.setBalance(maker, INITIAL_BALANCE, { from: tokenOwner }), + rep.setBalance(taker, INITIAL_BALANCE, { from: tokenOwner }), + dgd.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, { + from: maker, + }), + dgd.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, { + from: taker, + }), + dgd.setBalance(maker, INITIAL_BALANCE, { from: tokenOwner }), + dgd.setBalance(taker, INITIAL_BALANCE, { from: tokenOwner }), + zrx.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, { + from: maker, + }), + zrx.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, { + from: taker, + }), + zrx.setBalance(maker, INITIAL_BALANCE, { from: tokenOwner }), + zrx.setBalance(taker, INITIAL_BALANCE, { from: tokenOwner }), ]); }); @@ -132,22 +136,29 @@ contract('Exchange', (accounts: string[]) => { takerTokenAmount: new BigNumber(3), }); - const filledTakerTokenAmountBefore = - await zeroEx.exchange.getFilledTakerAmountAsync(order.params.orderHashHex); + const filledTakerTokenAmountBefore = await zeroEx.exchange.getFilledTakerAmountAsync( + order.params.orderHashHex, + ); expect(filledTakerTokenAmountBefore).to.be.bignumber.equal(0); const fillTakerTokenAmount1 = new BigNumber(2); - await exWrapper.fillOrderAsync(order, taker, {fillTakerTokenAmount: fillTakerTokenAmount1}); + await exWrapper.fillOrderAsync(order, taker, { + fillTakerTokenAmount: fillTakerTokenAmount1, + }); - const filledTakerTokenAmountAfter1 = - await zeroEx.exchange.getFilledTakerAmountAsync(order.params.orderHashHex); + const filledTakerTokenAmountAfter1 = await zeroEx.exchange.getFilledTakerAmountAsync( + order.params.orderHashHex, + ); expect(filledTakerTokenAmountAfter1).to.be.bignumber.equal(fillTakerTokenAmount1); const fillTakerTokenAmount2 = new BigNumber(1); - await exWrapper.fillOrderAsync(order, taker, {fillTakerTokenAmount: fillTakerTokenAmount2}); + await exWrapper.fillOrderAsync(order, taker, { + fillTakerTokenAmount: fillTakerTokenAmount2, + }); - const filledTakerTokenAmountAfter2 = - await zeroEx.exchange.getFilledTakerAmountAsync(order.params.orderHashHex); + const filledTakerTokenAmountAfter2 = await zeroEx.exchange.getFilledTakerAmountAsync( + order.params.orderHashHex, + ); expect(filledTakerTokenAmountAfter2).to.be.bignumber.equal(filledTakerTokenAmountAfter1); }); @@ -157,42 +168,51 @@ contract('Exchange', (accounts: string[]) => { takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100), 18), }); - const filledTakerTokenAmountBefore = - await zeroEx.exchange.getFilledTakerAmountAsync(order.params.orderHashHex); + const filledTakerTokenAmountBefore = await zeroEx.exchange.getFilledTakerAmountAsync( + order.params.orderHashHex, + ); expect(filledTakerTokenAmountBefore).to.be.bignumber.equal(0); const fillTakerTokenAmount = order.params.takerTokenAmount.div(2); - await exWrapper.fillOrderAsync(order, taker, {fillTakerTokenAmount}); + await exWrapper.fillOrderAsync(order, taker, { fillTakerTokenAmount }); - const filledTakerTokenAmountAfter = - await zeroEx.exchange.getFilledTakerAmountAsync(order.params.orderHashHex); + const filledTakerTokenAmountAfter = await zeroEx.exchange.getFilledTakerAmountAsync( + order.params.orderHashHex, + ); expect(filledTakerTokenAmountAfter).to.be.bignumber.equal(fillTakerTokenAmount); const newBalances = await dmyBalances.getAsync(); const fillMakerTokenAmount = fillTakerTokenAmount - .times(order.params.makerTokenAmount) - .dividedToIntegerBy(order.params.takerTokenAmount); + .times(order.params.makerTokenAmount) + .dividedToIntegerBy(order.params.takerTokenAmount); const paidMakerFee = order.params.makerFee - .times(fillMakerTokenAmount) - .dividedToIntegerBy(order.params.makerTokenAmount); + .times(fillMakerTokenAmount) + .dividedToIntegerBy(order.params.makerTokenAmount); const paidTakerFee = order.params.takerFee - .times(fillMakerTokenAmount) - .dividedToIntegerBy(order.params.makerTokenAmount); - expect(newBalances[maker][order.params.makerToken]) - .to.be.bignumber.equal(balances[maker][order.params.makerToken].minus(fillMakerTokenAmount)); - expect(newBalances[maker][order.params.takerToken]) - .to.be.bignumber.equal(balances[maker][order.params.takerToken].add(fillTakerTokenAmount)); - expect(newBalances[maker][zrx.address]).to.be.bignumber - .equal(balances[maker][zrx.address].minus(paidMakerFee)); - expect(newBalances[taker][order.params.takerToken]) - .to.be.bignumber.equal(balances[taker][order.params.takerToken].minus(fillTakerTokenAmount)); - expect(newBalances[taker][order.params.makerToken]) - .to.be.bignumber.equal(balances[taker][order.params.makerToken].add(fillMakerTokenAmount)); - expect(newBalances[taker][zrx.address]).to.be.bignumber - .equal(balances[taker][zrx.address].minus(paidTakerFee)); - expect(newBalances[feeRecipient][zrx.address]) - .to.be.bignumber.equal(balances[feeRecipient][zrx.address].add(paidMakerFee.add(paidTakerFee))); + .times(fillMakerTokenAmount) + .dividedToIntegerBy(order.params.makerTokenAmount); + expect(newBalances[maker][order.params.makerToken]).to.be.bignumber.equal( + balances[maker][order.params.makerToken].minus(fillMakerTokenAmount), + ); + expect(newBalances[maker][order.params.takerToken]).to.be.bignumber.equal( + balances[maker][order.params.takerToken].add(fillTakerTokenAmount), + ); + expect(newBalances[maker][zrx.address]).to.be.bignumber.equal( + balances[maker][zrx.address].minus(paidMakerFee), + ); + expect(newBalances[taker][order.params.takerToken]).to.be.bignumber.equal( + balances[taker][order.params.takerToken].minus(fillTakerTokenAmount), + ); + expect(newBalances[taker][order.params.makerToken]).to.be.bignumber.equal( + balances[taker][order.params.makerToken].add(fillMakerTokenAmount), + ); + expect(newBalances[taker][zrx.address]).to.be.bignumber.equal( + balances[taker][zrx.address].minus(paidTakerFee), + ); + expect(newBalances[feeRecipient][zrx.address]).to.be.bignumber.equal( + balances[feeRecipient][zrx.address].add(paidMakerFee.add(paidTakerFee)), + ); }); it('should transfer the correct amounts when makerTokenAmount > takerTokenAmount', async () => { @@ -201,42 +221,51 @@ contract('Exchange', (accounts: string[]) => { takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100), 18), }); - const filledTakerTokenAmountBefore = - await zeroEx.exchange.getFilledTakerAmountAsync(order.params.orderHashHex); + const filledTakerTokenAmountBefore = await zeroEx.exchange.getFilledTakerAmountAsync( + order.params.orderHashHex, + ); expect(filledTakerTokenAmountBefore).to.be.bignumber.equal(0); const fillTakerTokenAmount = order.params.takerTokenAmount.div(2); - await exWrapper.fillOrderAsync(order, taker, {fillTakerTokenAmount}); + await exWrapper.fillOrderAsync(order, taker, { fillTakerTokenAmount }); - const filledTakerTokenAmountAfter = - await zeroEx.exchange.getFilledTakerAmountAsync(order.params.orderHashHex); + const filledTakerTokenAmountAfter = await zeroEx.exchange.getFilledTakerAmountAsync( + order.params.orderHashHex, + ); expect(filledTakerTokenAmountAfter).to.be.bignumber.equal(fillTakerTokenAmount); const newBalances = await dmyBalances.getAsync(); const fillMakerTokenAmount = fillTakerTokenAmount - .times(order.params.makerTokenAmount) - .dividedToIntegerBy(order.params.takerTokenAmount); + .times(order.params.makerTokenAmount) + .dividedToIntegerBy(order.params.takerTokenAmount); const paidMakerFee = order.params.makerFee - .times(fillMakerTokenAmount) - .dividedToIntegerBy(order.params.makerTokenAmount); + .times(fillMakerTokenAmount) + .dividedToIntegerBy(order.params.makerTokenAmount); const paidTakerFee = order.params.takerFee - .times(fillMakerTokenAmount) - .dividedToIntegerBy(order.params.makerTokenAmount); - expect(newBalances[maker][order.params.makerToken]) - .to.be.bignumber.equal(balances[maker][order.params.makerToken].minus(fillMakerTokenAmount)); - expect(newBalances[maker][order.params.takerToken]) - .to.be.bignumber.equal(balances[maker][order.params.takerToken].add(fillTakerTokenAmount)); - expect(newBalances[maker][zrx.address]).to.be.bignumber - .equal(balances[maker][zrx.address].minus(paidMakerFee)); - expect(newBalances[taker][order.params.takerToken]) - .to.be.bignumber.equal(balances[taker][order.params.takerToken].minus(fillTakerTokenAmount)); - expect(newBalances[taker][order.params.makerToken]) - .to.be.bignumber.equal(balances[taker][order.params.makerToken].add(fillMakerTokenAmount)); - expect(newBalances[taker][zrx.address]).to.be.bignumber - .equal(balances[taker][zrx.address].minus(paidTakerFee)); - expect(newBalances[feeRecipient][zrx.address]) - .to.be.bignumber.equal(balances[feeRecipient][zrx.address].add(paidMakerFee.add(paidTakerFee))); + .times(fillMakerTokenAmount) + .dividedToIntegerBy(order.params.makerTokenAmount); + expect(newBalances[maker][order.params.makerToken]).to.be.bignumber.equal( + balances[maker][order.params.makerToken].minus(fillMakerTokenAmount), + ); + expect(newBalances[maker][order.params.takerToken]).to.be.bignumber.equal( + balances[maker][order.params.takerToken].add(fillTakerTokenAmount), + ); + expect(newBalances[maker][zrx.address]).to.be.bignumber.equal( + balances[maker][zrx.address].minus(paidMakerFee), + ); + expect(newBalances[taker][order.params.takerToken]).to.be.bignumber.equal( + balances[taker][order.params.takerToken].minus(fillTakerTokenAmount), + ); + expect(newBalances[taker][order.params.makerToken]).to.be.bignumber.equal( + balances[taker][order.params.makerToken].add(fillMakerTokenAmount), + ); + expect(newBalances[taker][zrx.address]).to.be.bignumber.equal( + balances[taker][zrx.address].minus(paidTakerFee), + ); + expect(newBalances[feeRecipient][zrx.address]).to.be.bignumber.equal( + balances[feeRecipient][zrx.address].add(paidMakerFee.add(paidTakerFee)), + ); }); it('should transfer the correct amounts when makerTokenAmount < takerTokenAmount', async () => { @@ -245,42 +274,51 @@ contract('Exchange', (accounts: string[]) => { takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(200), 18), }); - const filledTakerTokenAmountBefore = - await zeroEx.exchange.getFilledTakerAmountAsync(order.params.orderHashHex); + const filledTakerTokenAmountBefore = await zeroEx.exchange.getFilledTakerAmountAsync( + order.params.orderHashHex, + ); expect(filledTakerTokenAmountBefore).to.be.bignumber.equal(0); const fillTakerTokenAmount = order.params.takerTokenAmount.div(2); - await exWrapper.fillOrderAsync(order, taker, {fillTakerTokenAmount}); + await exWrapper.fillOrderAsync(order, taker, { fillTakerTokenAmount }); - const filledTakerTokenAmountAfter = - await zeroEx.exchange.getFilledTakerAmountAsync(order.params.orderHashHex); + const filledTakerTokenAmountAfter = await zeroEx.exchange.getFilledTakerAmountAsync( + order.params.orderHashHex, + ); expect(filledTakerTokenAmountAfter).to.be.bignumber.equal(fillTakerTokenAmount); const newBalances = await dmyBalances.getAsync(); const fillMakerTokenAmount = fillTakerTokenAmount - .times(order.params.makerTokenAmount) - .dividedToIntegerBy(order.params.takerTokenAmount); + .times(order.params.makerTokenAmount) + .dividedToIntegerBy(order.params.takerTokenAmount); const paidMakerFee = order.params.makerFee - .times(fillMakerTokenAmount) - .dividedToIntegerBy(order.params.makerTokenAmount); + .times(fillMakerTokenAmount) + .dividedToIntegerBy(order.params.makerTokenAmount); const paidTakerFee = order.params.takerFee - .times(fillMakerTokenAmount) - .dividedToIntegerBy(order.params.makerTokenAmount); - expect(newBalances[maker][order.params.makerToken]) - .to.be.bignumber.equal(balances[maker][order.params.makerToken].minus(fillMakerTokenAmount)); - expect(newBalances[maker][order.params.takerToken]) - .to.be.bignumber.equal(balances[maker][order.params.takerToken].add(fillTakerTokenAmount)); - expect(newBalances[maker][zrx.address]).to.be.bignumber - .equal(balances[maker][zrx.address].minus(paidMakerFee)); - expect(newBalances[taker][order.params.takerToken]) - .to.be.bignumber.equal(balances[taker][order.params.takerToken].minus(fillTakerTokenAmount)); - expect(newBalances[taker][order.params.makerToken]) - .to.be.bignumber.equal(balances[taker][order.params.makerToken].add(fillMakerTokenAmount)); - expect(newBalances[taker][zrx.address]).to.be.bignumber - .equal(balances[taker][zrx.address].minus(paidTakerFee)); - expect(newBalances[feeRecipient][zrx.address]) - .to.be.bignumber.equal(balances[feeRecipient][zrx.address].add(paidMakerFee.add(paidTakerFee))); + .times(fillMakerTokenAmount) + .dividedToIntegerBy(order.params.makerTokenAmount); + expect(newBalances[maker][order.params.makerToken]).to.be.bignumber.equal( + balances[maker][order.params.makerToken].minus(fillMakerTokenAmount), + ); + expect(newBalances[maker][order.params.takerToken]).to.be.bignumber.equal( + balances[maker][order.params.takerToken].add(fillTakerTokenAmount), + ); + expect(newBalances[maker][zrx.address]).to.be.bignumber.equal( + balances[maker][zrx.address].minus(paidMakerFee), + ); + expect(newBalances[taker][order.params.takerToken]).to.be.bignumber.equal( + balances[taker][order.params.takerToken].minus(fillTakerTokenAmount), + ); + expect(newBalances[taker][order.params.makerToken]).to.be.bignumber.equal( + balances[taker][order.params.makerToken].add(fillMakerTokenAmount), + ); + expect(newBalances[taker][zrx.address]).to.be.bignumber.equal( + balances[taker][zrx.address].minus(paidTakerFee), + ); + expect(newBalances[feeRecipient][zrx.address]).to.be.bignumber.equal( + balances[feeRecipient][zrx.address].add(paidMakerFee.add(paidTakerFee)), + ); }); it('should transfer the correct amounts when taker is specified and order is claimed by taker', async () => { @@ -290,78 +328,95 @@ contract('Exchange', (accounts: string[]) => { takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(200), 18), }); - const filledTakerTokenAmountBefore = - await zeroEx.exchange.getFilledTakerAmountAsync(order.params.orderHashHex); + const filledTakerTokenAmountBefore = await zeroEx.exchange.getFilledTakerAmountAsync( + order.params.orderHashHex, + ); expect(filledTakerTokenAmountBefore).to.be.bignumber.equal(0); const fillTakerTokenAmount = order.params.takerTokenAmount.div(2); - await exWrapper.fillOrderAsync(order, taker, {fillTakerTokenAmount}); + await exWrapper.fillOrderAsync(order, taker, { fillTakerTokenAmount }); - const filledTakerTokenAmountAfter = - await zeroEx.exchange.getFilledTakerAmountAsync(order.params.orderHashHex); + const filledTakerTokenAmountAfter = await zeroEx.exchange.getFilledTakerAmountAsync( + order.params.orderHashHex, + ); const expectedFillAmountTAfter = fillTakerTokenAmount.add(filledTakerTokenAmountBefore); expect(filledTakerTokenAmountAfter).to.be.bignumber.equal(expectedFillAmountTAfter); const newBalances = await dmyBalances.getAsync(); const fillMakerTokenAmount = fillTakerTokenAmount - .times(order.params.makerTokenAmount) - .dividedToIntegerBy(order.params.takerTokenAmount); + .times(order.params.makerTokenAmount) + .dividedToIntegerBy(order.params.takerTokenAmount); const paidMakerFee = order.params.makerFee - .times(fillMakerTokenAmount) - .dividedToIntegerBy(order.params.makerTokenAmount); + .times(fillMakerTokenAmount) + .dividedToIntegerBy(order.params.makerTokenAmount); const paidTakerFee = order.params.takerFee - .times(fillMakerTokenAmount) - .dividedToIntegerBy(order.params.makerTokenAmount); - expect(newBalances[maker][order.params.makerToken]) - .to.be.bignumber.equal(balances[maker][order.params.makerToken].minus(fillMakerTokenAmount)); - expect(newBalances[maker][order.params.takerToken]) - .to.be.bignumber.equal(balances[maker][order.params.takerToken].add(fillTakerTokenAmount)); - expect(newBalances[maker][zrx.address]).to.be.bignumber - .equal(balances[maker][zrx.address].minus(paidMakerFee)); - expect(newBalances[taker][order.params.takerToken]) - .to.be.bignumber.equal(balances[taker][order.params.takerToken].minus(fillTakerTokenAmount)); - expect(newBalances[taker][order.params.makerToken]) - .to.be.bignumber.equal(balances[taker][order.params.makerToken].add(fillMakerTokenAmount)); - expect(newBalances[taker][zrx.address]).to.be.bignumber - .equal(balances[taker][zrx.address].minus(paidTakerFee)); - expect(newBalances[feeRecipient][zrx.address]) - .to.be.bignumber.equal(balances[feeRecipient][zrx.address].add(paidMakerFee.add(paidTakerFee))); + .times(fillMakerTokenAmount) + .dividedToIntegerBy(order.params.makerTokenAmount); + expect(newBalances[maker][order.params.makerToken]).to.be.bignumber.equal( + balances[maker][order.params.makerToken].minus(fillMakerTokenAmount), + ); + expect(newBalances[maker][order.params.takerToken]).to.be.bignumber.equal( + balances[maker][order.params.takerToken].add(fillTakerTokenAmount), + ); + expect(newBalances[maker][zrx.address]).to.be.bignumber.equal( + balances[maker][zrx.address].minus(paidMakerFee), + ); + expect(newBalances[taker][order.params.takerToken]).to.be.bignumber.equal( + balances[taker][order.params.takerToken].minus(fillTakerTokenAmount), + ); + expect(newBalances[taker][order.params.makerToken]).to.be.bignumber.equal( + balances[taker][order.params.makerToken].add(fillMakerTokenAmount), + ); + expect(newBalances[taker][zrx.address]).to.be.bignumber.equal( + balances[taker][zrx.address].minus(paidTakerFee), + ); + expect(newBalances[feeRecipient][zrx.address]).to.be.bignumber.equal( + balances[feeRecipient][zrx.address].add(paidMakerFee.add(paidTakerFee)), + ); }); it('should fill remaining value if fillTakerTokenAmount > remaining takerTokenAmount', async () => { const fillTakerTokenAmount = order.params.takerTokenAmount.div(2); - await exWrapper.fillOrderAsync(order, taker, {fillTakerTokenAmount}); + await exWrapper.fillOrderAsync(order, taker, { fillTakerTokenAmount }); - const res = await exWrapper.fillOrderAsync(order, taker, - {fillTakerTokenAmount: order.params.takerTokenAmount}); + const res = await exWrapper.fillOrderAsync(order, taker, { + fillTakerTokenAmount: order.params.takerTokenAmount, + }); - expect(res.logs[0].args.filledTakerTokenAmount) - .to.be.bignumber.equal(order.params.takerTokenAmount.minus(fillTakerTokenAmount)); + expect(res.logs[0].args.filledTakerTokenAmount).to.be.bignumber.equal( + order.params.takerTokenAmount.minus(fillTakerTokenAmount), + ); const newBalances = await dmyBalances.getAsync(); - expect(newBalances[maker][order.params.makerToken]) - .to.be.bignumber.equal(balances[maker][order.params.makerToken].minus(order.params.makerTokenAmount)); - expect(newBalances[maker][order.params.takerToken]) - .to.be.bignumber.equal(balances[maker][order.params.takerToken].add(order.params.takerTokenAmount)); - expect(newBalances[maker][zrx.address]) - .to.be.bignumber.equal(balances[maker][zrx.address].minus(order.params.makerFee)); - expect(newBalances[taker][order.params.takerToken]) - .to.be.bignumber.equal(balances[taker][order.params.takerToken].minus(order.params.takerTokenAmount)); - expect(newBalances[taker][order.params.makerToken]) - .to.be.bignumber.equal(balances[taker][order.params.makerToken].add(order.params.makerTokenAmount)); - expect(newBalances[taker][zrx.address]) - .to.be.bignumber.equal(balances[taker][zrx.address].minus(order.params.takerFee)); - expect(newBalances[feeRecipient][zrx.address]) - .to.be.bignumber.equal( - balances[feeRecipient][zrx.address].add(order.params.makerFee.add(order.params.takerFee)), - ); + expect(newBalances[maker][order.params.makerToken]).to.be.bignumber.equal( + balances[maker][order.params.makerToken].minus(order.params.makerTokenAmount), + ); + expect(newBalances[maker][order.params.takerToken]).to.be.bignumber.equal( + balances[maker][order.params.takerToken].add(order.params.takerTokenAmount), + ); + expect(newBalances[maker][zrx.address]).to.be.bignumber.equal( + balances[maker][zrx.address].minus(order.params.makerFee), + ); + expect(newBalances[taker][order.params.takerToken]).to.be.bignumber.equal( + balances[taker][order.params.takerToken].minus(order.params.takerTokenAmount), + ); + expect(newBalances[taker][order.params.makerToken]).to.be.bignumber.equal( + balances[taker][order.params.makerToken].add(order.params.makerTokenAmount), + ); + expect(newBalances[taker][zrx.address]).to.be.bignumber.equal( + balances[taker][zrx.address].minus(order.params.takerFee), + ); + expect(newBalances[feeRecipient][zrx.address]).to.be.bignumber.equal( + balances[feeRecipient][zrx.address].add(order.params.makerFee.add(order.params.takerFee)), + ); }); it('should log 1 event with the correct arguments when order has a feeRecipient', async () => { const divisor = 2; - const res = await exWrapper.fillOrderAsync(order, taker, - {fillTakerTokenAmount: order.params.takerTokenAmount.div(divisor)}); + const res = await exWrapper.fillOrderAsync(order, taker, { + fillTakerTokenAmount: order.params.takerTokenAmount.div(divisor), + }); expect(res.logs).to.have.length(1); const logArgs = res.logs[0].args; @@ -390,8 +445,9 @@ contract('Exchange', (accounts: string[]) => { feeRecipient: ZeroEx.NULL_ADDRESS, }); const divisor = 2; - const res = await exWrapper.fillOrderAsync(order, taker, - {fillTakerTokenAmount: order.params.takerTokenAmount.div(divisor)}); + const res = await exWrapper.fillOrderAsync(order, taker, { + fillTakerTokenAmount: order.params.takerTokenAmount.div(divisor), + }); expect(res.logs).to.have.length(1); const logArgs = res.logs[0].args; @@ -422,7 +478,7 @@ contract('Exchange', (accounts: string[]) => { takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(200), 18), }); - return expect(exWrapper.fillOrderAsync(order, taker)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(exWrapper.fillOrderAsync(order, taker)).to.be.rejectedWith(constants.REVERT); }); it('should throw if signature is invalid', async () => { @@ -432,7 +488,7 @@ contract('Exchange', (accounts: string[]) => { order.params.r = ethUtil.bufferToHex(ethUtil.sha3('invalidR')); order.params.s = ethUtil.bufferToHex(ethUtil.sha3('invalidS')); - return expect(exWrapper.fillOrderAsync(order, taker)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(exWrapper.fillOrderAsync(order, taker)).to.be.rejectedWith(constants.REVERT); }); it('should throw if makerTokenAmount is 0', async () => { @@ -440,7 +496,7 @@ contract('Exchange', (accounts: string[]) => { makerTokenAmount: new BigNumber(0), }); - return expect(exWrapper.fillOrderAsync(order, taker)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(exWrapper.fillOrderAsync(order, taker)).to.be.rejectedWith(constants.REVERT); }); it('should throw if takerTokenAmount is 0', async () => { @@ -448,19 +504,21 @@ contract('Exchange', (accounts: string[]) => { takerTokenAmount: new BigNumber(0), }); - return expect(exWrapper.fillOrderAsync(order, taker)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(exWrapper.fillOrderAsync(order, taker)).to.be.rejectedWith(constants.REVERT); }); it('should throw if fillTakerTokenAmount is 0', async () => { order = await orderFactory.newSignedOrderAsync(); - return expect(exWrapper.fillOrderAsync(order, taker, {fillTakerTokenAmount: new BigNumber(0)})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect( + exWrapper.fillOrderAsync(order, taker, { + fillTakerTokenAmount: new BigNumber(0), + }), + ).to.be.rejectedWith(constants.REVERT); }); it('should not change balances if maker balances are too low to fill order and \ - shouldThrowOnInsufficientBalanceOrAllowance = false', - async () => { + shouldThrowOnInsufficientBalanceOrAllowance = false', async () => { order = await orderFactory.newSignedOrderAsync({ makerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100000), 18), }); @@ -471,19 +529,20 @@ contract('Exchange', (accounts: string[]) => { }); it('should throw if maker balances are too low to fill order and \ - shouldThrowOnInsufficientBalanceOrAllowance = true', - async () => { + shouldThrowOnInsufficientBalanceOrAllowance = true', async () => { order = await orderFactory.newSignedOrderAsync({ makerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100000), 18), }); - return expect(exWrapper.fillOrderAsync(order, taker, {shouldThrowOnInsufficientBalanceOrAllowance: true})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect( + exWrapper.fillOrderAsync(order, taker, { + shouldThrowOnInsufficientBalanceOrAllowance: true, + }), + ).to.be.rejectedWith(constants.REVERT); }); it('should not change balances if taker balances are too low to fill order and \ - shouldThrowOnInsufficientBalanceOrAllowance = false', - async () => { + shouldThrowOnInsufficientBalanceOrAllowance = false', async () => { order = await orderFactory.newSignedOrderAsync({ takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100000), 18), }); @@ -494,59 +553,70 @@ contract('Exchange', (accounts: string[]) => { }); it('should throw if taker balances are too low to fill order and \ - shouldThrowOnInsufficientBalanceOrAllowance = true', - async () => { + shouldThrowOnInsufficientBalanceOrAllowance = true', async () => { order = await orderFactory.newSignedOrderAsync({ takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(100000), 18), }); - return expect(exWrapper.fillOrderAsync(order, taker, {shouldThrowOnInsufficientBalanceOrAllowance: true})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect( + exWrapper.fillOrderAsync(order, taker, { + shouldThrowOnInsufficientBalanceOrAllowance: true, + }), + ).to.be.rejectedWith(constants.REVERT); }); it('should not change balances if maker allowances are too low to fill order and \ - shouldThrowOnInsufficientBalanceOrAllowance = false', - async () => { - await rep.approve(TokenTransferProxy.address, 0, {from: maker}); + shouldThrowOnInsufficientBalanceOrAllowance = false', async () => { + await rep.approve(TokenTransferProxy.address, 0, { from: maker }); await exWrapper.fillOrderAsync(order, taker); - await rep.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {from: maker}); + await rep.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, { + from: maker, + }); const newBalances = await dmyBalances.getAsync(); expect(newBalances).to.be.deep.equal(balances); }); it('should throw if maker allowances are too low to fill order and \ - shouldThrowOnInsufficientBalanceOrAllowance = true', - async () => { - await rep.approve(TokenTransferProxy.address, 0, {from: maker}); - expect(exWrapper.fillOrderAsync(order, taker, {shouldThrowOnInsufficientBalanceOrAllowance: true})) - .to.be.rejectedWith(constants.INVALID_OPCODE); - await rep.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {from: maker}); + shouldThrowOnInsufficientBalanceOrAllowance = true', async () => { + await rep.approve(TokenTransferProxy.address, 0, { from: maker }); + expect( + exWrapper.fillOrderAsync(order, taker, { + shouldThrowOnInsufficientBalanceOrAllowance: true, + }), + ).to.be.rejectedWith(constants.REVERT); + await rep.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, { + from: maker, + }); }); it('should not change balances if taker allowances are too low to fill order and \ - shouldThrowOnInsufficientBalanceOrAllowance = false', - async () => { - await dgd.approve(TokenTransferProxy.address, 0, {from: taker}); + shouldThrowOnInsufficientBalanceOrAllowance = false', async () => { + await dgd.approve(TokenTransferProxy.address, 0, { from: taker }); await exWrapper.fillOrderAsync(order, taker); - await dgd.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {from: taker}); + await dgd.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, { + from: taker, + }); const newBalances = await dmyBalances.getAsync(); expect(newBalances).to.be.deep.equal(balances); }); it('should throw if taker allowances are too low to fill order and \ - shouldThrowOnInsufficientBalanceOrAllowance = true', - async () => { - await dgd.approve(TokenTransferProxy.address, 0, {from: taker}); - expect(exWrapper.fillOrderAsync(order, taker, {shouldThrowOnInsufficientBalanceOrAllowance: true})) - .to.be.rejectedWith(constants.INVALID_OPCODE); - await dgd.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {from: taker}); + shouldThrowOnInsufficientBalanceOrAllowance = true', async () => { + await dgd.approve(TokenTransferProxy.address, 0, { from: taker }); + expect( + exWrapper.fillOrderAsync(order, taker, { + shouldThrowOnInsufficientBalanceOrAllowance: true, + }), + ).to.be.rejectedWith(constants.REVERT); + await dgd.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, { + from: taker, + }); }); it('should not change balances if makerToken is ZRX, makerTokenAmount + makerFee > maker balance, \ - and shouldThrowOnInsufficientBalanceOrAllowance = false', - async () => { + and shouldThrowOnInsufficientBalanceOrAllowance = false', async () => { const makerZRXBalance = new BigNumber(balances[maker][zrx.address]); order = await orderFactory.newSignedOrderAsync({ makerToken: zrx.address, @@ -559,8 +629,7 @@ contract('Exchange', (accounts: string[]) => { }); it('should not change balances if makerToken is ZRX, makerTokenAmount + makerFee > maker allowance, \ - and shouldThrowOnInsufficientBalanceOrAllowance = false', - async () => { + and shouldThrowOnInsufficientBalanceOrAllowance = false', async () => { const makerZRXAllowance = await zrx.allowance(maker, TokenTransferProxy.address); order = await orderFactory.newSignedOrderAsync({ makerToken: zrx.address, @@ -573,8 +642,7 @@ contract('Exchange', (accounts: string[]) => { }); it('should not change balances if takerToken is ZRX, takerTokenAmount + takerFee > taker balance, \ - and shouldThrowOnInsufficientBalanceOrAllowance = false', - async () => { + and shouldThrowOnInsufficientBalanceOrAllowance = false', async () => { const takerZRXBalance = new BigNumber(balances[taker][zrx.address]); order = await orderFactory.newSignedOrderAsync({ takerToken: zrx.address, @@ -587,8 +655,7 @@ contract('Exchange', (accounts: string[]) => { }); it('should not change balances if takerToken is ZRX, takerTokenAmount + takerFee > taker allowance, \ - and shouldThrowOnInsufficientBalanceOrAllowance = false', - async () => { + and shouldThrowOnInsufficientBalanceOrAllowance = false', async () => { const takerZRXAllowance = await zrx.allowance(taker, TokenTransferProxy.address); order = await orderFactory.newSignedOrderAsync({ takerToken: zrx.address, @@ -603,14 +670,17 @@ contract('Exchange', (accounts: string[]) => { it('should throw if getBalance or getAllowance attempts to change state and \ shouldThrowOnInsufficientBalanceOrAllowance = false', async () => { const maliciousToken = await MaliciousToken.new(); - await maliciousToken.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, {from: taker}); + await maliciousToken.approve(TokenTransferProxy.address, INITIAL_ALLOWANCE, { from: taker }); order = await orderFactory.newSignedOrderAsync({ takerToken: maliciousToken.address, }); - return expect(exWrapper.fillOrderAsync(order, taker, {shouldThrowOnInsufficientBalanceOrAllowance: false})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect( + exWrapper.fillOrderAsync(order, taker, { + shouldThrowOnInsufficientBalanceOrAllowance: false, + }), + ).to.be.rejectedWith(constants.REVERT); }); it('should not change balances if an order is expired', async () => { @@ -651,7 +721,7 @@ contract('Exchange', (accounts: string[]) => { }); it('should throw if not sent by maker', async () => { - return expect(exWrapper.cancelOrderAsync(order, taker)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(exWrapper.cancelOrderAsync(order, taker)).to.be.rejectedWith(constants.REVERT); }); it('should throw if makerTokenAmount is 0', async () => { @@ -659,7 +729,7 @@ contract('Exchange', (accounts: string[]) => { makerTokenAmount: new BigNumber(0), }); - return expect(exWrapper.cancelOrderAsync(order, maker)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(exWrapper.cancelOrderAsync(order, maker)).to.be.rejectedWith(constants.REVERT); }); it('should throw if takerTokenAmount is 0', async () => { @@ -667,19 +737,24 @@ contract('Exchange', (accounts: string[]) => { takerTokenAmount: new BigNumber(0), }); - return expect(exWrapper.cancelOrderAsync(order, maker)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(exWrapper.cancelOrderAsync(order, maker)).to.be.rejectedWith(constants.REVERT); }); it('should throw if cancelTakerTokenAmount is 0', async () => { order = await orderFactory.newSignedOrderAsync(); - return expect(exWrapper.cancelOrderAsync(order, maker, {cancelTakerTokenAmount: new BigNumber(0)})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect( + exWrapper.cancelOrderAsync(order, maker, { + cancelTakerTokenAmount: new BigNumber(0), + }), + ).to.be.rejectedWith(constants.REVERT); }); it('should be able to cancel a full order', async () => { await exWrapper.cancelOrderAsync(order, maker); - await exWrapper.fillOrderAsync(order, taker, {fillTakerTokenAmount: order.params.takerTokenAmount.div(2)}); + await exWrapper.fillOrderAsync(order, taker, { + fillTakerTokenAmount: order.params.takerTokenAmount.div(2), + }); const newBalances = await dmyBalances.getAsync(); expect(newBalances).to.be.deep.equal(balances); @@ -687,43 +762,55 @@ contract('Exchange', (accounts: string[]) => { it('should be able to cancel part of an order', async () => { const cancelTakerTokenAmount = order.params.takerTokenAmount.div(2); - await exWrapper.cancelOrderAsync(order, maker, {cancelTakerTokenAmount}); + await exWrapper.cancelOrderAsync(order, maker, { + cancelTakerTokenAmount, + }); - const res = await exWrapper.fillOrderAsync(order, taker, - {fillTakerTokenAmount: order.params.takerTokenAmount}); - expect(res.logs[0].args.filledTakerTokenAmount) - .to.be.bignumber.equal(order.params.takerTokenAmount.minus(cancelTakerTokenAmount)); + const res = await exWrapper.fillOrderAsync(order, taker, { + fillTakerTokenAmount: order.params.takerTokenAmount, + }); + expect(res.logs[0].args.filledTakerTokenAmount).to.be.bignumber.equal( + order.params.takerTokenAmount.minus(cancelTakerTokenAmount), + ); const newBalances = await dmyBalances.getAsync(); const cancelMakerTokenAmount = cancelTakerTokenAmount - .times(order.params.makerTokenAmount) - .dividedToIntegerBy(order.params.takerTokenAmount); + .times(order.params.makerTokenAmount) + .dividedToIntegerBy(order.params.takerTokenAmount); const paidMakerFee = order.params.makerFee - .times(cancelMakerTokenAmount) - .dividedToIntegerBy(order.params.makerTokenAmount); + .times(cancelMakerTokenAmount) + .dividedToIntegerBy(order.params.makerTokenAmount); const paidTakerFee = order.params.takerFee - .times(cancelMakerTokenAmount) - .dividedToIntegerBy(order.params.makerTokenAmount); - expect(newBalances[maker][order.params.makerToken]) - .to.be.bignumber.equal(balances[maker][order.params.makerToken].minus(cancelMakerTokenAmount)); - expect(newBalances[maker][order.params.takerToken]) - .to.be.bignumber.equal(balances[maker][order.params.takerToken].add(cancelTakerTokenAmount)); - expect(newBalances[maker][zrx.address]) - .to.be.bignumber.equal(balances[maker][zrx.address].minus(paidMakerFee)); - expect(newBalances[taker][order.params.takerToken]) - .to.be.bignumber.equal(balances[taker][order.params.takerToken].minus(cancelTakerTokenAmount)); - expect(newBalances[taker][order.params.makerToken]) - .to.be.bignumber.equal(balances[taker][order.params.makerToken].add(cancelMakerTokenAmount)); - expect(newBalances[taker][zrx.address]).to.be.bignumber - .equal(balances[taker][zrx.address].minus(paidTakerFee)); - expect(newBalances[feeRecipient][zrx.address]) - .to.be.bignumber.equal(balances[feeRecipient][zrx.address].add(paidMakerFee.add(paidTakerFee))); + .times(cancelMakerTokenAmount) + .dividedToIntegerBy(order.params.makerTokenAmount); + expect(newBalances[maker][order.params.makerToken]).to.be.bignumber.equal( + balances[maker][order.params.makerToken].minus(cancelMakerTokenAmount), + ); + expect(newBalances[maker][order.params.takerToken]).to.be.bignumber.equal( + balances[maker][order.params.takerToken].add(cancelTakerTokenAmount), + ); + expect(newBalances[maker][zrx.address]).to.be.bignumber.equal( + balances[maker][zrx.address].minus(paidMakerFee), + ); + expect(newBalances[taker][order.params.takerToken]).to.be.bignumber.equal( + balances[taker][order.params.takerToken].minus(cancelTakerTokenAmount), + ); + expect(newBalances[taker][order.params.makerToken]).to.be.bignumber.equal( + balances[taker][order.params.makerToken].add(cancelMakerTokenAmount), + ); + expect(newBalances[taker][zrx.address]).to.be.bignumber.equal( + balances[taker][zrx.address].minus(paidTakerFee), + ); + expect(newBalances[feeRecipient][zrx.address]).to.be.bignumber.equal( + balances[feeRecipient][zrx.address].add(paidMakerFee.add(paidTakerFee)), + ); }); it('should log 1 event with correct arguments', async () => { const divisor = 2; - const res = await exWrapper.cancelOrderAsync(order, maker, - {cancelTakerTokenAmount: order.params.takerTokenAmount.div(divisor)}); + const res = await exWrapper.cancelOrderAsync(order, maker, { + cancelTakerTokenAmount: order.params.takerTokenAmount.div(divisor), + }); expect(res.logs).to.have.length(1); const logArgs = res.logs[0].args; @@ -747,7 +834,6 @@ contract('Exchange', (accounts: string[]) => { const res = await exWrapper.cancelOrderAsync(order, maker); expect(res.logs).to.have.length(1); - const errId = res.logs[0].args.errorId.toNumber(); const errCode = res.logs[0].args.errorId.toNumber(); expect(errCode).to.be.equal(ExchangeContractErrs.ERROR_ORDER_FULLY_FILLED_OR_CANCELLED); }); diff --git a/packages/contracts/test/ts/exchange/helpers.ts b/packages/contracts/test/ts/exchange/helpers.ts index a39f4d9e2..95f68e419 100644 --- a/packages/contracts/test/ts/exchange/helpers.ts +++ b/packages/contracts/test/ts/exchange/helpers.ts @@ -1,21 +1,18 @@ -import {ZeroEx} from '0x.js'; -import {BigNumber} from 'bignumber.js'; +import { ZeroEx } from '0x.js'; +import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import ethUtil = require('ethereumjs-util'); -import {Artifacts} from '../../../util/artifacts'; -import {ExchangeWrapper} from '../../../util/exchange_wrapper'; -import {Order} from '../../../util/order'; -import {OrderFactory} from '../../../util/order_factory'; -import {chaiSetup} from '../utils/chai_setup'; +import { Artifacts } from '../../../util/artifacts'; +import { ExchangeWrapper } from '../../../util/exchange_wrapper'; +import { Order } from '../../../util/order'; +import { OrderFactory } from '../../../util/order_factory'; +import { chaiSetup } from '../utils/chai_setup'; chaiSetup.configure(); const expect = chai.expect; -const { - Exchange, - TokenRegistry, -} = new Artifacts(artifacts); +const { Exchange, TokenRegistry } = new Artifacts(artifacts); contract('Exchange', (accounts: string[]) => { const maker = accounts[0]; @@ -26,10 +23,7 @@ contract('Exchange', (accounts: string[]) => { let orderFactory: OrderFactory; before(async () => { - const [tokenRegistry, exchange] = await Promise.all([ - TokenRegistry.deployed(), - Exchange.deployed(), - ]); + const [tokenRegistry, exchange] = await Promise.all([TokenRegistry.deployed(), Exchange.deployed()]); exchangeWrapper = new ExchangeWrapper(exchange); const [repAddress, dgdAddress] = await Promise.all([ tokenRegistry.getTokenAddressBySymbol('REP'), diff --git a/packages/contracts/test/ts/exchange/wrapper.ts b/packages/contracts/test/ts/exchange/wrapper.ts index c40d60104..e69e08bcf 100644 --- a/packages/contracts/test/ts/exchange/wrapper.ts +++ b/packages/contracts/test/ts/exchange/wrapper.ts @@ -1,25 +1,20 @@ -import {ZeroEx} from '0x.js'; -import {BigNumber} from 'bignumber.js'; +import { ZeroEx } from '0x.js'; +import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import * as _ from 'lodash'; -import {Artifacts} from '../../../util/artifacts'; -import {Balances} from '../../../util/balances'; -import {constants} from '../../../util/constants'; -import {ExchangeWrapper} from '../../../util/exchange_wrapper'; -import {Order} from '../../../util/order'; -import {OrderFactory} from '../../../util/order_factory'; -import {BalancesByOwner, ContractInstance} from '../../../util/types'; -import {chaiSetup} from '../utils/chai_setup'; +import { Artifacts } from '../../../util/artifacts'; +import { Balances } from '../../../util/balances'; +import { constants } from '../../../util/constants'; +import { ExchangeWrapper } from '../../../util/exchange_wrapper'; +import { Order } from '../../../util/order'; +import { OrderFactory } from '../../../util/order_factory'; +import { BalancesByOwner, ContractInstance } from '../../../util/types'; +import { chaiSetup } from '../utils/chai_setup'; chaiSetup.configure(); const expect = chai.expect; -const { - Exchange, - TokenTransferProxy, - DummyToken, - TokenRegistry, -} = new Artifacts(artifacts); +const { Exchange, TokenTransferProxy, DummyToken, TokenRegistry } = new Artifacts(artifacts); contract('Exchange', (accounts: string[]) => { const maker = accounts[0]; @@ -43,10 +38,7 @@ contract('Exchange', (accounts: string[]) => { let orderFactory: OrderFactory; before(async () => { - [tokenRegistry, exchange] = await Promise.all([ - TokenRegistry.deployed(), - Exchange.deployed(), - ]); + [tokenRegistry, exchange] = await Promise.all([TokenRegistry.deployed(), Exchange.deployed()]); exWrapper = new ExchangeWrapper(exchange); const [repAddress, dgdAddress, zrxAddress] = await Promise.all([ tokenRegistry.getTokenAddressBySymbol('REP'), @@ -74,18 +66,18 @@ contract('Exchange', (accounts: string[]) => { ]); dmyBalances = new Balances([rep, dgd, zrx], [maker, taker, feeRecipient]); await Promise.all([ - rep.approve(TokenTransferProxy.address, INIT_ALLOW, {from: maker}), - rep.approve(TokenTransferProxy.address, INIT_ALLOW, {from: taker}), - rep.setBalance(maker, INIT_BAL, {from: tokenOwner}), - rep.setBalance(taker, INIT_BAL, {from: tokenOwner}), - dgd.approve(TokenTransferProxy.address, INIT_ALLOW, {from: maker}), - dgd.approve(TokenTransferProxy.address, INIT_ALLOW, {from: taker}), - dgd.setBalance(maker, INIT_BAL, {from: tokenOwner}), - dgd.setBalance(taker, INIT_BAL, {from: tokenOwner}), - zrx.approve(TokenTransferProxy.address, INIT_ALLOW, {from: maker}), - zrx.approve(TokenTransferProxy.address, INIT_ALLOW, {from: taker}), - zrx.setBalance(maker, INIT_BAL, {from: tokenOwner}), - zrx.setBalance(taker, INIT_BAL, {from: tokenOwner}), + rep.approve(TokenTransferProxy.address, INIT_ALLOW, { from: maker }), + rep.approve(TokenTransferProxy.address, INIT_ALLOW, { from: taker }), + rep.setBalance(maker, INIT_BAL, { from: tokenOwner }), + rep.setBalance(taker, INIT_BAL, { from: tokenOwner }), + dgd.approve(TokenTransferProxy.address, INIT_ALLOW, { from: maker }), + dgd.approve(TokenTransferProxy.address, INIT_ALLOW, { from: taker }), + dgd.setBalance(maker, INIT_BAL, { from: tokenOwner }), + dgd.setBalance(taker, INIT_BAL, { from: tokenOwner }), + zrx.approve(TokenTransferProxy.address, INIT_ALLOW, { from: maker }), + zrx.approve(TokenTransferProxy.address, INIT_ALLOW, { from: taker }), + zrx.setBalance(maker, INIT_BAL, { from: tokenOwner }), + zrx.setBalance(taker, INIT_BAL, { from: tokenOwner }), ]); }); @@ -100,31 +92,38 @@ contract('Exchange', (accounts: string[]) => { takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(200), 18), }); const fillTakerTokenAmount = order.params.takerTokenAmount.div(2); - await exWrapper.fillOrKillOrderAsync(order, taker, {fillTakerTokenAmount}); + await exWrapper.fillOrKillOrderAsync(order, taker, { + fillTakerTokenAmount, + }); const newBalances = await dmyBalances.getAsync(); const fillMakerTokenAmount = fillTakerTokenAmount - .times(order.params.makerTokenAmount) - .dividedToIntegerBy(order.params.takerTokenAmount); + .times(order.params.makerTokenAmount) + .dividedToIntegerBy(order.params.takerTokenAmount); const makerFee = order.params.makerFee - .times(fillMakerTokenAmount) - .dividedToIntegerBy(order.params.makerTokenAmount); + .times(fillMakerTokenAmount) + .dividedToIntegerBy(order.params.makerTokenAmount); const takerFee = order.params.takerFee - .times(fillMakerTokenAmount) - .dividedToIntegerBy(order.params.makerTokenAmount); - expect(newBalances[maker][order.params.makerToken]) - .to.be.bignumber.equal(balances[maker][order.params.makerToken].minus(fillMakerTokenAmount)); - expect(newBalances[maker][order.params.takerToken]) - .to.be.bignumber.equal(balances[maker][order.params.takerToken].add(fillTakerTokenAmount)); + .times(fillMakerTokenAmount) + .dividedToIntegerBy(order.params.makerTokenAmount); + expect(newBalances[maker][order.params.makerToken]).to.be.bignumber.equal( + balances[maker][order.params.makerToken].minus(fillMakerTokenAmount), + ); + expect(newBalances[maker][order.params.takerToken]).to.be.bignumber.equal( + balances[maker][order.params.takerToken].add(fillTakerTokenAmount), + ); expect(newBalances[maker][zrx.address]).to.be.bignumber.equal(balances[maker][zrx.address].minus(makerFee)); - expect(newBalances[taker][order.params.takerToken]) - .to.be.bignumber.equal(balances[taker][order.params.takerToken].minus(fillTakerTokenAmount)); - expect(newBalances[taker][order.params.makerToken]) - .to.be.bignumber.equal(balances[taker][order.params.makerToken].add(fillMakerTokenAmount)); + expect(newBalances[taker][order.params.takerToken]).to.be.bignumber.equal( + balances[taker][order.params.takerToken].minus(fillTakerTokenAmount), + ); + expect(newBalances[taker][order.params.makerToken]).to.be.bignumber.equal( + balances[taker][order.params.makerToken].add(fillMakerTokenAmount), + ); expect(newBalances[taker][zrx.address]).to.be.bignumber.equal(balances[taker][zrx.address].minus(takerFee)); - expect(newBalances[feeRecipient][zrx.address]) - .to.be.bignumber.equal(balances[feeRecipient][zrx.address].add(makerFee.add(takerFee))); + expect(newBalances[feeRecipient][zrx.address]).to.be.bignumber.equal( + balances[feeRecipient][zrx.address].add(makerFee.add(takerFee)), + ); }); it('should throw if an order is expired', async () => { @@ -132,18 +131,18 @@ contract('Exchange', (accounts: string[]) => { expirationTimestampInSec: new BigNumber(Math.floor((Date.now() - 10000) / 1000)), }); - return expect(exWrapper.fillOrKillOrderAsync(order, taker)) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(exWrapper.fillOrKillOrderAsync(order, taker)).to.be.rejectedWith(constants.REVERT); }); it('should throw if entire fillTakerTokenAmount not filled', async () => { const order = await orderFactory.newSignedOrderAsync(); const from = taker; - await exWrapper.fillOrderAsync(order, from, {fillTakerTokenAmount: order.params.takerTokenAmount.div(2)}); + await exWrapper.fillOrderAsync(order, from, { + fillTakerTokenAmount: order.params.takerTokenAmount.div(2), + }); - return expect(exWrapper.fillOrKillOrderAsync(order, taker)) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(exWrapper.fillOrKillOrderAsync(order, taker)).to.be.rejectedWith(constants.REVERT); }); }); @@ -166,14 +165,14 @@ contract('Exchange', (accounts: string[]) => { orders.forEach(order => { const fillTakerTokenAmount = order.params.takerTokenAmount.div(2); const fillMakerTokenAmount = fillTakerTokenAmount - .times(order.params.makerTokenAmount) - .dividedToIntegerBy(order.params.takerTokenAmount); + .times(order.params.makerTokenAmount) + .dividedToIntegerBy(order.params.takerTokenAmount); const makerFee = order.params.makerFee - .times(fillMakerTokenAmount) - .dividedToIntegerBy(order.params.makerTokenAmount); + .times(fillMakerTokenAmount) + .dividedToIntegerBy(order.params.makerTokenAmount); const takerFee = order.params.takerFee - .times(fillMakerTokenAmount) - .dividedToIntegerBy(order.params.makerTokenAmount); + .times(fillMakerTokenAmount) + .dividedToIntegerBy(order.params.makerTokenAmount); fillTakerTokenAmounts.push(fillTakerTokenAmount); balances[maker][makerToken] = balances[maker][makerToken].minus(fillMakerTokenAmount); balances[maker][takerToken] = balances[maker][takerToken].add(fillTakerTokenAmount); @@ -181,11 +180,14 @@ contract('Exchange', (accounts: string[]) => { balances[taker][makerToken] = balances[taker][makerToken].add(fillMakerTokenAmount); balances[taker][takerToken] = balances[taker][takerToken].minus(fillTakerTokenAmount); balances[taker][zrx.address] = balances[taker][zrx.address].minus(takerFee); - balances[feeRecipient][zrx.address] = - balances[feeRecipient][zrx.address].add(makerFee.add(takerFee)); + balances[feeRecipient][zrx.address] = balances[feeRecipient][zrx.address].add( + makerFee.add(takerFee), + ); }); - await exWrapper.batchFillOrdersAsync(orders, taker, {fillTakerTokenAmounts}); + await exWrapper.batchFillOrdersAsync(orders, taker, { + fillTakerTokenAmounts, + }); const newBalances = await dmyBalances.getAsync(); expect(newBalances).to.be.deep.equal(balances); @@ -200,14 +202,14 @@ contract('Exchange', (accounts: string[]) => { orders.forEach(order => { const fillTakerTokenAmount = order.params.takerTokenAmount.div(2); const fillMakerTokenAmount = fillTakerTokenAmount - .times(order.params.makerTokenAmount) - .dividedToIntegerBy(order.params.takerTokenAmount); + .times(order.params.makerTokenAmount) + .dividedToIntegerBy(order.params.takerTokenAmount); const makerFee = order.params.makerFee - .times(fillMakerTokenAmount) - .dividedToIntegerBy(order.params.makerTokenAmount); + .times(fillMakerTokenAmount) + .dividedToIntegerBy(order.params.makerTokenAmount); const takerFee = order.params.takerFee - .times(fillMakerTokenAmount) - .dividedToIntegerBy(order.params.makerTokenAmount); + .times(fillMakerTokenAmount) + .dividedToIntegerBy(order.params.makerTokenAmount); fillTakerTokenAmounts.push(fillTakerTokenAmount); balances[maker][makerToken] = balances[maker][makerToken].minus(fillMakerTokenAmount); balances[maker][takerToken] = balances[maker][takerToken].add(fillTakerTokenAmount); @@ -215,11 +217,14 @@ contract('Exchange', (accounts: string[]) => { balances[taker][makerToken] = balances[taker][makerToken].add(fillMakerTokenAmount); balances[taker][takerToken] = balances[taker][takerToken].minus(fillTakerTokenAmount); balances[taker][zrx.address] = balances[taker][zrx.address].minus(takerFee); - balances[feeRecipient][zrx.address] = - balances[feeRecipient][zrx.address].add(makerFee.add(takerFee)); + balances[feeRecipient][zrx.address] = balances[feeRecipient][zrx.address].add( + makerFee.add(takerFee), + ); }); - await exWrapper.batchFillOrKillOrdersAsync(orders, taker, {fillTakerTokenAmounts}); + await exWrapper.batchFillOrKillOrdersAsync(orders, taker, { + fillTakerTokenAmounts, + }); const newBalances = await dmyBalances.getAsync(); expect(newBalances).to.be.deep.equal(balances); @@ -227,8 +232,6 @@ contract('Exchange', (accounts: string[]) => { it('should throw if a single order does not fill the expected amount', async () => { const fillTakerTokenAmounts: BigNumber[] = []; - const makerToken = rep.address; - const takerToken = dgd.address; orders.forEach(order => { const fillTakerTokenAmount = order.params.takerTokenAmount.div(2); fillTakerTokenAmounts.push(fillTakerTokenAmount); @@ -236,57 +239,77 @@ contract('Exchange', (accounts: string[]) => { await exWrapper.fillOrKillOrderAsync(orders[0], taker); - return expect(exWrapper.batchFillOrKillOrdersAsync(orders, taker, {fillTakerTokenAmounts})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect( + exWrapper.batchFillOrKillOrdersAsync(orders, taker, { + fillTakerTokenAmounts, + }), + ).to.be.rejectedWith(constants.REVERT); }); }); describe('fillOrdersUpTo', () => { it('should stop when the entire fillTakerTokenAmount is filled', async () => { - const fillTakerTokenAmount = - orders[0].params.takerTokenAmount.plus(orders[1].params.takerTokenAmount.div(2)); - await exWrapper.fillOrdersUpToAsync(orders, taker, {fillTakerTokenAmount}); + const fillTakerTokenAmount = orders[0].params.takerTokenAmount.plus( + orders[1].params.takerTokenAmount.div(2), + ); + await exWrapper.fillOrdersUpToAsync(orders, taker, { + fillTakerTokenAmount, + }); const newBalances = await dmyBalances.getAsync(); const fillMakerTokenAmount = orders[0].params.makerTokenAmount.add( - orders[1].params.makerTokenAmount.dividedToIntegerBy(2)); + orders[1].params.makerTokenAmount.dividedToIntegerBy(2), + ); const makerFee = orders[0].params.makerFee.add(orders[1].params.makerFee.dividedToIntegerBy(2)); const takerFee = orders[0].params.takerFee.add(orders[1].params.takerFee.dividedToIntegerBy(2)); - expect(newBalances[maker][orders[0].params.makerToken]) - .to.be.bignumber.equal(balances[maker][orders[0].params.makerToken].minus(fillMakerTokenAmount)); - expect(newBalances[maker][orders[0].params.takerToken]) - .to.be.bignumber.equal(balances[maker][orders[0].params.takerToken].add(fillTakerTokenAmount)); - expect(newBalances[maker][zrx.address]).to.be.bignumber - .equal(balances[maker][zrx.address].minus(makerFee)); - expect(newBalances[taker][orders[0].params.takerToken]) - .to.be.bignumber.equal(balances[taker][orders[0].params.takerToken].minus(fillTakerTokenAmount)); - expect(newBalances[taker][orders[0].params.makerToken]) - .to.be.bignumber.equal(balances[taker][orders[0].params.makerToken].add(fillMakerTokenAmount)); - expect(newBalances[taker][zrx.address]).to.be.bignumber - .equal(balances[taker][zrx.address].minus(takerFee)); - expect(newBalances[feeRecipient][zrx.address]) - .to.be.bignumber.equal(balances[feeRecipient][zrx.address].add(makerFee.add(takerFee))); + expect(newBalances[maker][orders[0].params.makerToken]).to.be.bignumber.equal( + balances[maker][orders[0].params.makerToken].minus(fillMakerTokenAmount), + ); + expect(newBalances[maker][orders[0].params.takerToken]).to.be.bignumber.equal( + balances[maker][orders[0].params.takerToken].add(fillTakerTokenAmount), + ); + expect(newBalances[maker][zrx.address]).to.be.bignumber.equal( + balances[maker][zrx.address].minus(makerFee), + ); + expect(newBalances[taker][orders[0].params.takerToken]).to.be.bignumber.equal( + balances[taker][orders[0].params.takerToken].minus(fillTakerTokenAmount), + ); + expect(newBalances[taker][orders[0].params.makerToken]).to.be.bignumber.equal( + balances[taker][orders[0].params.makerToken].add(fillMakerTokenAmount), + ); + expect(newBalances[taker][zrx.address]).to.be.bignumber.equal( + balances[taker][zrx.address].minus(takerFee), + ); + expect(newBalances[feeRecipient][zrx.address]).to.be.bignumber.equal( + balances[feeRecipient][zrx.address].add(makerFee.add(takerFee)), + ); }); it('should fill all orders if cannot fill entire fillTakerTokenAmount', async () => { const fillTakerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(100000), 18); orders.forEach(order => { - balances[maker][order.params.makerToken] = balances[maker][order.params.makerToken] - .minus(order.params.makerTokenAmount); - balances[maker][order.params.takerToken] = balances[maker][order.params.takerToken] - .add(order.params.takerTokenAmount); - balances[maker][zrx.address] = balances[maker][zrx.address] - .minus(order.params.makerFee); - balances[taker][order.params.makerToken] = balances[taker][order.params.makerToken] - .add(order.params.makerTokenAmount); - balances[taker][order.params.takerToken] = balances[taker][order.params.takerToken] - .minus(order.params.takerTokenAmount); + balances[maker][order.params.makerToken] = balances[maker][order.params.makerToken].minus( + order.params.makerTokenAmount, + ); + balances[maker][order.params.takerToken] = balances[maker][order.params.takerToken].add( + order.params.takerTokenAmount, + ); + balances[maker][zrx.address] = balances[maker][zrx.address].minus(order.params.makerFee); + balances[taker][order.params.makerToken] = balances[taker][order.params.makerToken].add( + order.params.makerTokenAmount, + ); + balances[taker][order.params.takerToken] = balances[taker][order.params.takerToken].minus( + order.params.takerTokenAmount, + ); balances[taker][zrx.address] = balances[taker][zrx.address].minus(order.params.takerFee); - balances[feeRecipient][zrx.address] = - balances[feeRecipient][zrx.address].add(order.params.makerFee.add(order.params.takerFee)); + balances[feeRecipient][zrx.address] = balances[feeRecipient][zrx.address].add( + order.params.makerFee.add(order.params.takerFee), + ); + }); + await exWrapper.fillOrdersUpToAsync(orders, taker, { + fillTakerTokenAmount, }); - await exWrapper.fillOrdersUpToAsync(orders, taker, {fillTakerTokenAmount}); const newBalances = await dmyBalances.getAsync(); expect(newBalances).to.be.deep.equal(balances); @@ -295,24 +318,28 @@ contract('Exchange', (accounts: string[]) => { it('should throw when an order does not use the same takerToken', async () => { orders = await Promise.all([ orderFactory.newSignedOrderAsync(), - orderFactory.newSignedOrderAsync({takerToken: zrx.address}), + orderFactory.newSignedOrderAsync({ takerToken: zrx.address }), orderFactory.newSignedOrderAsync(), ]); return expect( - exWrapper.fillOrdersUpToAsync( - orders, taker, {fillTakerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(1000), 18)}), - ).to.be.rejectedWith(constants.INVALID_OPCODE); + exWrapper.fillOrdersUpToAsync(orders, taker, { + fillTakerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(1000), 18), + }), + ).to.be.rejectedWith(constants.REVERT); }); }); describe('batchCancelOrders', () => { it('should be able to cancel multiple orders', async () => { const cancelTakerTokenAmounts = _.map(orders, order => order.params.takerTokenAmount); - await exWrapper.batchCancelOrdersAsync(orders, maker, {cancelTakerTokenAmounts}); + await exWrapper.batchCancelOrdersAsync(orders, maker, { + cancelTakerTokenAmounts, + }); - const res = await exWrapper.batchFillOrdersAsync( - orders, taker, {fillTakerTokenAmounts: cancelTakerTokenAmounts}); + await exWrapper.batchFillOrdersAsync(orders, taker, { + fillTakerTokenAmounts: cancelTakerTokenAmounts, + }); const newBalances = await dmyBalances.getAsync(); expect(balances).to.be.deep.equal(newBalances); }); diff --git a/packages/contracts/test/ts/multi_sig_with_time_lock.ts b/packages/contracts/test/ts/multi_sig_with_time_lock.ts index 6dd4dc3b2..ea939a758 100644 --- a/packages/contracts/test/ts/multi_sig_with_time_lock.ts +++ b/packages/contracts/test/ts/multi_sig_with_time_lock.ts @@ -1,18 +1,18 @@ -import {promisify} from '@0xproject/utils'; -import {BigNumber} from 'bignumber.js'; +import { RPC } from '@0xproject/dev-utils'; +import { BigNumber, promisify } from '@0xproject/utils'; import * as chai from 'chai'; import Web3 = require('web3'); import * as multiSigWalletJSON from '../../build/contracts/MultiSigWalletWithTimeLock.json'; -import {Artifacts} from '../../util/artifacts'; -import {constants} from '../../util/constants'; -import {MultiSigWrapper} from '../../util/multi_sig_wrapper'; -import {RPC} from '../../util/rpc'; -import {ContractInstance} from '../../util/types'; +import * as truffleConf from '../../truffle.js'; +import { Artifacts } from '../../util/artifacts'; +import { constants } from '../../util/constants'; +import { MultiSigWrapper } from '../../util/multi_sig_wrapper'; +import { ContractInstance } from '../../util/types'; -import {chaiSetup} from './utils/chai_setup'; +import { chaiSetup } from './utils/chai_setup'; -const {MultiSigWalletWithTimeLock} = new Artifacts(artifacts); +const { MultiSigWalletWithTimeLock } = new Artifacts(artifacts); const MULTI_SIG_ABI = (multiSigWalletJSON as any).abi; chaiSetup.configure(); @@ -38,13 +38,15 @@ contract('MultiSigWalletWithTimeLock', (accounts: string[]) => { const secondsTimeLocked = await multiSig.secondsTimeLocked.call(); initialSecondsTimeLocked = secondsTimeLocked.toNumber(); - rpc = new RPC(); + const rpcUrl = `http://${truffleConf.networks.development.host}:${truffleConf.networks.development.port}`; + rpc = new RPC(rpcUrl); }); describe('changeTimeLock', () => { it('should throw when not called by wallet', async () => { - return expect(multiSig.changeTimeLock(SECONDS_TIME_LOCKED, {from: owners[0]})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(multiSig.changeTimeLock(SECONDS_TIME_LOCKED, { from: owners[0] })).to.be.rejectedWith( + constants.REVERT, + ); }); it('should throw without enough confirmations', async () => { @@ -58,11 +60,11 @@ contract('MultiSigWalletWithTimeLock', (accounts: string[]) => { const subRes = await multiSigWrapper.submitTransactionAsync(destination, from, dataParams); txId = subRes.logs[0].args.transactionId.toNumber(); - return expect(multiSig.executeTransaction(txId)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(multiSig.executeTransaction(txId)).to.be.rejectedWith(constants.REVERT); }); it('should set confirmation time with enough confirmations', async () => { - const res = await multiSig.confirmTransaction(txId, {from: owners[1]}); + const res = await multiSig.confirmTransaction(txId, { from: owners[1] }); expect(res.logs).to.have.length(2); const blockNum = await promisify<number>(web3.eth.getBlockNumber)(); const blockInfo = await promisify<Web3.BlockWithoutTransactionData>(web3.eth.getBlock)(blockNum); @@ -94,10 +96,12 @@ contract('MultiSigWalletWithTimeLock', (accounts: string[]) => { const subRes = await multiSigWrapper.submitTransactionAsync(destination, from, dataParams); txId = subRes.logs[0].args.transactionId.toNumber(); - const confRes = await multiSig.confirmTransaction(txId, {from: owners[1]}); + const confRes = await multiSig.confirmTransaction(txId, { + from: owners[1], + }); expect(confRes.logs).to.have.length(2); - return expect(multiSig.executeTransaction(txId)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(multiSig.executeTransaction(txId)).to.be.rejectedWith(constants.REVERT); }); it('should execute if it has enough confirmations and is past the time lock', async () => { diff --git a/packages/contracts/test/ts/multi_sig_with_time_lock_except_remove_auth_addr.ts b/packages/contracts/test/ts/multi_sig_with_time_lock_except_remove_auth_addr.ts index 97ccac2bd..62aa625fe 100644 --- a/packages/contracts/test/ts/multi_sig_with_time_lock_except_remove_auth_addr.ts +++ b/packages/contracts/test/ts/multi_sig_with_time_lock_except_remove_auth_addr.ts @@ -1,14 +1,14 @@ import * as chai from 'chai'; import * as tokenTransferProxyJSON from '../../build/contracts/TokenTransferProxy.json'; -import {Artifacts} from '../../util/artifacts'; -import {constants} from '../../util/constants'; -import {crypto} from '../../util/crypto'; -import {MultiSigWrapper} from '../../util/multi_sig_wrapper'; -import {ContractInstance, TransactionDataParams} from '../../util/types'; - -import {chaiSetup} from './utils/chai_setup'; -const {TokenTransferProxy, MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress} = new Artifacts(artifacts); +import { Artifacts } from '../../util/artifacts'; +import { constants } from '../../util/constants'; +import { crypto } from '../../util/crypto'; +import { MultiSigWrapper } from '../../util/multi_sig_wrapper'; +import { ContractInstance, TransactionDataParams } from '../../util/types'; + +import { chaiSetup } from './utils/chai_setup'; +const { TokenTransferProxy, MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress } = new Artifacts(artifacts); const PROXY_ABI = (tokenTransferProxyJSON as any).abi; chaiSetup.configure(); @@ -20,8 +20,14 @@ contract('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', (accounts: s const SECONDS_TIME_LOCKED = 1000000; // initialize fake addresses - const authorizedAddress = `0x${crypto.solSHA3([accounts[0]]).slice(0, 20).toString('hex')}`; - const unauthorizedAddress = `0x${crypto.solSHA3([accounts[1]]).slice(0, 20).toString('hex')}`; + const authorizedAddress = `0x${crypto + .solSHA3([accounts[0]]) + .slice(0, 20) + .toString('hex')}`; + const unauthorizedAddress = `0x${crypto + .solSHA3([accounts[1]]) + .slice(0, 20) + .toString('hex')}`; let tokenTransferProxy: ContractInstance; let multiSig: ContractInstance; @@ -31,11 +37,19 @@ contract('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', (accounts: s beforeEach(async () => { const initialOwner = accounts[0]; - tokenTransferProxy = await TokenTransferProxy.new({from: initialOwner}); - await tokenTransferProxy.addAuthorizedAddress(authorizedAddress, {from: initialOwner}); + tokenTransferProxy = await TokenTransferProxy.new({ from: initialOwner }); + await tokenTransferProxy.addAuthorizedAddress(authorizedAddress, { + from: initialOwner, + }); multiSig = await MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress.new( - owners, requiredApprovals, SECONDS_TIME_LOCKED, tokenTransferProxy.address); - await tokenTransferProxy.transferOwnership(multiSig.address, {from: initialOwner}); + owners, + requiredApprovals, + SECONDS_TIME_LOCKED, + tokenTransferProxy.address, + ); + await tokenTransferProxy.transferOwnership(multiSig.address, { + from: initialOwner, + }); multiSigWrapper = new MultiSigWrapper(multiSig); validDestination = tokenTransferProxy.address; }); @@ -43,8 +57,7 @@ contract('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', (accounts: s describe('isFunctionRemoveAuthorizedAddress', () => { it('should throw if data is not for removeAuthorizedAddress', async () => { const data = MultiSigWrapper.encodeFnArgs('addAuthorizedAddress', PROXY_ABI, [owners[0]]); - return expect(multiSig.isFunctionRemoveAuthorizedAddress.call(data)) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(multiSig.isFunctionRemoveAuthorizedAddress.call(data)).to.be.rejectedWith(constants.REVERT); }); it('should return true if data is for removeAuthorizedAddress', async () => { @@ -64,7 +77,7 @@ contract('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', (accounts: s const res = await multiSigWrapper.submitTransactionAsync(validDestination, owners[0], dataParams); const txId = res.logs[0].args.transactionId.toString(); - return expect(multiSig.executeRemoveAuthorizedAddress(txId)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(multiSig.executeRemoveAuthorizedAddress(txId)).to.be.rejectedWith(constants.REVERT); }); it('should throw if tx destination is not the tokenTransferProxy', async () => { @@ -77,11 +90,11 @@ contract('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', (accounts: s }; const res = await multiSigWrapper.submitTransactionAsync(invalidDestination, owners[0], dataParams); const txId = res.logs[0].args.transactionId.toString(); - await multiSig.confirmTransaction(txId, {from: owners[1]}); + await multiSig.confirmTransaction(txId, { from: owners[1] }); const isConfirmed = await multiSig.isConfirmed.call(txId); expect(isConfirmed).to.be.true(); - return expect(multiSig.executeRemoveAuthorizedAddress(txId)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(multiSig.executeRemoveAuthorizedAddress(txId)).to.be.rejectedWith(constants.REVERT); }); it('should throw if tx data is not for removeAuthorizedAddress', async () => { @@ -92,11 +105,11 @@ contract('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', (accounts: s }; const res = await multiSigWrapper.submitTransactionAsync(validDestination, owners[0], dataParams); const txId = res.logs[0].args.transactionId.toString(); - await multiSig.confirmTransaction(txId, {from: owners[1]}); + await multiSig.confirmTransaction(txId, { from: owners[1] }); const isConfirmed = await multiSig.isConfirmed.call(txId); expect(isConfirmed).to.be.true(); - return expect(multiSig.executeRemoveAuthorizedAddress(txId)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(multiSig.executeRemoveAuthorizedAddress(txId)).to.be.rejectedWith(constants.REVERT); }); it('should execute removeAuthorizedAddress for valid tokenTransferProxy if fully confirmed', async () => { @@ -107,7 +120,7 @@ contract('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', (accounts: s }; const res = await multiSigWrapper.submitTransactionAsync(validDestination, owners[0], dataParams); const txId = res.logs[0].args.transactionId.toString(); - await multiSig.confirmTransaction(txId, {from: owners[1]}); + await multiSig.confirmTransaction(txId, { from: owners[1] }); const isConfirmed = await multiSig.isConfirmed.call(txId); expect(isConfirmed).to.be.true(); await multiSig.executeRemoveAuthorizedAddress(txId); @@ -124,14 +137,14 @@ contract('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', (accounts: s }; const res = await multiSigWrapper.submitTransactionAsync(validDestination, owners[0], dataParams); const txId = res.logs[0].args.transactionId.toString(); - await multiSig.confirmTransaction(txId, {from: owners[1]}); + await multiSig.confirmTransaction(txId, { from: owners[1] }); const isConfirmed = await multiSig.isConfirmed.call(txId); expect(isConfirmed).to.be.true(); await multiSig.executeRemoveAuthorizedAddress(txId); const tx = await multiSig.transactions.call(txId); const isExecuted = tx[3]; expect(isExecuted).to.be.true(); - return expect(multiSig.executeRemoveAuthorizedAddress(txId)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(multiSig.executeRemoveAuthorizedAddress(txId)).to.be.rejectedWith(constants.REVERT); }); }); }); diff --git a/packages/contracts/test/ts/token_registry.ts b/packages/contracts/test/ts/token_registry.ts index ed0bbf55b..d1c551565 100644 --- a/packages/contracts/test/ts/token_registry.ts +++ b/packages/contracts/test/ts/token_registry.ts @@ -1,16 +1,16 @@ -import {ZeroEx} from '0x.js'; +import { ZeroEx } from '0x.js'; import * as chai from 'chai'; import ethUtil = require('ethereumjs-util'); import * as _ from 'lodash'; -import {Artifacts} from '../../util/artifacts'; -import {constants} from '../../util/constants'; -import {TokenRegWrapper} from '../../util/token_registry_wrapper'; -import {ContractInstance} from '../../util/types'; +import { Artifacts } from '../../util/artifacts'; +import { constants } from '../../util/constants'; +import { TokenRegWrapper } from '../../util/token_registry_wrapper'; +import { ContractInstance } from '../../util/types'; -import {chaiSetup} from './utils/chai_setup'; +import { chaiSetup } from './utils/chai_setup'; -const {TokenRegistry} = new Artifacts(artifacts); +const { TokenRegistry } = new Artifacts(artifacts); chaiSetup.configure(); const expect = chai.expect; @@ -58,7 +58,7 @@ contract('TokenRegistry', (accounts: string[]) => { describe('addToken', () => { it('should throw when not called by owner', async () => { - return expect(tokenRegWrapper.addTokenAsync(token1, notOwner)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(tokenRegWrapper.addTokenAsync(token1, notOwner)).to.be.rejectedWith(constants.REVERT); }); it('should add token metadata when called by owner', async () => { @@ -70,27 +70,31 @@ contract('TokenRegistry', (accounts: string[]) => { it('should throw if token already exists', async () => { await tokenRegWrapper.addTokenAsync(token1, owner); - return expect(tokenRegWrapper.addTokenAsync(token1, owner)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(tokenRegWrapper.addTokenAsync(token1, owner)).to.be.rejectedWith(constants.REVERT); }); it('should throw if token address is null', async () => { - return expect(tokenRegWrapper.addTokenAsync(nullToken, owner)).to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(tokenRegWrapper.addTokenAsync(nullToken, owner)).to.be.rejectedWith(constants.REVERT); }); it('should throw if name already exists', async () => { await tokenRegWrapper.addTokenAsync(token1, owner); - const duplicateNameToken = _.assign({}, token2, {name: token1.name}); + const duplicateNameToken = _.assign({}, token2, { name: token1.name }); - return expect(tokenRegWrapper.addTokenAsync(duplicateNameToken, owner)) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(tokenRegWrapper.addTokenAsync(duplicateNameToken, owner)).to.be.rejectedWith( + constants.REVERT, + ); }); it('should throw if symbol already exists', async () => { await tokenRegWrapper.addTokenAsync(token1, owner); - const duplicateSymbolToken = _.assign({}, token2, {symbol: token1.symbol}); + const duplicateSymbolToken = _.assign({}, token2, { + symbol: token1.symbol, + }); - return expect(tokenRegWrapper.addTokenAsync(duplicateSymbolToken, owner)) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(tokenRegWrapper.addTokenAsync(duplicateSymbolToken, owner)).to.be.rejectedWith( + constants.REVERT, + ); }); }); @@ -115,19 +119,22 @@ contract('TokenRegistry', (accounts: string[]) => { describe('setTokenName', () => { it('should throw when not called by owner', async () => { - return expect(tokenReg.setTokenName(token1.address, token2.name, {from: notOwner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect( + tokenReg.setTokenName(token1.address, token2.name, { from: notOwner }), + ).to.be.rejectedWith(constants.REVERT); }); it('should change the token name when called by owner', async () => { - const res = await tokenReg.setTokenName(token1.address, token2.name, {from: owner}); + const res = await tokenReg.setTokenName(token1.address, token2.name, { + from: owner, + }); expect(res.logs).to.have.length(1); const [newData, oldData] = await Promise.all([ tokenRegWrapper.getTokenByNameAsync(token2.name), tokenRegWrapper.getTokenByNameAsync(token1.name), ]); - const expectedNewData = _.assign({}, token1, {name: token2.name}); + const expectedNewData = _.assign({}, token1, { name: token2.name }); const expectedOldData = nullToken; expect(newData).to.be.deep.equal(expectedNewData); expect(oldData).to.be.deep.equal(expectedOldData); @@ -136,31 +143,36 @@ contract('TokenRegistry', (accounts: string[]) => { it('should throw if the name already exists', async () => { await tokenRegWrapper.addTokenAsync(token2, owner); - return expect(tokenReg.setTokenName(token1.address, token2.name, {from: owner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(tokenReg.setTokenName(token1.address, token2.name, { from: owner })).to.be.rejectedWith( + constants.REVERT, + ); }); it('should throw if token does not exist', async () => { - return expect(tokenReg.setTokenName(nullToken.address, token2.name, {from: owner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect( + tokenReg.setTokenName(nullToken.address, token2.name, { from: owner }), + ).to.be.rejectedWith(constants.REVERT); }); }); describe('setTokenSymbol', () => { it('should throw when not called by owner', async () => { - return expect(tokenReg.setTokenSymbol(token1.address, token2.symbol, {from: notOwner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect( + tokenReg.setTokenSymbol(token1.address, token2.symbol, { + from: notOwner, + }), + ).to.be.rejectedWith(constants.REVERT); }); it('should change the token symbol when called by owner', async () => { - const res = await tokenReg.setTokenSymbol(token1.address, token2.symbol, {from: owner}); + const res = await tokenReg.setTokenSymbol(token1.address, token2.symbol, { from: owner }); expect(res.logs).to.have.length(1); const [newData, oldData] = await Promise.all([ tokenRegWrapper.getTokenBySymbolAsync(token2.symbol), tokenRegWrapper.getTokenBySymbolAsync(token1.symbol), ]); - const expectedNewData = _.assign({}, token1, {symbol: token2.symbol}); + const expectedNewData = _.assign({}, token1, { symbol: token2.symbol }); const expectedOldData = nullToken; expect(newData).to.be.deep.equal(expectedNewData); expect(oldData).to.be.deep.equal(expectedOldData); @@ -169,26 +181,35 @@ contract('TokenRegistry', (accounts: string[]) => { it('should throw if the symbol already exists', async () => { await tokenRegWrapper.addTokenAsync(token2, owner); - return expect(tokenReg.setTokenSymbol(token1.address, token2.symbol, {from: owner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect( + tokenReg.setTokenSymbol(token1.address, token2.symbol, { + from: owner, + }), + ).to.be.rejectedWith(constants.REVERT); }); it('should throw if token does not exist', async () => { - return expect(tokenReg.setTokenSymbol(nullToken.address, token2.symbol, {from: owner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect( + tokenReg.setTokenSymbol(nullToken.address, token2.symbol, { + from: owner, + }), + ).to.be.rejectedWith(constants.REVERT); }); }); describe('removeToken', () => { it('should throw if not called by owner', async () => { const index = 0; - return expect(tokenReg.removeToken(token1.address, index, {from: notOwner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(tokenReg.removeToken(token1.address, index, { from: notOwner })).to.be.rejectedWith( + constants.REVERT, + ); }); it('should remove token metadata when called by owner', async () => { const index = 0; - const res = await tokenReg.removeToken(token1.address, index, {from: owner}); + const res = await tokenReg.removeToken(token1.address, index, { + from: owner, + }); expect(res.logs).to.have.length(1); const tokenData = await tokenRegWrapper.getTokenMetaDataAsync(token1.address); expect(tokenData).to.be.deep.equal(nullToken); @@ -196,17 +217,18 @@ contract('TokenRegistry', (accounts: string[]) => { it('should throw if token does not exist', async () => { const index = 0; - return expect(tokenReg.removeToken(nullToken.address, index, {from: owner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(tokenReg.removeToken(nullToken.address, index, { from: owner })).to.be.rejectedWith( + constants.REVERT, + ); }); it('should throw if token at given index does not match address', async () => { await tokenRegWrapper.addTokenAsync(token2, owner); const incorrectIndex = 0; - return expect(tokenReg.removeToken(token2.address, incorrectIndex, {from: owner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(tokenReg.removeToken(token2.address, incorrectIndex, { from: owner })).to.be.rejectedWith( + constants.REVERT, + ); }); - }); }); }); diff --git a/packages/contracts/test/ts/token_transfer_proxy/auth.ts b/packages/contracts/test/ts/token_transfer_proxy/auth.ts index 785fbc016..9ae0a8fc3 100644 --- a/packages/contracts/test/ts/token_transfer_proxy/auth.ts +++ b/packages/contracts/test/ts/token_transfer_proxy/auth.ts @@ -1,8 +1,8 @@ import * as chai from 'chai'; -import {constants} from '../../../util/constants'; -import {ContractInstance} from '../../../util/types'; -import {chaiSetup} from '../utils/chai_setup'; +import { constants } from '../../../util/constants'; +import { ContractInstance } from '../../../util/types'; +import { chaiSetup } from '../utils/chai_setup'; chaiSetup.configure(); const expect = chai.expect; @@ -22,12 +22,15 @@ contract('TokenTransferProxy', (accounts: string[]) => { describe('addAuthorizedAddress', () => { it('should throw if not called by owner', async () => { - return expect(tokenTransferProxy.addAuthorizedAddress(notOwner, {from: notOwner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(tokenTransferProxy.addAuthorizedAddress(notOwner, { from: notOwner })).to.be.rejectedWith( + constants.REVERT, + ); }); it('should allow owner to add an authorized address', async () => { - await tokenTransferProxy.addAuthorizedAddress(notAuthorized, {from: owner}); + await tokenTransferProxy.addAuthorizedAddress(notAuthorized, { + from: owner, + }); authorized = notAuthorized; notAuthorized = null; const isAuthorized = await tokenTransferProxy.authorized.call(authorized); @@ -35,19 +38,25 @@ contract('TokenTransferProxy', (accounts: string[]) => { }); it('should throw if owner attempts to authorize a duplicate address', async () => { - return expect(tokenTransferProxy.addAuthorizedAddress(authorized, {from: owner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect(tokenTransferProxy.addAuthorizedAddress(authorized, { from: owner })).to.be.rejectedWith( + constants.REVERT, + ); }); }); describe('removeAuthorizedAddress', () => { it('should throw if not called by owner', async () => { - return expect(tokenTransferProxy.removeAuthorizedAddress(authorized, {from: notOwner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect( + tokenTransferProxy.removeAuthorizedAddress(authorized, { + from: notOwner, + }), + ).to.be.rejectedWith(constants.REVERT); }); it('should allow owner to remove an authorized address', async () => { - await tokenTransferProxy.removeAuthorizedAddress(authorized, {from: owner}); + await tokenTransferProxy.removeAuthorizedAddress(authorized, { + from: owner, + }); notAuthorized = authorized; authorized = null; @@ -56,8 +65,11 @@ contract('TokenTransferProxy', (accounts: string[]) => { }); it('should throw if owner attempts to remove an address that is not authorized', async () => { - return expect(tokenTransferProxy.removeAuthorizedAddress(notAuthorized, {from: owner})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + return expect( + tokenTransferProxy.removeAuthorizedAddress(notAuthorized, { + from: owner, + }), + ).to.be.rejectedWith(constants.REVERT); }); }); @@ -65,7 +77,9 @@ contract('TokenTransferProxy', (accounts: string[]) => { it('should return all authorized addresses', async () => { const initial = await tokenTransferProxy.getAuthorizedAddresses(); expect(initial).to.have.length(1); - await tokenTransferProxy.addAuthorizedAddress(notAuthorized, {from: owner}); + await tokenTransferProxy.addAuthorizedAddress(notAuthorized, { + from: owner, + }); authorized = notAuthorized; notAuthorized = null; @@ -73,7 +87,9 @@ contract('TokenTransferProxy', (accounts: string[]) => { expect(afterAdd).to.have.length(2); expect(afterAdd).to.include(authorized); - await tokenTransferProxy.removeAuthorizedAddress(authorized, {from: owner}); + await tokenTransferProxy.removeAuthorizedAddress(authorized, { + from: owner, + }); notAuthorized = authorized; authorized = null; const afterRemove = await tokenTransferProxy.getAuthorizedAddresses(); diff --git a/packages/contracts/test/ts/token_transfer_proxy/transfer_from.ts b/packages/contracts/test/ts/token_transfer_proxy/transfer_from.ts index 6e0bfdc1a..e1aff6dae 100644 --- a/packages/contracts/test/ts/token_transfer_proxy/transfer_from.ts +++ b/packages/contracts/test/ts/token_transfer_proxy/transfer_from.ts @@ -1,18 +1,14 @@ import * as chai from 'chai'; -import {Artifacts} from '../../../util/artifacts'; -import {Balances} from '../../../util/balances'; -import {constants} from '../../../util/constants'; -import {ContractInstance} from '../../../util/types'; -import {chaiSetup} from '../utils/chai_setup'; +import { Artifacts } from '../../../util/artifacts'; +import { Balances } from '../../../util/balances'; +import { constants } from '../../../util/constants'; +import { ContractInstance } from '../../../util/types'; +import { chaiSetup } from '../utils/chai_setup'; chaiSetup.configure(); const expect = chai.expect; -const { - TokenTransferProxy, - DummyToken, - TokenRegistry, -} = new Artifacts(artifacts); +const { TokenTransferProxy, DummyToken, TokenRegistry } = new Artifacts(artifacts); contract('TokenTransferProxy', (accounts: string[]) => { const INIT_BAL = 100000000; @@ -36,32 +32,42 @@ contract('TokenTransferProxy', (accounts: string[]) => { dmyBalances = new Balances([rep], [accounts[0], accounts[1]]); await Promise.all([ - rep.approve(TokenTransferProxy.address, INIT_ALLOW, {from: accounts[0]}), - rep.setBalance(accounts[0], INIT_BAL, {from: owner}), - rep.approve(TokenTransferProxy.address, INIT_ALLOW, {from: accounts[1]}), - rep.setBalance(accounts[1], INIT_BAL, {from: owner}), + rep.approve(TokenTransferProxy.address, INIT_ALLOW, { + from: accounts[0], + }), + rep.setBalance(accounts[0], INIT_BAL, { from: owner }), + rep.approve(TokenTransferProxy.address, INIT_ALLOW, { + from: accounts[1], + }), + rep.setBalance(accounts[1], INIT_BAL, { from: owner }), ]); }); describe('transferFrom', () => { it('should throw when called by an unauthorized address', async () => { - expect(tokenTransferProxy.transferFrom(rep.address, accounts[0], accounts[1], 1000, {from: notAuthorized})) - .to.be.rejectedWith(constants.INVALID_OPCODE); + expect( + tokenTransferProxy.transferFrom(rep.address, accounts[0], accounts[1], 1000, { from: notAuthorized }), + ).to.be.rejectedWith(constants.REVERT); }); it('should allow an authorized address to transfer', async () => { const balances = await dmyBalances.getAsync(); - await tokenTransferProxy.addAuthorizedAddress(notAuthorized, {from: owner}); + await tokenTransferProxy.addAuthorizedAddress(notAuthorized, { + from: owner, + }); const transferAmt = 10000; - await tokenTransferProxy.transferFrom(rep.address, accounts[0], accounts[1], - transferAmt, {from: notAuthorized}); + await tokenTransferProxy.transferFrom(rep.address, accounts[0], accounts[1], transferAmt, { + from: notAuthorized, + }); const newBalances = await dmyBalances.getAsync(); - expect(newBalances[accounts[0]][rep.address]) - .to.be.bignumber.equal(balances[accounts[0]][rep.address].minus(transferAmt)); - expect(newBalances[accounts[1]][rep.address]) - .to.be.bignumber.equal(balances[accounts[1]][rep.address].add(transferAmt)); + expect(newBalances[accounts[0]][rep.address]).to.be.bignumber.equal( + balances[accounts[0]][rep.address].minus(transferAmt), + ); + expect(newBalances[accounts[1]][rep.address]).to.be.bignumber.equal( + balances[accounts[1]][rep.address].add(transferAmt), + ); }); }); }); diff --git a/packages/contracts/test/ts/unlimitedAllowanceToken.ts b/packages/contracts/test/ts/unlimited_allowance_token.ts index ca3fcd7d2..c90a52095 100644 --- a/packages/contracts/test/ts/unlimitedAllowanceToken.ts +++ b/packages/contracts/test/ts/unlimited_allowance_token.ts @@ -1,20 +1,24 @@ -import {ZeroEx} from '0x.js'; -import {BigNumber} from 'bignumber.js'; +import { ZeroEx } from '0x.js'; +import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import * as Web3 from 'web3'; -import {Artifacts} from '../../util/artifacts'; -import {ContractInstance} from '../../util/types'; +import { Artifacts } from '../../util/artifacts'; +import { constants } from '../../util/constants'; +import { ContractInstance } from '../../util/types'; -import {chaiSetup} from './utils/chai_setup'; +import { chaiSetup } from './utils/chai_setup'; -const {DummyToken} = new Artifacts(artifacts); +const { DummyToken } = new Artifacts(artifacts); const web3: Web3 = (global as any).web3; chaiSetup.configure(); const expect = chai.expect; contract('UnlimitedAllowanceToken', (accounts: string[]) => { - const zeroEx = new ZeroEx(web3.currentProvider); + const config = { + networkId: constants.TESTRPC_NETWORK_ID, + }; + const zeroEx = new ZeroEx(web3.currentProvider, config); const owner = accounts[0]; const spender = accounts[1]; @@ -23,8 +27,8 @@ contract('UnlimitedAllowanceToken', (accounts: string[]) => { let token: ContractInstance; beforeEach(async () => { - token = await DummyToken.new({from: owner}); - await token.mint(MAX_MINT_VALUE, {from: owner}); + token = await DummyToken.new({ from: owner }); + await token.mint(MAX_MINT_VALUE, { from: owner }); tokenAddress = token.address; }); @@ -44,7 +48,9 @@ contract('UnlimitedAllowanceToken', (accounts: string[]) => { }); it('should return true on a 0 value transfer', async () => { - const didReturnTrue = await token.transfer.call(spender, 0, {from: owner}); + const didReturnTrue = await token.transfer.call(spender, 0, { + from: owner, + }); expect(didReturnTrue).to.be.true(); }); }); @@ -54,7 +60,7 @@ contract('UnlimitedAllowanceToken', (accounts: string[]) => { const ownerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner); const amountToTransfer = ownerBalance.plus(1); await zeroEx.token.setAllowanceAsync(tokenAddress, owner, spender, amountToTransfer); - const didReturnTrue = await token.transferFrom.call(owner, spender, amountToTransfer, {from: spender}); + const didReturnTrue = await token.transferFrom.call(owner, spender, amountToTransfer, { from: spender }); expect(didReturnTrue).to.be.false(); }); @@ -66,13 +72,13 @@ contract('UnlimitedAllowanceToken', (accounts: string[]) => { const spenderAllowanceIsInsufficient = spenderAllowance.cmp(amountToTransfer) < 0; expect(spenderAllowanceIsInsufficient).to.be.true(); - const didReturnTrue = await token.transferFrom.call(owner, spender, amountToTransfer, {from: spender}); + const didReturnTrue = await token.transferFrom.call(owner, spender, amountToTransfer, { from: spender }); expect(didReturnTrue).to.be.false(); }); it('should return true on a 0 value transfer', async () => { const amountToTransfer = 0; - const didReturnTrue = await token.transferFrom.call(owner, spender, amountToTransfer, {from: spender}); + const didReturnTrue = await token.transferFrom.call(owner, spender, amountToTransfer, { from: spender }); expect(didReturnTrue).to.be.true(); }); @@ -81,7 +87,9 @@ contract('UnlimitedAllowanceToken', (accounts: string[]) => { const amountToTransfer = initOwnerBalance; const initSpenderAllowance = zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; await zeroEx.token.setAllowanceAsync(tokenAddress, owner, spender, initSpenderAllowance); - await zeroEx.token.transferFromAsync(tokenAddress, owner, spender, spender, amountToTransfer); + await zeroEx.token.transferFromAsync(tokenAddress, owner, spender, spender, amountToTransfer, { + gasLimit: constants.MAX_TOKEN_TRANSFERFROM_GAS, + }); const newSpenderAllowance = await zeroEx.token.getAllowanceAsync(tokenAddress, owner, spender); expect(initSpenderAllowance).to.be.bignumber.equal(newSpenderAllowance); @@ -92,7 +100,9 @@ contract('UnlimitedAllowanceToken', (accounts: string[]) => { const amountToTransfer = initOwnerBalance; const initSpenderAllowance = initOwnerBalance; await zeroEx.token.setAllowanceAsync(tokenAddress, owner, spender, initSpenderAllowance); - await zeroEx.token.transferFromAsync(tokenAddress, owner, spender, spender, amountToTransfer); + await zeroEx.token.transferFromAsync(tokenAddress, owner, spender, spender, amountToTransfer, { + gasLimit: constants.MAX_TOKEN_TRANSFERFROM_GAS, + }); const newOwnerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner); const newSpenderBalance = await zeroEx.token.getBalanceAsync(tokenAddress, spender); @@ -106,7 +116,9 @@ contract('UnlimitedAllowanceToken', (accounts: string[]) => { const amountToTransfer = initOwnerBalance; const initSpenderAllowance = initOwnerBalance; await zeroEx.token.setAllowanceAsync(tokenAddress, owner, spender, initSpenderAllowance); - await zeroEx.token.transferFromAsync(tokenAddress, owner, spender, spender, amountToTransfer); + await zeroEx.token.transferFromAsync(tokenAddress, owner, spender, spender, amountToTransfer, { + gasLimit: constants.MAX_TOKEN_TRANSFERFROM_GAS, + }); const newSpenderAllowance = await zeroEx.token.getAllowanceAsync(tokenAddress, owner, spender); expect(newSpenderAllowance).to.be.bignumber.equal(0); diff --git a/packages/contracts/test/ts/unlimited_allowance_token_v2.ts b/packages/contracts/test/ts/unlimited_allowance_token_v2.ts new file mode 100644 index 000000000..1b29a02ba --- /dev/null +++ b/packages/contracts/test/ts/unlimited_allowance_token_v2.ts @@ -0,0 +1,141 @@ +import { ZeroEx } from '0x.js'; +import { BigNumber } from '@0xproject/utils'; +import * as chai from 'chai'; +import * as Web3 from 'web3'; + +import { Artifacts } from '../../util/artifacts'; +import { constants } from '../../util/constants'; +import { ContractInstance } from '../../util/types'; + +import { chaiSetup } from './utils/chai_setup'; + +const { DummyTokenV2 } = new Artifacts(artifacts); +const web3: Web3 = (global as any).web3; +chaiSetup.configure(); +const expect = chai.expect; + +contract('UnlimitedAllowanceTokenV2', (accounts: string[]) => { + const config = { + networkId: constants.TESTRPC_NETWORK_ID, + }; + const zeroEx = new ZeroEx(web3.currentProvider, config); + const owner = accounts[0]; + const spender = accounts[1]; + + const MAX_MINT_VALUE = new BigNumber(100000000000000000000); + let tokenAddress: string; + let token: ContractInstance; + + beforeEach(async () => { + token = await DummyTokenV2.new({ from: owner }); + await token.mint(MAX_MINT_VALUE, { from: owner }); + tokenAddress = token.address; + }); + + describe('transfer', () => { + it('should throw if owner has insufficient balance', async () => { + const ownerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner); + const amountToTransfer = ownerBalance.plus(1); + return expect(token.transfer.call(spender, amountToTransfer, { from: owner })).to.be.rejectedWith( + constants.REVERT, + ); + }); + + it('should transfer balance from sender to receiver', async () => { + const receiver = spender; + const initOwnerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner); + const amountToTransfer = new BigNumber(1); + await zeroEx.token.transferAsync(tokenAddress, owner, receiver, amountToTransfer); + const finalOwnerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner); + const finalReceiverBalance = await zeroEx.token.getBalanceAsync(tokenAddress, receiver); + + const expectedFinalOwnerBalance = initOwnerBalance.minus(amountToTransfer); + const expectedFinalReceiverBalance = amountToTransfer; + expect(finalOwnerBalance).to.be.bignumber.equal(expectedFinalOwnerBalance); + expect(finalReceiverBalance).to.be.bignumber.equal(expectedFinalReceiverBalance); + }); + + it('should return true on a 0 value transfer', async () => { + const didReturnTrue = await token.transfer.call(spender, 0, { + from: owner, + }); + expect(didReturnTrue).to.be.true(); + }); + }); + + describe('transferFrom', () => { + it('should throw if owner has insufficient balance', async () => { + const ownerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner); + const amountToTransfer = ownerBalance.plus(1); + await zeroEx.token.setAllowanceAsync(tokenAddress, owner, spender, amountToTransfer); + return expect( + token.transferFrom.call(owner, spender, amountToTransfer, { + from: spender, + }), + ).to.be.rejectedWith(constants.REVERT); + }); + + it('should throw if spender has insufficient allowance', async () => { + const ownerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner); + const amountToTransfer = ownerBalance; + + const spenderAllowance = await zeroEx.token.getAllowanceAsync(tokenAddress, owner, spender); + const spenderAllowanceIsInsufficient = spenderAllowance.cmp(amountToTransfer) < 0; + expect(spenderAllowanceIsInsufficient).to.be.true(); + + return expect( + token.transferFrom.call(owner, spender, amountToTransfer, { + from: spender, + }), + ).to.be.rejectedWith(constants.REVERT); + }); + + it('should return true on a 0 value transfer', async () => { + const amountToTransfer = 0; + const didReturnTrue = await token.transferFrom.call(owner, spender, amountToTransfer, { from: spender }); + expect(didReturnTrue).to.be.true(); + }); + + it('should not modify spender allowance if spender allowance is 2^256 - 1', async () => { + const initOwnerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner); + const amountToTransfer = initOwnerBalance; + const initSpenderAllowance = zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; + await zeroEx.token.setAllowanceAsync(tokenAddress, owner, spender, initSpenderAllowance); + await zeroEx.token.transferFromAsync(tokenAddress, owner, spender, spender, amountToTransfer, { + gasLimit: constants.MAX_TOKEN_TRANSFERFROM_GAS, + }); + + const newSpenderAllowance = await zeroEx.token.getAllowanceAsync(tokenAddress, owner, spender); + expect(initSpenderAllowance).to.be.bignumber.equal(newSpenderAllowance); + }); + + it('should transfer the correct balances if spender has sufficient allowance', async () => { + const initOwnerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner); + const amountToTransfer = initOwnerBalance; + const initSpenderAllowance = initOwnerBalance; + await zeroEx.token.setAllowanceAsync(tokenAddress, owner, spender, initSpenderAllowance); + await zeroEx.token.transferFromAsync(tokenAddress, owner, spender, spender, amountToTransfer, { + gasLimit: constants.MAX_TOKEN_TRANSFERFROM_GAS, + }); + + const newOwnerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner); + const newSpenderBalance = await zeroEx.token.getBalanceAsync(tokenAddress, spender); + + expect(newOwnerBalance).to.be.bignumber.equal(0); + expect(newSpenderBalance).to.be.bignumber.equal(initOwnerBalance); + }); + + it('should modify allowance if spender has sufficient allowance less than 2^256 - 1', async () => { + const initOwnerBalance = await zeroEx.token.getBalanceAsync(tokenAddress, owner); + const amountToTransfer = initOwnerBalance; + const initSpenderAllowance = initOwnerBalance; + await zeroEx.token.setAllowanceAsync(tokenAddress, owner, spender, initSpenderAllowance); + await zeroEx.token.transferFromAsync(tokenAddress, owner, spender, spender, amountToTransfer, { + gasLimit: constants.MAX_TOKEN_TRANSFERFROM_GAS, + }); + + const newSpenderAllowance = await zeroEx.token.getAllowanceAsync(tokenAddress, owner, spender); + expect(newSpenderAllowance).to.be.bignumber.equal(0); + }); + }); +}); diff --git a/packages/contracts/test/ts/zrxToken.ts b/packages/contracts/test/ts/zrx_token.ts index 471ee93f2..766c94c2a 100644 --- a/packages/contracts/test/ts/zrxToken.ts +++ b/packages/contracts/test/ts/zrx_token.ts @@ -1,16 +1,17 @@ -import {ZeroEx} from '0x.js'; -import {BigNumber} from 'bignumber.js'; +import { ZeroEx } from '0x.js'; +import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import Web3 = require('web3'); -import {Artifacts} from '../../util/artifacts'; -import {ContractInstance} from '../../util/types'; +import { Artifacts } from '../../util/artifacts'; +import { constants } from '../../util/constants'; +import { ContractInstance } from '../../util/types'; -import {chaiSetup} from './utils/chai_setup'; +import { chaiSetup } from './utils/chai_setup'; chaiSetup.configure(); const expect = chai.expect; -const {Exchange, ZRXToken} = new Artifacts(artifacts); +const { Exchange, ZRXToken } = new Artifacts(artifacts); const web3: Web3 = (global as any).web3; contract('ZRXToken', (accounts: string[]) => { @@ -25,10 +26,11 @@ contract('ZRXToken', (accounts: string[]) => { beforeEach(async () => { zeroEx = new ZeroEx(web3.currentProvider, { - exchangeContractAddress: Exchange.address, + exchangeContractAddress: Exchange.address, + networkId: constants.TESTRPC_NETWORK_ID, }); - zrxAddress = await zeroEx.exchange.getZRXTokenAddressAsync(); - zrx = await ZRXToken.at(zrxAddress); + zrx = await ZRXToken.new(); + zrxAddress = zrx.address; MAX_UINT = zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; }); @@ -83,7 +85,9 @@ contract('ZRXToken', (accounts: string[]) => { }); it('should return true on a 0 value transfer', async () => { - const didReturnTrue = await zrx.transfer.call(spender, 0, {from: owner}); + const didReturnTrue = await zrx.transfer.call(spender, 0, { + from: owner, + }); expect(didReturnTrue).to.be.true(); }); }); @@ -92,13 +96,12 @@ contract('ZRXToken', (accounts: string[]) => { it('should return false if owner has insufficient balance', async () => { const ownerBalance = await zeroEx.token.getBalanceAsync(zrxAddress, owner); const amountToTransfer = ownerBalance.plus(1); - let txHash = await zeroEx.token.setAllowanceAsync(zrxAddress, owner, spender, amountToTransfer); + const txHash = await zeroEx.token.setAllowanceAsync(zrxAddress, owner, spender, amountToTransfer, { + gasLimit: constants.MAX_TOKEN_APPROVE_GAS, + }); await zeroEx.awaitTransactionMinedAsync(txHash); - const didReturnTrue = await zrx.transferFrom.call(owner, spender, amountToTransfer, {from: spender}); + const didReturnTrue = await zrx.transferFrom.call(owner, spender, amountToTransfer, { from: spender }); expect(didReturnTrue).to.be.false(); - // Reset allowance - txHash = await zeroEx.token.setAllowanceAsync(zrxAddress, owner, spender, new BigNumber(0)); - await zeroEx.awaitTransactionMinedAsync(txHash); }); it('should return false if spender has insufficient allowance', async () => { @@ -109,13 +112,13 @@ contract('ZRXToken', (accounts: string[]) => { const spenderAllowanceIsInsufficient = spenderAllowance.cmp(amountToTransfer) < 0; expect(spenderAllowanceIsInsufficient).to.be.true(); - const didReturnTrue = await zrx.transferFrom.call(owner, spender, amountToTransfer, {from: spender}); + const didReturnTrue = await zrx.transferFrom.call(owner, spender, amountToTransfer, { from: spender }); expect(didReturnTrue).to.be.false(); }); it('should return true on a 0 value transfer', async () => { const amountToTransfer = 0; - const didReturnTrue = await zrx.transferFrom.call(owner, spender, amountToTransfer, {from: spender}); + const didReturnTrue = await zrx.transferFrom.call(owner, spender, amountToTransfer, { from: spender }); expect(didReturnTrue).to.be.true(); }); @@ -123,16 +126,17 @@ contract('ZRXToken', (accounts: string[]) => { const initOwnerBalance = await zeroEx.token.getBalanceAsync(zrxAddress, owner); const amountToTransfer = initOwnerBalance; const initSpenderAllowance = MAX_UINT; - let txHash = await zeroEx.token.setAllowanceAsync(zrxAddress, owner, spender, initSpenderAllowance); + let txHash = await zeroEx.token.setAllowanceAsync(zrxAddress, owner, spender, initSpenderAllowance, { + gasLimit: constants.MAX_TOKEN_APPROVE_GAS, + }); await zeroEx.awaitTransactionMinedAsync(txHash); - txHash = await zeroEx.token.transferFromAsync(zrxAddress, owner, spender, spender, amountToTransfer); + txHash = await zeroEx.token.transferFromAsync(zrxAddress, owner, spender, spender, amountToTransfer, { + gasLimit: constants.MAX_TOKEN_TRANSFERFROM_GAS, + }); await zeroEx.awaitTransactionMinedAsync(txHash); const newSpenderAllowance = await zeroEx.token.getAllowanceAsync(zrxAddress, owner, spender); expect(initSpenderAllowance).to.be.bignumber.equal(newSpenderAllowance); - // Restore balance - txHash = await zeroEx.token.transferAsync(zrxAddress, spender, owner, amountToTransfer); - await zeroEx.awaitTransactionMinedAsync(txHash); }); it('should transfer the correct balances if spender has sufficient allowance', async () => { @@ -142,7 +146,9 @@ contract('ZRXToken', (accounts: string[]) => { const initSpenderAllowance = initOwnerBalance; let txHash = await zeroEx.token.setAllowanceAsync(zrxAddress, owner, spender, initSpenderAllowance); await zeroEx.awaitTransactionMinedAsync(txHash); - txHash = await zeroEx.token.transferFromAsync(zrxAddress, owner, spender, spender, amountToTransfer); + txHash = await zeroEx.token.transferFromAsync(zrxAddress, owner, spender, spender, amountToTransfer, { + gasLimit: constants.MAX_TOKEN_TRANSFERFROM_GAS, + }); await zeroEx.awaitTransactionMinedAsync(txHash); const newOwnerBalance = await zeroEx.token.getBalanceAsync(zrxAddress, owner); @@ -155,10 +161,11 @@ contract('ZRXToken', (accounts: string[]) => { it('should modify allowance if spender has sufficient allowance less than 2^256 - 1', async () => { const initOwnerBalance = await zeroEx.token.getBalanceAsync(zrxAddress, owner); const amountToTransfer = initOwnerBalance; - const initSpenderAllowance = initOwnerBalance; - let txHash = await zeroEx.token.setAllowanceAsync(zrxAddress, owner, spender, initSpenderAllowance); + let txHash = await zeroEx.token.setAllowanceAsync(zrxAddress, owner, spender, amountToTransfer); await zeroEx.awaitTransactionMinedAsync(txHash); - txHash = await zeroEx.token.transferFromAsync(zrxAddress, owner, spender, spender, amountToTransfer); + txHash = await zeroEx.token.transferFromAsync(zrxAddress, owner, spender, spender, amountToTransfer, { + gasLimit: constants.MAX_TOKEN_TRANSFERFROM_GAS, + }); await zeroEx.awaitTransactionMinedAsync(txHash); const newSpenderAllowance = await zeroEx.token.getAllowanceAsync(zrxAddress, owner, spender); diff --git a/packages/contracts/tsconfig.json b/packages/contracts/tsconfig.json index c51d5acc4..38008a542 100644 --- a/packages/contracts/tsconfig.json +++ b/packages/contracts/tsconfig.json @@ -1,17 +1,17 @@ { + "extends": "../../tsconfig", "compilerOptions": { - "outDir": "./lib/", - "sourceMap": true, - "noImplicitAny": true, - "module": "commonjs", - "target": "es6", + "outDir": "lib", "baseUrl": ".", + "declaration": false, + "strictNullChecks": false, + "strictFunctionTypes": false, "allowJs": true }, "include": [ "../../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/web3-typescript-typings/index.d.ts", "../../node_modules/chai-as-promised-typescript-typings/index.d.ts", "../../node_modules/types-ethereumjs-util/index.d.ts", "../../node_modules/types-bn/index.d.ts", @@ -21,7 +21,5 @@ "./migrations/**/*", "./deploy/**/*" ], - "exclude": [ - "./deploy/solc/solc_bin" - ] + "exclude": ["./deploy/solc/solc_bin"] } diff --git a/packages/contracts/tslint.json b/packages/contracts/tslint.json index a07795151..ffaefe83a 100644 --- a/packages/contracts/tslint.json +++ b/packages/contracts/tslint.json @@ -1,5 +1,3 @@ { - "extends": [ - "@0xproject/tslint-config" - ] + "extends": ["@0xproject/tslint-config"] } diff --git a/packages/contracts/util/artifacts.ts b/packages/contracts/util/artifacts.ts index b15c9216f..ecb18cbce 100644 --- a/packages/contracts/util/artifacts.ts +++ b/packages/contracts/util/artifacts.ts @@ -6,6 +6,7 @@ export class Artifacts { public Exchange: any; public ZRXToken: any; public DummyToken: any; + public DummyTokenV2: any; public EtherToken: any; public MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress: any; public MaliciousToken: any; @@ -17,9 +18,11 @@ export class Artifacts { this.Exchange = artifacts.require('Exchange'); this.ZRXToken = artifacts.require('ZRXToken'); this.DummyToken = artifacts.require('DummyToken'); - this.EtherToken = artifacts.require('EtherToken'); + this.DummyTokenV2 = artifacts.require('DummyToken_v2'); + this.EtherToken = artifacts.require('WETH9'); this.MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress = artifacts.require( - 'MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress'); + 'MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', + ); this.MaliciousToken = artifacts.require('MaliciousToken'); } } diff --git a/packages/contracts/util/balances.ts b/packages/contracts/util/balances.ts index fce15db6d..6a1659ab1 100644 --- a/packages/contracts/util/balances.ts +++ b/packages/contracts/util/balances.ts @@ -1,22 +1,19 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; -import {bigNumberConfigs} from './bignumber_config'; -import {BalancesByOwner, ContractInstance} from './types'; - -bigNumberConfigs.configure(); +import { BalancesByOwner, ContractInstance } from './types'; export class Balances { - private tokenContractInstances: ContractInstance[]; - private ownerAddresses: string[]; + private _tokenContractInstances: ContractInstance[]; + private _ownerAddresses: string[]; constructor(tokenContractInstances: ContractInstance[], ownerAddresses: string[]) { - this.tokenContractInstances = tokenContractInstances; - this.ownerAddresses = ownerAddresses; + this._tokenContractInstances = tokenContractInstances; + this._ownerAddresses = ownerAddresses; } public async getAsync(): Promise<BalancesByOwner> { const balancesByOwner: BalancesByOwner = {}; - for (const tokenContractInstance of this.tokenContractInstances) { - for (const ownerAddress of this.ownerAddresses) { + for (const tokenContractInstance of this._tokenContractInstances) { + for (const ownerAddress of this._ownerAddresses) { let balance = await tokenContractInstance.balanceOf(ownerAddress); balance = new BigNumber(balance); if (_.isUndefined(balancesByOwner[ownerAddress])) { diff --git a/packages/contracts/util/bignumber_config.ts b/packages/contracts/util/bignumber_config.ts deleted file mode 100644 index 38f59d341..000000000 --- a/packages/contracts/util/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/contracts/util/constants.ts b/packages/contracts/util/constants.ts index 5beebc68c..e61b2f802 100644 --- a/packages/contracts/util/constants.ts +++ b/packages/contracts/util/constants.ts @@ -1,4 +1,9 @@ export const constants = { NULL_BYTES: '0x', INVALID_OPCODE: 'invalid opcode', + REVERT: 'revert', + TESTRPC_NETWORK_ID: 50, + MAX_ETHERTOKEN_WITHDRAW_GAS: 43000, + MAX_TOKEN_TRANSFERFROM_GAS: 80000, + MAX_TOKEN_APPROVE_GAS: 60000, }; diff --git a/packages/contracts/util/crypto.ts b/packages/contracts/util/crypto.ts index 5253b8c15..9173df643 100644 --- a/packages/contracts/util/crypto.ts +++ b/packages/contracts/util/crypto.ts @@ -1,4 +1,3 @@ -import {BigNumber} from 'bignumber.js'; import BN = require('bn.js'); import ABI = require('ethereumjs-abi'); import ethUtil = require('ethereumjs-util'); @@ -19,14 +18,14 @@ export const crypto = { const isNumber = _.isFinite(arg); if (isNumber) { argTypes.push('uint8'); - } else if ((arg).isBigNumber) { + } else if (arg.isBigNumber) { argTypes.push('uint256'); args[i] = new BN(arg.toString(10), 10); } else if (ethUtil.isValidAddress(arg)) { argTypes.push('address'); } else if (_.isString(arg)) { argTypes.push('string'); - } else if (_.isBoolean(arg)) { + } else if (_.isBoolean(arg)) { argTypes.push('bool'); } else { throw new Error(`Unable to guess arg type: ${arg}`); diff --git a/packages/contracts/util/exchange_wrapper.ts b/packages/contracts/util/exchange_wrapper.ts index 304dcdacf..ca79f92c4 100644 --- a/packages/contracts/util/exchange_wrapper.ts +++ b/packages/contracts/util/exchange_wrapper.ts @@ -1,23 +1,26 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; -import {formatters} from './formatters'; -import {Order} from './order'; -import {ContractInstance} from './types'; +import { formatters } from './formatters'; +import { Order } from './order'; +import { ContractInstance } from './types'; export class ExchangeWrapper { - private exchange: ContractInstance; + private _exchange: ContractInstance; constructor(exchangeContractInstance: ContractInstance) { - this.exchange = exchangeContractInstance; + this._exchange = exchangeContractInstance; } - public async fillOrderAsync(order: Order, from: string, - opts: { - fillTakerTokenAmount?: BigNumber; - shouldThrowOnInsufficientBalanceOrAllowance?: boolean; - } = {}) { + public async fillOrderAsync( + order: Order, + from: string, + opts: { + fillTakerTokenAmount?: BigNumber; + shouldThrowOnInsufficientBalanceOrAllowance?: boolean; + } = {}, + ) { const shouldThrowOnInsufficientBalanceOrAllowance = !!opts.shouldThrowOnInsufficientBalanceOrAllowance; const params = order.createFill(shouldThrowOnInsufficientBalanceOrAllowance, opts.fillTakerTokenAmount); - const tx = await this.exchange.fillOrder( + const tx = await this._exchange.fillOrder( params.orderAddresses, params.orderValues, params.fillTakerTokenAmount, @@ -25,48 +28,52 @@ export class ExchangeWrapper { params.v, params.r, params.s, - {from}, + { from }, ); _.each(tx.logs, log => wrapLogBigNumbers(log)); return tx; } - public async cancelOrderAsync(order: Order, from: string, - opts: {cancelTakerTokenAmount?: BigNumber} = {}) { + public async cancelOrderAsync(order: Order, from: string, opts: { cancelTakerTokenAmount?: BigNumber } = {}) { const params = order.createCancel(opts.cancelTakerTokenAmount); - const tx = await this.exchange.cancelOrder( + const tx = await this._exchange.cancelOrder( params.orderAddresses, params.orderValues, params.cancelTakerTokenAmount, - {from}, + { from }, ); _.each(tx.logs, log => wrapLogBigNumbers(log)); return tx; } - public async fillOrKillOrderAsync(order: Order, from: string, - opts: {fillTakerTokenAmount?: BigNumber} = {}) { + public async fillOrKillOrderAsync(order: Order, from: string, opts: { fillTakerTokenAmount?: BigNumber } = {}) { const shouldThrowOnInsufficientBalanceOrAllowance = true; const params = order.createFill(shouldThrowOnInsufficientBalanceOrAllowance, opts.fillTakerTokenAmount); - const tx = await this.exchange.fillOrKillOrder( + const tx = await this._exchange.fillOrKillOrder( params.orderAddresses, params.orderValues, params.fillTakerTokenAmount, params.v, params.r, params.s, - {from}, + { from }, ); _.each(tx.logs, log => wrapLogBigNumbers(log)); return tx; } - public async batchFillOrdersAsync(orders: Order[], from: string, - opts: { - fillTakerTokenAmounts?: BigNumber[]; - shouldThrowOnInsufficientBalanceOrAllowance?: boolean; - } = {}) { + public async batchFillOrdersAsync( + orders: Order[], + from: string, + opts: { + fillTakerTokenAmounts?: BigNumber[]; + shouldThrowOnInsufficientBalanceOrAllowance?: boolean; + } = {}, + ) { const shouldThrowOnInsufficientBalanceOrAllowance = !!opts.shouldThrowOnInsufficientBalanceOrAllowance; const params = formatters.createBatchFill( - orders, shouldThrowOnInsufficientBalanceOrAllowance, opts.fillTakerTokenAmounts); - const tx = await this.exchange.batchFillOrders( + orders, + shouldThrowOnInsufficientBalanceOrAllowance, + opts.fillTakerTokenAmounts, + ); + const tx = await this._exchange.batchFillOrders( params.orderAddresses, params.orderValues, params.fillTakerTokenAmounts, @@ -74,36 +81,44 @@ export class ExchangeWrapper { params.v, params.r, params.s, - {from}, + { from }, ); _.each(tx.logs, log => wrapLogBigNumbers(log)); return tx; } - public async batchFillOrKillOrdersAsync(orders: Order[], from: string, - opts: {fillTakerTokenAmounts?: BigNumber[]} = {}) { + public async batchFillOrKillOrdersAsync( + orders: Order[], + from: string, + opts: { fillTakerTokenAmounts?: BigNumber[] } = {}, + ) { const params = formatters.createBatchFill(orders, undefined, opts.fillTakerTokenAmounts); - const tx = await this.exchange.batchFillOrKillOrders( + const tx = await this._exchange.batchFillOrKillOrders( params.orderAddresses, params.orderValues, params.fillTakerTokenAmounts, params.v, params.r, params.s, - {from}, + { from }, ); _.each(tx.logs, log => wrapLogBigNumbers(log)); return tx; } - public async fillOrdersUpToAsync(orders: Order[], from: string, - opts: { - fillTakerTokenAmount?: BigNumber; - shouldThrowOnInsufficientBalanceOrAllowance?: boolean; - } = {}) { + public async fillOrdersUpToAsync( + orders: Order[], + from: string, + opts: { + fillTakerTokenAmount?: BigNumber; + shouldThrowOnInsufficientBalanceOrAllowance?: boolean; + } = {}, + ) { const shouldThrowOnInsufficientBalanceOrAllowance = !!opts.shouldThrowOnInsufficientBalanceOrAllowance; - const params = formatters.createFillUpTo(orders, - shouldThrowOnInsufficientBalanceOrAllowance, - opts.fillTakerTokenAmount); - const tx = await this.exchange.fillOrdersUpTo( + const params = formatters.createFillUpTo( + orders, + shouldThrowOnInsufficientBalanceOrAllowance, + opts.fillTakerTokenAmount, + ); + const tx = await this._exchange.fillOrdersUpTo( params.orderAddresses, params.orderValues, params.fillTakerTokenAmount, @@ -111,19 +126,22 @@ export class ExchangeWrapper { params.v, params.r, params.s, - {from}, + { from }, ); _.each(tx.logs, log => wrapLogBigNumbers(log)); return tx; } - public async batchCancelOrdersAsync(orders: Order[], from: string, - opts: {cancelTakerTokenAmounts?: BigNumber[]} = {}) { + public async batchCancelOrdersAsync( + orders: Order[], + from: string, + opts: { cancelTakerTokenAmounts?: BigNumber[] } = {}, + ) { const params = formatters.createBatchCancel(orders, opts.cancelTakerTokenAmounts); - const tx = await this.exchange.batchCancelOrders( + const tx = await this._exchange.batchCancelOrders( params.orderAddresses, params.orderValues, params.cancelTakerTokenAmounts, - {from}, + { from }, ); _.each(tx.logs, log => wrapLogBigNumbers(log)); return tx; @@ -131,11 +149,11 @@ export class ExchangeWrapper { public async getOrderHashAsync(order: Order): Promise<string> { const shouldThrowOnInsufficientBalanceOrAllowance = false; const params = order.createFill(shouldThrowOnInsufficientBalanceOrAllowance); - const orderHash = await this.exchange.getOrderHash(params.orderAddresses, params.orderValues); + const orderHash = await this._exchange.getOrderHash(params.orderAddresses, params.orderValues); return orderHash; } public async isValidSignatureAsync(order: Order): Promise<boolean> { - const isValidSignature = await this.exchange.isValidSignature( + const isValidSignature = await this._exchange.isValidSignature( order.params.maker, order.params.orderHashHex, order.params.v, @@ -144,14 +162,20 @@ export class ExchangeWrapper { ); return isValidSignature; } - public async isRoundingErrorAsync(numerator: BigNumber, denominator: BigNumber, - target: BigNumber): Promise<boolean> { - const isRoundingError = await this.exchange.isRoundingError(numerator, denominator, target); + public async isRoundingErrorAsync( + numerator: BigNumber, + denominator: BigNumber, + target: BigNumber, + ): Promise<boolean> { + const isRoundingError = await this._exchange.isRoundingError(numerator, denominator, target); return isRoundingError; } - public async getPartialAmountAsync(numerator: BigNumber, denominator: BigNumber, - target: BigNumber): Promise<BigNumber> { - const partialAmount = new BigNumber(await this.exchange.getPartialAmount(numerator, denominator, target)); + public async getPartialAmountAsync( + numerator: BigNumber, + denominator: BigNumber, + target: BigNumber, + ): Promise<BigNumber> { + const partialAmount = new BigNumber(await this._exchange.getPartialAmount(numerator, denominator, target)); return partialAmount; } } diff --git a/packages/contracts/util/formatters.ts b/packages/contracts/util/formatters.ts index 0ad44481a..0d0ef6df4 100644 --- a/packages/contracts/util/formatters.ts +++ b/packages/contracts/util/formatters.ts @@ -1,13 +1,15 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; -import {Order} from './order'; -import {BatchCancelOrders, BatchFillOrders, FillOrdersUpTo} from './types'; +import { Order } from './order'; +import { BatchCancelOrders, BatchFillOrders, FillOrdersUpTo } from './types'; export const formatters = { - createBatchFill(orders: Order[], - shouldThrowOnInsufficientBalanceOrAllowance: boolean, - fillTakerTokenAmounts: BigNumber[] = []) { + createBatchFill( + orders: Order[], + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + fillTakerTokenAmounts: BigNumber[] = [], + ) { const batchFill: BatchFillOrders = { orderAddresses: [], orderValues: [], @@ -18,11 +20,21 @@ export const formatters = { s: [], }; _.forEach(orders, order => { - batchFill.orderAddresses.push([order.params.maker, order.params.taker, order.params.makerToken, - order.params.takerToken, order.params.feeRecipient]); - batchFill.orderValues.push([order.params.makerTokenAmount, order.params.takerTokenAmount, - order.params.makerFee, order.params.takerFee, - order.params.expirationTimestampInSec, order.params.salt]); + batchFill.orderAddresses.push([ + order.params.maker, + order.params.taker, + order.params.makerToken, + order.params.takerToken, + order.params.feeRecipient, + ]); + batchFill.orderValues.push([ + order.params.makerTokenAmount, + order.params.takerTokenAmount, + order.params.makerFee, + order.params.takerFee, + order.params.expirationTimestampInSec, + order.params.salt, + ]); batchFill.v.push(order.params.v); batchFill.r.push(order.params.r); batchFill.s.push(order.params.s); @@ -32,9 +44,11 @@ export const formatters = { }); return batchFill; }, - createFillUpTo(orders: Order[], - shouldThrowOnInsufficientBalanceOrAllowance: boolean, - fillTakerTokenAmount: BigNumber) { + createFillUpTo( + orders: Order[], + shouldThrowOnInsufficientBalanceOrAllowance: boolean, + fillTakerTokenAmount: BigNumber, + ) { const fillUpTo: FillOrdersUpTo = { orderAddresses: [], orderValues: [], @@ -45,11 +59,21 @@ export const formatters = { s: [], }; orders.forEach(order => { - fillUpTo.orderAddresses.push([order.params.maker, order.params.taker, order.params.makerToken, - order.params.takerToken, order.params.feeRecipient]); - fillUpTo.orderValues.push([order.params.makerTokenAmount, order.params.takerTokenAmount, - order.params.makerFee, order.params.takerFee, - order.params.expirationTimestampInSec, order.params.salt]); + fillUpTo.orderAddresses.push([ + order.params.maker, + order.params.taker, + order.params.makerToken, + order.params.takerToken, + order.params.feeRecipient, + ]); + fillUpTo.orderValues.push([ + order.params.makerTokenAmount, + order.params.takerTokenAmount, + order.params.makerFee, + order.params.takerFee, + order.params.expirationTimestampInSec, + order.params.salt, + ]); fillUpTo.v.push(order.params.v); fillUpTo.r.push(order.params.r); fillUpTo.s.push(order.params.s); @@ -63,11 +87,21 @@ export const formatters = { cancelTakerTokenAmounts, }; orders.forEach(order => { - batchCancel.orderAddresses.push([order.params.maker, order.params.taker, order.params.makerToken, - order.params.takerToken, order.params.feeRecipient]); - batchCancel.orderValues.push([order.params.makerTokenAmount, order.params.takerTokenAmount, - order.params.makerFee, order.params.takerFee, - order.params.expirationTimestampInSec, order.params.salt]); + batchCancel.orderAddresses.push([ + order.params.maker, + order.params.taker, + order.params.makerToken, + order.params.takerToken, + order.params.feeRecipient, + ]); + batchCancel.orderValues.push([ + order.params.makerTokenAmount, + order.params.takerTokenAmount, + order.params.makerFee, + order.params.takerFee, + order.params.expirationTimestampInSec, + order.params.salt, + ]); if (cancelTakerTokenAmounts.length < orders.length) { batchCancel.cancelTakerTokenAmounts.push(order.params.takerTokenAmount); } diff --git a/packages/contracts/util/multi_sig_wrapper.ts b/packages/contracts/util/multi_sig_wrapper.ts index 4ad970ac9..0e2e671ec 100644 --- a/packages/contracts/util/multi_sig_wrapper.ts +++ b/packages/contracts/util/multi_sig_wrapper.ts @@ -3,12 +3,12 @@ import ethUtil = require('ethereumjs-util'); import * as _ from 'lodash'; import * as Web3 from 'web3'; -import {ContractInstance, TransactionDataParams} from './types'; +import { ContractInstance, TransactionDataParams } from './types'; export class MultiSigWrapper { - private multiSig: ContractInstance; + private _multiSig: ContractInstance; public static encodeFnArgs(name: string, abi: Web3.AbiDefinition[], args: any[]) { - const abiEntity = _.find(abi, {name}) as Web3.MethodAbi; + const abiEntity = _.find(abi, { name }) as Web3.MethodAbi; if (_.isUndefined(abiEntity)) { throw new Error(`Did not find abi entry for name: ${name}`); } @@ -22,13 +22,18 @@ export class MultiSigWrapper { return funcSig + argsData.join(''); } constructor(multiSigContractInstance: ContractInstance) { - this.multiSig = multiSigContractInstance; + this._multiSig = multiSigContractInstance; } - public async submitTransactionAsync(destination: string, from: string, - dataParams: TransactionDataParams, - value: number = 0) { - const {name, abi, args = []} = dataParams; + public async submitTransactionAsync( + destination: string, + from: string, + dataParams: TransactionDataParams, + value: number = 0, + ) { + const { name, abi, args = [] } = dataParams; const encoded = MultiSigWrapper.encodeFnArgs(name, abi, args); - return this.multiSig.submitTransaction(destination, value, encoded, {from}); + return this._multiSig.submitTransaction(destination, value, encoded, { + from, + }); } } diff --git a/packages/contracts/util/order.ts b/packages/contracts/util/order.ts index ec5362b66..e202d485b 100644 --- a/packages/contracts/util/order.ts +++ b/packages/contracts/util/order.ts @@ -1,11 +1,10 @@ -import {promisify} from '@0xproject/utils'; -import {BigNumber} from 'bignumber.js'; +import { BigNumber, promisify } from '@0xproject/utils'; import ethUtil = require('ethereumjs-util'); import * as _ from 'lodash'; import Web3 = require('web3'); -import {crypto} from './crypto'; -import {OrderParams} from './types'; +import { crypto } from './crypto'; +import { OrderParams } from './types'; // In order to benefit from type-safety, we re-assign the global web3 instance injected by Truffle // with type `any` to a variable of type `Web3`. @@ -17,11 +16,11 @@ export class Order { this.params = params; } public isValidSignature() { - const {v, r, s} = this.params; + const { v, r, s } = this.params; if (_.isUndefined(v) || _.isUndefined(r) || _.isUndefined(s)) { throw new Error('Cannot call isValidSignature on unsigned order'); } - const orderHash = this.getOrderHash(); + const orderHash = this._getOrderHash(); const msgHash = ethUtil.hashPersonalMessage(ethUtil.toBuffer(orderHash)); try { const pubKey = ethUtil.ecrecover(msgHash, v, ethUtil.toBuffer(r), ethUtil.toBuffer(s)); @@ -32,9 +31,9 @@ export class Order { } } public async signAsync() { - const orderHash = this.getOrderHash(); + const orderHash = this._getOrderHash(); const signature = await promisify<string>(web3.eth.sign)(this.params.maker, orderHash); - const {v, r, s} = ethUtil.fromRpcSig(signature); + const { v, r, s } = ethUtil.fromRpcSig(signature); this.params = _.assign(this.params, { orderHashHex: orderHash, v, @@ -88,7 +87,7 @@ export class Order { }; return cancel; } - private getOrderHash(): string { + private _getOrderHash(): string { const orderHash = crypto.solSHA3([ this.params.exchangeContractAddress, this.params.maker, diff --git a/packages/contracts/util/order_factory.ts b/packages/contracts/util/order_factory.ts index 526e229a4..a45877de0 100644 --- a/packages/contracts/util/order_factory.ts +++ b/packages/contracts/util/order_factory.ts @@ -1,22 +1,27 @@ -import {ZeroEx} from '0x.js'; -import {BigNumber} from 'bignumber.js'; +import { ZeroEx } from '0x.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; -import {Order} from './order'; -import {DefaultOrderParams, OptionalOrderParams, OrderParams} from './types'; +import { Order } from './order'; +import { DefaultOrderParams, OptionalOrderParams, OrderParams } from './types'; export class OrderFactory { - private defaultOrderParams: DefaultOrderParams; + private _defaultOrderParams: DefaultOrderParams; constructor(defaultOrderParams: DefaultOrderParams) { - this.defaultOrderParams = defaultOrderParams; + this._defaultOrderParams = defaultOrderParams; } public async newSignedOrderAsync(customOrderParams: OptionalOrderParams = {}) { - const randomExpiration = new BigNumber(Math.floor((Date.now() + (Math.random() * 100000000000)) / 1000)); - const orderParams: OrderParams = _.assign({}, { - expirationTimestampInSec: randomExpiration, - salt: ZeroEx.generatePseudoRandomSalt(), - taker: ZeroEx.NULL_ADDRESS, - }, this.defaultOrderParams, customOrderParams); + const randomExpiration = new BigNumber(Math.floor((Date.now() + Math.random() * 100000000000) / 1000)); + const orderParams: OrderParams = _.assign( + {}, + { + expirationTimestampInSec: randomExpiration, + salt: ZeroEx.generatePseudoRandomSalt(), + taker: ZeroEx.NULL_ADDRESS, + }, + this._defaultOrderParams, + customOrderParams, + ); const order = new Order(orderParams); await order.signAsync(); return order; diff --git a/packages/contracts/util/rpc.ts b/packages/contracts/util/rpc.ts deleted file mode 100644 index 023602bd6..000000000 --- a/packages/contracts/util/rpc.ts +++ /dev/null @@ -1,43 +0,0 @@ -import 'isomorphic-fetch'; - -import * as truffleConf from '../truffle.js'; - -export class RPC { - private host: string; - private port: number; - private id: number; - constructor() { - this.host = truffleConf.networks.development.host; - this.port = truffleConf.networks.development.port; - this.id = 0; - } - public async increaseTimeAsync(time: number) { - const method = 'evm_increaseTime'; - const params = [time]; - const payload = this.toPayload(method, params); - return this.sendAsync(payload); - } - public async mineBlockAsync() { - const method = 'evm_mine'; - const payload = this.toPayload(method); - return this.sendAsync(payload); - } - private toPayload(method: string, params: any[] = []) { - const payload = JSON.stringify({ - id: this.id, - method, - params, - }); - this.id++; - return payload; - } - private async sendAsync(payload: string): Promise<any> { - const opts = { - method: 'POST', - body: payload, - }; - const response = await fetch(`http://${this.host}:${this.port}`, opts); - const responsePayload = await response.json(); - return responsePayload; - } -} diff --git a/packages/contracts/util/token_registry_wrapper.ts b/packages/contracts/util/token_registry_wrapper.ts index 5e1c627cc..07a577dea 100644 --- a/packages/contracts/util/token_registry_wrapper.ts +++ b/packages/contracts/util/token_registry_wrapper.ts @@ -1,24 +1,24 @@ -import {ContractInstance, Token} from './types'; +import { ContractInstance, Token } from './types'; export class TokenRegWrapper { - private tokenReg: ContractInstance; + private _tokenReg: ContractInstance; constructor(tokenRegContractInstance: ContractInstance) { - this.tokenReg = tokenRegContractInstance; + this._tokenReg = tokenRegContractInstance; } public addTokenAsync(token: Token, from: string) { - const tx = this.tokenReg.addToken( + const tx = this._tokenReg.addToken( token.address, token.name, token.symbol, token.decimals, token.ipfsHash, token.swarmHash, - {from}, + { from }, ); return tx; } public async getTokenMetaDataAsync(tokenAddress: string) { - const data = await this.tokenReg.getTokenMetaData(tokenAddress); + const data = await this._tokenReg.getTokenMetaData(tokenAddress); const token: Token = { address: data[0], name: data[1], @@ -30,7 +30,7 @@ export class TokenRegWrapper { return token; } public async getTokenByNameAsync(tokenName: string) { - const data = await this.tokenReg.getTokenByName(tokenName); + const data = await this._tokenReg.getTokenByName(tokenName); const token: Token = { address: data[0], name: data[1], @@ -42,7 +42,7 @@ export class TokenRegWrapper { return token; } public async getTokenBySymbolAsync(tokenSymbol: string) { - const data = await this.tokenReg.getTokenBySymbol(tokenSymbol); + const data = await this._tokenReg.getTokenBySymbol(tokenSymbol); const token: Token = { address: data[0], name: data[1], diff --git a/packages/contracts/util/types.ts b/packages/contracts/util/types.ts index b2cf786df..e511ca9f4 100644 --- a/packages/contracts/util/types.ts +++ b/packages/contracts/util/types.ts @@ -1,4 +1,4 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as Web3 from 'web3'; export interface BalancesByOwner { @@ -84,15 +84,6 @@ export interface TransactionDataParams { args: any[]; } -export interface Token { - address?: string; - name: string; - symbol: string; - decimals: number; - ipfsHash: string; - swarmHash: string; -} - export interface MultiSigConfig { owners: string[]; confirmationsRequired: number; @@ -103,6 +94,15 @@ export interface MultiSigConfigByNetwork { [networkName: string]: MultiSigConfig; } +export interface Token { + address?: string; + name: string; + symbol: string; + decimals: number; + ipfsHash: string; + swarmHash: string; +} + export interface TokenInfoByNetwork { development: Token[]; live: Token[]; diff --git a/packages/deployer/README.md b/packages/deployer/README.md new file mode 100644 index 000000000..4293f82d4 --- /dev/null +++ b/packages/deployer/README.md @@ -0,0 +1,73 @@ +## @0xproject/deployer + +This repository contains a CLI tool that facilitates compiling and deployment of smart contracts. + +## Installation + +```bash +yarn add @0xproject/deployer +``` + +## Usage + +```bash +node ./node_modules/@0xproject/deployer/lib/cli.js --help +cli.js [command] + +Commands: + cli.js compile compile contracts + cli.js migrate compile and deploy contracts using migration scripts + cli.js deploy deploy a single contract with provided arguments + +Options: + --version Show version number [boolean] + --contracts-dir path of contracts directory to compile + [string] [default: "/Users/leonidlogvinov/Dev/0x/0x.js/contracts"] + --network-id mainnet=1, kovan=42, testrpc=50 [number] [default: 50] + --should-optimize enable optimizer [boolean] [default: false] + --artifacts-dir path to write contracts artifacts to + [string] [default: "/Users/leonidlogvinov/Dev/0x/0x.js/build/artifacts/"] + --jsonrpc-port port connected to JSON RPC [number] [default: 8545] + --gas-price gasPrice to be used for transactions + [string] [default: "2000000000"] + --account account to use for deploying contracts [string] + --help Show help [boolean] +``` + +## Contributing + +We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. + +Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. + +### Install Dependencies + +If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: + +```bash +yarn config set workspaces-experimental true +``` + +Then install dependencies + +```bash +yarn install +``` + +### Build + +```bash +yarn build +``` + +### Lint + +```bash +yarn lint +``` + +### Run Tests + +```bash +yarn test +``` diff --git a/packages/deployer/package.json b/packages/deployer/package.json new file mode 100644 index 000000000..1ae0ca227 --- /dev/null +++ b/packages/deployer/package.json @@ -0,0 +1,43 @@ +{ + "name": "@0xproject/deployer", + "version": "0.0.2", + "description": "Smart contract deployer of 0x protocol", + "main": "lib/src/cli.js", + "scripts": { + "build": "yarn clean && copyfiles 'test/fixtures/contracts/**/*' src/solc/solc_bin/* ./lib && tsc", + "test": "npm run build; mocha lib/test/*_test.js", + "compile": "npm run build; node lib/src/cli.js compile", + "clean": "rm -rf ./lib", + "migrate": "npm run build; node lib/src/cli.js migrate", + "lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'", + "test:circleci": "yarn test" + }, + "bin": { + "0x-deployer": "lib/src/cli.js" + }, + "repository": { + "type": "git", + "url": "https://github.com/0xProject/0x.js.git" + }, + "author": "Amir Bandeali", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/0xProject/0x.js/issues" + }, + "homepage": "https://github.com/0xProject/0x.js/packages/deployer/README.md", + "devDependencies": { + "copyfiles": "^1.2.0", + "types-bn": "^0.0.1", + "typescript": "~2.6.1", + "web3-typescript-typings": "^0.9.5" + }, + "dependencies": { + "@0xproject/utils": "^0.1.3", + "@0xproject/web3-wrapper": "^0.1.6", + "lodash": "^4.17.4", + "solc": "^0.4.18", + "web3": "^0.20.0", + "web3-eth-abi": "^1.0.0-beta.24", + "yargs": "^10.0.3" + } +} diff --git a/packages/deployer/scripts/postpublish.js b/packages/deployer/scripts/postpublish.js new file mode 100644 index 000000000..24384b228 --- /dev/null +++ b/packages/deployer/scripts/postpublish.js @@ -0,0 +1,39 @@ +const execAsync = require('async-child-process').execAsync; +const postpublish_utils = require('../../../scripts/postpublish_utils'); +const packageJSON = require('../package.json'); + +const cwd = __dirname + '/..'; +const subPackageName = packageJSON.name; +const S3BucketPath = 's3://connect-docs-jsons/'; + +let tag; +let version; +postpublish_utils + .getLatestTagAndVersionAsync(subPackageName) + .then(function(result) { + tag = result.tag; + version = result.version; + const releaseName = postpublish_utils.getReleaseName(subPackageName, version); + return postpublish_utils.publishReleaseNotes(tag, releaseName); + }) + .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, + }); + }) + .then(function(result) { + if (result.stderr !== '') { + throw new Error(result.stderr); + } + const fileName = 'v' + version + '.json'; + console.log('POSTPUBLISH: Doc generation successful, uploading docs... as ', fileName); + const s3Url = S3BucketPath + fileName; + return execAsync('S3_URL=' + s3Url + ' yarn upload_docs_json', { + cwd, + }); + }) + .catch(function(err) { + throw err; + }); diff --git a/packages/contracts/deploy/cli.ts b/packages/deployer/src/cli.ts index 423523e21..decb37fdc 100644 --- a/packages/contracts/deploy/cli.ts +++ b/packages/deployer/src/cli.ts @@ -1,34 +1,30 @@ -import {Web3Wrapper} from '@0xproject/web3-wrapper'; -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as _ from 'lodash'; import * as path from 'path'; import * as Web3 from 'web3'; import * as yargs from 'yargs'; -import {commands} from './src/commands'; -import { - CliOptions, - CompilerOptions, - DeployerOptions, -} from './src/utils/types'; +import { commands } from './commands'; +import { CliOptions, CompilerOptions, DeployerOptions } from './utils/types'; const DEFAULT_OPTIMIZER_ENABLED = false; const DEFAULT_CONTRACTS_DIR = path.resolve('contracts'); const DEFAULT_ARTIFACTS_DIR = `${path.resolve('build')}/artifacts/`; const DEFAULT_NETWORK_ID = 50; const DEFAULT_JSONRPC_PORT = 8545; -const DEFAULT_GAS_PRICE = ((10 ** 9) * 2).toString(); +const DEFAULT_GAS_PRICE = (10 ** 9 * 2).toString(); /** * Compiles all contracts with options passed in through CLI. * @param argv Instance of process.argv provided by yargs. */ -async function onCompileCommand(args: CliOptions): Promise<void> { +async function onCompileCommand(argv: CliOptions): Promise<void> { const opts: CompilerOptions = { - contractsDir: args.contractsDir, - networkId: args.networkId, - optimizerEnabled: args.shouldOptimize ? 1 : 0, - artifactsDir: args.artifactsDir, + contractsDir: argv.contractsDir, + networkId: argv.networkId, + optimizerEnabled: argv.shouldOptimize ? 1 : 0, + artifactsDir: argv.artifactsDir, }; await commands.compileAsync(opts); } @@ -108,11 +104,11 @@ function deployCommandBuilder(yargsInstance: any) { description: 'comma separated list of constructor args to deploy contract with', }) .demandOption(['contract', 'args']) - .help() - .argv; + .help().argv; } (() => { + const identityCommandBuilder = _.identity; return yargs .option('contracts-dir', { type: 'string', @@ -148,18 +144,13 @@ function deployCommandBuilder(yargsInstance: any) { type: 'string', description: 'account to use for deploying contracts', }) - .command('compile', - 'compile contracts', - _.noop, - onCompileCommand) - .command('migrate', - 'compile and deploy contracts using migration scripts', - _.noop, - onMigrateCommand) - .command('deploy', - 'deploy a single contract with provided arguments', - deployCommandBuilder, - onDeployCommand) - .help() - .argv; + .command('compile', 'compile contracts', identityCommandBuilder, onCompileCommand) + .command( + 'migrate', + 'compile and deploy contracts using migration scripts', + identityCommandBuilder, + onMigrateCommand, + ) + .command('deploy', 'deploy a single contract with provided arguments', deployCommandBuilder, onDeployCommand) + .help().argv; })(); diff --git a/packages/contracts/deploy/src/commands.ts b/packages/deployer/src/commands.ts index fc421a760..2acef8e8f 100644 --- a/packages/contracts/deploy/src/commands.ts +++ b/packages/deployer/src/commands.ts @@ -1,7 +1,7 @@ -import {migrator} from './../migrations/migrate'; -import {Compiler} from './compiler'; -import {Deployer} from './deployer'; -import {CompilerOptions, DeployerOptions} from './utils/types'; +import { migrator } from './migrations/migrate'; +import { Compiler } from './compiler'; +import { Deployer } from './deployer'; +import { CompilerOptions, DeployerOptions } from './utils/types'; export const commands = { async compileAsync(opts: CompilerOptions): Promise<void> { diff --git a/packages/contracts/deploy/src/compiler.ts b/packages/deployer/src/compiler.ts index 8a44e94a3..63db6c865 100644 --- a/packages/contracts/deploy/src/compiler.ts +++ b/packages/deployer/src/compiler.ts @@ -1,12 +1,11 @@ -import {promisify} from '@0xproject/utils'; import * as ethUtil from 'ethereumjs-util'; import * as _ from 'lodash'; import * as path from 'path'; import solc = require('solc'); import * as Web3 from 'web3'; -import {binPaths} from './../solc/bin_paths'; -import {fsWrapper} from './utils/fs_wrapper'; +import { binPaths } from './solc/bin_paths'; +import { fsWrapper } from './utils/fs_wrapper'; import { CompilerOptions, ContractArtifact, @@ -14,25 +13,24 @@ import { ContractNetworks, ContractSources, ImportContents, - SolcErrors, } from './utils/types'; -import {utils} from './utils/utils'; +import { utils } from './utils/utils'; const SOLIDITY_FILE_EXTENSION = '.sol'; export class Compiler { - private contractsDir: string; - private networkId: number; - private optimizerEnabled: number; - private artifactsDir: string; - private contractSourcesIfExists?: ContractSources; - private solcErrors: Set<string>; + private _contractsDir: string; + private _networkId: number; + private _optimizerEnabled: number; + private _artifactsDir: string; + private _contractSourcesIfExists?: ContractSources; + private _solcErrors: Set<string>; /** * Recursively retrieves Solidity source code from directory. * @param dirPath Directory to search. * @return Mapping of contract name to contract source. */ - private static async getContractSourcesAsync(dirPath: string): Promise<ContractSources> { + private static async _getContractSourcesAsync(dirPath: string): Promise<ContractSources> { let dirContents: string[] = []; try { dirContents = await fsWrapper.readdirAsync(dirPath); @@ -54,7 +52,7 @@ export class Compiler { } } else { try { - const nestedSources = await Compiler.getContractSourcesAsync(contentPath); + const nestedSources = await Compiler._getContractSourcesAsync(contentPath); sources = { ...sources, ...nestedSources, @@ -71,7 +69,7 @@ export class Compiler { * @param source Source code of contract. * @return Solc compiler version. */ - private static parseSolidityVersion(source: string): string { + private static _parseSolidityVersion(source: string): string { const solcVersionMatch = source.match(/(?:solidity\s\^?)([0-9]{1,2}[.][0-9]{1,2}[.][0-9]{1,2})/); if (_.isNull(solcVersionMatch)) { throw new Error('Could not find Solidity version in source'); @@ -87,7 +85,7 @@ export class Compiler { * @param errMsg An error message from the compiled output. * @return The error message with directories truncated from the contract path. */ - private static getNormalizedErrMsg(errMsg: string): string { + private static _getNormalizedErrMsg(errMsg: string): string { const errPathMatch = errMsg.match(/(.*\.sol)/); if (_.isNull(errPathMatch)) { throw new Error('Could not find a path in error message'); @@ -103,26 +101,25 @@ export class Compiler { * @return An instance of the Compiler class. */ constructor(opts: CompilerOptions) { - this.contractsDir = opts.contractsDir; - this.networkId = opts.networkId; - this.optimizerEnabled = opts.optimizerEnabled; - this.artifactsDir = opts.artifactsDir; - this.solcErrors = new Set(); + this._contractsDir = opts.contractsDir; + this._networkId = opts.networkId; + this._optimizerEnabled = opts.optimizerEnabled; + this._artifactsDir = opts.artifactsDir; + this._solcErrors = new Set(); } /** * Compiles all Solidity files found in contractsDir and writes JSON artifacts to artifactsDir. */ public async compileAllAsync(): Promise<void> { - await this.createArtifactsDirIfDoesNotExistAsync(); - this.contractSourcesIfExists = await Compiler.getContractSourcesAsync(this.contractsDir); - - const contractBaseNames = _.keys(this.contractSourcesIfExists); + await this._createArtifactsDirIfDoesNotExistAsync(); + this._contractSourcesIfExists = await Compiler._getContractSourcesAsync(this._contractsDir); + const contractBaseNames = _.keys(this._contractSourcesIfExists); const compiledContractPromises = _.map(contractBaseNames, async (contractBaseName: string): Promise<void> => { - return this.compileContractAsync(contractBaseName); + return this._compileContractAsync(contractBaseName); }); await Promise.all(compiledContractPromises); - this.solcErrors.forEach(errMsg => { + this._solcErrors.forEach(errMsg => { utils.consoleLog(errMsg); }); } @@ -130,14 +127,14 @@ export class Compiler { * Compiles contract and saves artifact to artifactsDir. * @param contractBaseName Name of contract with '.sol' extension. */ - private async compileContractAsync(contractBaseName: string): Promise<void> { - if (_.isUndefined(this.contractSourcesIfExists)) { + private async _compileContractAsync(contractBaseName: string): Promise<void> { + if (_.isUndefined(this._contractSourcesIfExists)) { throw new Error('Contract sources not yet initialized'); } - const source = this.contractSourcesIfExists[contractBaseName]; + const source = this._contractSourcesIfExists[contractBaseName]; const contractName = path.basename(contractBaseName, SOLIDITY_FILE_EXTENSION); - const currentArtifactPath = `${this.artifactsDir}/${contractName}.json`; + const currentArtifactPath = `${this._artifactsDir}/${contractName}.json`; const sourceHash = `0x${ethUtil.sha3(source).toString('hex')}`; let currentArtifactString: string; @@ -151,10 +148,11 @@ export class Compiler { currentArtifactString = await fsWrapper.readFileAsync(currentArtifactPath, opts); currentArtifact = JSON.parse(currentArtifactString); oldNetworks = currentArtifact.networks; - const oldNetwork: ContractData = oldNetworks[this.networkId]; - shouldCompile = _.isUndefined(oldNetwork) || - oldNetwork.keccak256 !== sourceHash || - oldNetwork.optimizer_enabled !== this.optimizerEnabled; + const oldNetwork: ContractData = oldNetworks[this._networkId]; + shouldCompile = + _.isUndefined(oldNetwork) || + oldNetwork.keccak256 !== sourceHash || + oldNetwork.optimizer_enabled !== this._optimizerEnabled; } catch (err) { shouldCompile = true; } @@ -166,9 +164,9 @@ export class Compiler { const input = { [contractBaseName]: source, }; - const solcVersion = Compiler.parseSolidityVersion(source); + const solcVersion = Compiler._parseSolidityVersion(source); const fullSolcVersion = binPaths[solcVersion]; - const solcBinPath = `./../solc/solc_bin/${fullSolcVersion}`; + const solcBinPath = `./solc/solc_bin/${fullSolcVersion}`; const solcBin = require(solcBinPath); const solcInstance = solc.setupMethods(solcBin); @@ -176,14 +174,16 @@ export class Compiler { const sourcesToCompile = { sources: input, }; - const compiled = solcInstance.compile(sourcesToCompile, - this.optimizerEnabled, - this.findImportsIfSourcesExist.bind(this)); + const compiled = solcInstance.compile( + sourcesToCompile, + this._optimizerEnabled, + this._findImportsIfSourcesExist.bind(this), + ); if (!_.isUndefined(compiled.errors)) { _.each(compiled.errors, errMsg => { - const normalizedErrMsg = Compiler.getNormalizedErrMsg(errMsg); - this.solcErrors.add(normalizedErrMsg); + const normalizedErrMsg = Compiler._getNormalizedErrMsg(errMsg); + this._solcErrors.add(normalizedErrMsg); }); } @@ -194,7 +194,7 @@ export class Compiler { const contractData: ContractData = { solc_version: solcVersion, keccak256: sourceHash, - optimizer_enabled: this.optimizerEnabled, + optimizer_enabled: this._optimizerEnabled, abi, unlinked_binary, updated_at, @@ -206,14 +206,14 @@ export class Compiler { ...currentArtifact, networks: { ...oldNetworks, - [this.networkId]: contractData, + [this._networkId]: contractData, }, }; } else { newArtifact = { contract_name: contractName, networks: { - [this.networkId]: contractData, + [this._networkId]: contractData, }, }; } @@ -228,12 +228,12 @@ export class Compiler { * @param importPath Path to an imported dependency. * @return Import contents object containing source code of dependency. */ - private findImportsIfSourcesExist(importPath: string): ImportContents { - if (_.isUndefined(this.contractSourcesIfExists)) { + private _findImportsIfSourcesExist(importPath: string): ImportContents { + if (_.isUndefined(this._contractSourcesIfExists)) { throw new Error('Contract sources not yet initialized'); } const contractBaseName = path.basename(importPath); - const source = this.contractSourcesIfExists[contractBaseName]; + const source = this._contractSourcesIfExists[contractBaseName]; const importContents: ImportContents = { contents: source, }; @@ -242,10 +242,10 @@ export class Compiler { /** * Creates the artifacts directory if it does not already exist. */ - private async createArtifactsDirIfDoesNotExistAsync(): Promise<void> { - if (!fsWrapper.doesPathExistSync(this.artifactsDir)) { + private async _createArtifactsDirIfDoesNotExistAsync(): Promise<void> { + if (!fsWrapper.doesPathExistSync(this._artifactsDir)) { utils.consoleLog('Creating artifacts directory...'); - await fsWrapper.mkdirAsync(this.artifactsDir); + await fsWrapper.mkdirAsync(this._artifactsDir); } } } diff --git a/packages/contracts/deploy/src/deployer.ts b/packages/deployer/src/deployer.ts index 4c8018ecc..6f03581e8 100644 --- a/packages/contracts/deploy/src/deployer.ts +++ b/packages/deployer/src/deployer.ts @@ -1,37 +1,32 @@ -import {TxData} from '@0xproject/types'; -import {promisify} from '@0xproject/utils'; -import {Web3Wrapper} from '@0xproject/web3-wrapper'; +import { TxData } from '@0xproject/types'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as _ from 'lodash'; import * as Web3 from 'web3'; -import {Contract} from './utils/contract'; -import {encoder} from './utils/encoder'; -import {fsWrapper} from './utils/fs_wrapper'; -import { - ContractArtifact, - ContractData, - DeployerOptions, -} from './utils/types'; -import {utils} from './utils/utils'; +import { Contract } from './utils/contract'; +import { encoder } from './utils/encoder'; +import { fsWrapper } from './utils/fs_wrapper'; +import { ContractArtifact, ContractData, DeployerOptions } from './utils/types'; +import { utils } from './utils/utils'; // Gas added to gas estimate to make sure there is sufficient gas for deployment. const EXTRA_GAS = 200000; export class Deployer { public web3Wrapper: Web3Wrapper; - private artifactsDir: string; - private jsonrpcPort: number; - private networkId: number; - private defaults: Partial<TxData>; + private _artifactsDir: string; + private _jsonrpcPort: number; + private _networkId: number; + private _defaults: Partial<TxData>; constructor(opts: DeployerOptions) { - this.artifactsDir = opts.artifactsDir; - this.jsonrpcPort = opts.jsonrpcPort; - this.networkId = opts.networkId; - const jsonrpcUrl = `http://localhost:${this.jsonrpcPort}`; + this._artifactsDir = opts.artifactsDir; + this._jsonrpcPort = opts.jsonrpcPort; + this._networkId = opts.networkId; + const jsonrpcUrl = `http://localhost:${this._jsonrpcPort}`; const web3Provider = new Web3.providers.HttpProvider(jsonrpcUrl); - this.defaults = opts.defaults; - this.web3Wrapper = new Web3Wrapper(web3Provider, this.defaults); + this._defaults = opts.defaults; + this.web3Wrapper = new Web3Wrapper(web3Provider, this._defaults); } /** * Loads contract artifact and deploys contract with given arguments. @@ -40,21 +35,21 @@ export class Deployer { * @return Deployed contract instance. */ public async deployAsync(contractName: string, args: any[] = []): Promise<Web3.ContractInstance> { - const contractArtifact: ContractArtifact = this.loadContractArtifactIfExists(contractName); - const contractData: ContractData = this.getContractDataFromArtifactIfExists(contractArtifact); + const contractArtifact: ContractArtifact = this._loadContractArtifactIfExists(contractName); + const contractData: ContractData = this._getContractDataFromArtifactIfExists(contractArtifact); const data = contractData.unlinked_binary; - const from = await this.getFromAddressAsync(); - const gas = await this.getAllowableGasEstimateAsync(data); + const from = await this._getFromAddressAsync(); + const gas = await this._getAllowableGasEstimateAsync(data); const txData = { - gasPrice: this.defaults.gasPrice, + gasPrice: this._defaults.gasPrice, from, data, gas, }; const abi = contractData.abi; - const web3ContractInstance = await this.deployFromAbiAsync(abi, args, txData); + const web3ContractInstance = await this._deployFromAbiAsync(abi, args, txData); utils.consoleLog(`${contractName}.sol successfully deployed at ${web3ContractInstance.address}`); - const contractInstance = new Contract(web3ContractInstance, this.defaults); + const contractInstance = new Contract(web3ContractInstance, this._defaults); return contractInstance; } /** @@ -65,7 +60,7 @@ export class Deployer { */ public async deployAndSaveAsync(contractName: string, args: any[] = []): Promise<Web3.ContractInstance> { const contractInstance = await this.deployAsync(contractName, args); - await this.saveContractDataToArtifactAsync(contractName, contractInstance.address, args); + await this._saveContractDataToArtifactAsync(contractName, contractInstance.address, args); return contractInstance; } /** @@ -75,7 +70,7 @@ export class Deployer { * @param txData Tx options used for deployment. * @return Promise that resolves to a web3 contract instance. */ - private async deployFromAbiAsync(abi: Web3.ContractAbi, args: any[], txData: Web3.TxData): Promise<any> { + private async _deployFromAbiAsync(abi: Web3.ContractAbi, args: any[], txData: Web3.TxData): Promise<any> { const contract: Web3.Contract<Web3.ContractInstance> = this.web3Wrapper.getContractFromAbi(abi); const deployPromise = new Promise((resolve, reject) => { /** @@ -100,10 +95,13 @@ export class Deployer { * @param contractAddress Contract address to save to artifact. * @param args Contract constructor arguments that will be encoded and saved to artifact. */ - private async saveContractDataToArtifactAsync(contractName: string, - contractAddress: string, args: any[]): Promise<void> { - const contractArtifact: ContractArtifact = this.loadContractArtifactIfExists(contractName); - const contractData: ContractData = this.getContractDataFromArtifactIfExists(contractArtifact); + private async _saveContractDataToArtifactAsync( + contractName: string, + contractAddress: string, + args: any[], + ): Promise<void> { + const contractArtifact: ContractArtifact = this._loadContractArtifactIfExists(contractName); + const contractData: ContractData = this._getContractDataFromArtifactIfExists(contractArtifact); const abi = contractData.abi; const encodedConstructorArgs = encoder.encodeConstructorArgsFromAbi(args, abi); const newContractData = { @@ -115,11 +113,11 @@ export class Deployer { ...contractArtifact, networks: { ...contractArtifact.networks, - [this.networkId]: newContractData, + [this._networkId]: newContractData, }, }; const artifactString = utils.stringifyWithFormatting(newArtifact); - const artifactPath = `${this.artifactsDir}/${contractName}.json`; + const artifactPath = `${this._artifactsDir}/${contractName}.json`; await fsWrapper.writeFileAsync(artifactPath, artifactString); } /** @@ -127,8 +125,8 @@ export class Deployer { * @param contractName Name of the contract, without the extension. * @return The contract artifact. */ - private loadContractArtifactIfExists(contractName: string): ContractArtifact { - const artifactPath = `${this.artifactsDir}/${contractName}.json`; + private _loadContractArtifactIfExists(contractName: string): ContractArtifact { + const artifactPath = `${this._artifactsDir}/${contractName}.json`; try { const contractArtifact: ContractArtifact = require(artifactPath); return contractArtifact; @@ -141,8 +139,8 @@ export class Deployer { * @param contractArtifact The contract artifact. * @return Network specific contract data. */ - private getContractDataFromArtifactIfExists(contractArtifact: ContractArtifact): ContractData { - const contractData = contractArtifact.networks[this.networkId]; + private _getContractDataFromArtifactIfExists(contractArtifact: ContractArtifact): ContractData { + const contractData = contractArtifact.networks[this._networkId]; if (_.isUndefined(contractData)) { throw new Error(`Data not found in artifact for contract: ${contractArtifact.contract_name}`); } @@ -152,13 +150,13 @@ export class Deployer { * Gets the address to use for sending a transaction. * @return The default from address. If not specified, returns the first address accessible by web3. */ - private async getFromAddressAsync(): Promise<string> { + private async _getFromAddressAsync(): Promise<string> { let from: string; - if (_.isUndefined(this.defaults.from)) { + if (_.isUndefined(this._defaults.from)) { const accounts = await this.web3Wrapper.getAvailableAddressesAsync(); from = accounts[0]; } else { - from = this.defaults.from; + from = this._defaults.from; } return from; } @@ -168,7 +166,7 @@ export class Deployer { * @param data Bytecode to estimate gas for. * @return Gas estimate for transaction data. */ - private async getAllowableGasEstimateAsync(data: string): Promise<number> { + private async _getAllowableGasEstimateAsync(data: string): Promise<number> { const block = await this.web3Wrapper.getBlockAsync('latest'); let gas: number; try { diff --git a/packages/deployer/src/globals.d.ts b/packages/deployer/src/globals.d.ts new file mode 100644 index 000000000..0a35002da --- /dev/null +++ b/packages/deployer/src/globals.d.ts @@ -0,0 +1,8 @@ +declare module 'solc' { + export function compile(sources: any, optimizerEnabled: number, findImports: (importPath: string) => any): any; + export function setupMethods(solcBin: any): any; +} + +declare module 'web3-eth-abi' { + export function encodeParameters(typesArray: string[], parameters: any[]): string; +} diff --git a/packages/deployer/src/migrations/config/multisig_sample.ts b/packages/deployer/src/migrations/config/multisig_sample.ts new file mode 100644 index 000000000..dabeb7a4f --- /dev/null +++ b/packages/deployer/src/migrations/config/multisig_sample.ts @@ -0,0 +1,10 @@ +import { MultiSigConfigByNetwork } from '../../types'; + +// Make a copy of this file named `multisig.js` and input custom params as needed +export const multiSig: MultiSigConfigByNetwork = { + kovan: { + owners: [], + confirmationsRequired: 0, + secondsRequired: 0, + }, +}; diff --git a/packages/contracts/deploy/migrations/config/token_info.ts b/packages/deployer/src/migrations/config/token_info.ts index f56914ecb..7e822fc3b 100644 --- a/packages/contracts/deploy/migrations/config/token_info.ts +++ b/packages/deployer/src/migrations/config/token_info.ts @@ -1,5 +1,5 @@ -import {constants} from './../../src/utils/constants'; -import {Token} from './../../src/utils/types'; +import { constants } from '../../utils/constants'; +import { Token } from '../../types'; export const tokenInfo: Token[] = [ { diff --git a/packages/deployer/src/migrations/migrate.ts b/packages/deployer/src/migrations/migrate.ts new file mode 100644 index 000000000..393806b45 --- /dev/null +++ b/packages/deployer/src/migrations/migrate.ts @@ -0,0 +1,90 @@ +import { BigNumber } from '@0xproject/utils'; +import { Web3Wrapper } from '@0xproject/web3-wrapper'; +import * as _ from 'lodash'; + +import { Deployer } from '../deployer'; +import { constants } from '../utils/constants'; +import { tokenInfo } from './config/token_info'; + +export const migrator = { + /** + * Custom migrations should be defined in this function. This will be called with the CLI 'migrate' command. + * Some operations might be completed in parallel, but we don't do that on purpose. + * That way the addresses are deterministic. + * @param deployer Deployer instance. + */ + async runMigrationsAsync(deployer: Deployer): Promise<void> { + const web3Wrapper: Web3Wrapper = deployer.web3Wrapper; + const accounts: string[] = await web3Wrapper.getAvailableAddressesAsync(); + + const tokenTransferProxy = await deployer.deployAndSaveAsync('TokenTransferProxy'); + const zrxToken = await deployer.deployAndSaveAsync('ZRXToken'); + const etherToken = await deployer.deployAndSaveAsync('WETH9'); + const tokenReg = await deployer.deployAndSaveAsync('TokenRegistry'); + + const exchangeArgs = [zrxToken.address, tokenTransferProxy.address]; + const owners = [accounts[0], accounts[1]]; + const confirmationsRequired = new BigNumber(2); + const secondsRequired = new BigNumber(0); + const multiSigArgs = [owners, confirmationsRequired, secondsRequired, tokenTransferProxy.address]; + const exchange = await deployer.deployAndSaveAsync('Exchange', exchangeArgs); + const multiSig = await deployer.deployAndSaveAsync( + 'MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', + multiSigArgs, + ); + + const owner = accounts[0]; + await tokenTransferProxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: owner }); + await tokenTransferProxy.transferOwnership.sendTransactionAsync(multiSig.address, { from: owner }); + const addTokenGasEstimate = await tokenReg.addToken.estimateGasAsync( + zrxToken.address, + tokenInfo[0].name, + tokenInfo[0].symbol, + tokenInfo[0].decimals, + tokenInfo[0].ipfsHash, + tokenInfo[0].swarmHash, + { from: owner }, + ); + await tokenReg.addToken.sendTransactionAsync( + zrxToken.address, + '0x Protocol Token', + 'ZRX', + 18, + constants.NULL_BYTES, + constants.NULL_BYTES, + { + from: owner, + gas: addTokenGasEstimate, + }, + ); + await tokenReg.addToken.sendTransactionAsync( + etherToken.address, + 'Ether Token', + 'WETH', + 18, + constants.NULL_BYTES, + constants.NULL_BYTES, + { + from: owner, + gas: addTokenGasEstimate, + }, + ); + for (const token of tokenInfo) { + const totalSupply = new BigNumber(0); + const args = [token.name, token.symbol, token.decimals, totalSupply]; + const dummyToken = await deployer.deployAsync('DummyToken', args); + await tokenReg.addToken.sendTransactionAsync( + dummyToken.address, + token.name, + token.symbol, + token.decimals, + token.ipfsHash, + token.swarmHash, + { + from: owner, + gas: addTokenGasEstimate, + }, + ); + } + }, +}; diff --git a/packages/contracts/deploy/solc/bin_paths.ts b/packages/deployer/src/solc/bin_paths.ts index a2d345bd7..e5b107101 100644 --- a/packages/contracts/deploy/solc/bin_paths.ts +++ b/packages/deployer/src/solc/bin_paths.ts @@ -1,4 +1,4 @@ -interface BinaryPaths { +export interface BinaryPaths { [key: string]: string; } diff --git a/packages/contracts/deploy/solc/solc_bin/soljson-v0.4.10+commit.f0d539ae.js b/packages/deployer/src/solc/solc_bin/soljson-v0.4.10+commit.f0d539ae.js index abeaeef1a..abeaeef1a 100644 --- a/packages/contracts/deploy/solc/solc_bin/soljson-v0.4.10+commit.f0d539ae.js +++ b/packages/deployer/src/solc/solc_bin/soljson-v0.4.10+commit.f0d539ae.js diff --git a/packages/contracts/deploy/solc/solc_bin/soljson-v0.4.11+commit.68ef5810.js b/packages/deployer/src/solc/solc_bin/soljson-v0.4.11+commit.68ef5810.js index 522ad2afe..522ad2afe 100644 --- a/packages/contracts/deploy/solc/solc_bin/soljson-v0.4.11+commit.68ef5810.js +++ b/packages/deployer/src/solc/solc_bin/soljson-v0.4.11+commit.68ef5810.js diff --git a/packages/contracts/deploy/solc/solc_bin/soljson-v0.4.12+commit.194ff033.js b/packages/deployer/src/solc/solc_bin/soljson-v0.4.12+commit.194ff033.js index 959545448..959545448 100644 --- a/packages/contracts/deploy/solc/solc_bin/soljson-v0.4.12+commit.194ff033.js +++ b/packages/deployer/src/solc/solc_bin/soljson-v0.4.12+commit.194ff033.js diff --git a/packages/contracts/deploy/solc/solc_bin/soljson-v0.4.13+commit.fb4cb1a.js b/packages/deployer/src/solc/solc_bin/soljson-v0.4.13+commit.fb4cb1a.js index 73705304e..73705304e 100644 --- a/packages/contracts/deploy/solc/solc_bin/soljson-v0.4.13+commit.fb4cb1a.js +++ b/packages/deployer/src/solc/solc_bin/soljson-v0.4.13+commit.fb4cb1a.js diff --git a/packages/contracts/deploy/solc/solc_bin/soljson-v0.4.14+commit.c2215d46.js b/packages/deployer/src/solc/solc_bin/soljson-v0.4.14+commit.c2215d46.js index 56bba18f2..56bba18f2 100644 --- a/packages/contracts/deploy/solc/solc_bin/soljson-v0.4.14+commit.c2215d46.js +++ b/packages/deployer/src/solc/solc_bin/soljson-v0.4.14+commit.c2215d46.js diff --git a/packages/contracts/deploy/solc/solc_bin/soljson-v0.4.15+commit.bbb8e64f.js b/packages/deployer/src/solc/solc_bin/soljson-v0.4.15+commit.bbb8e64f.js index c01807a87..c01807a87 100644 --- a/packages/contracts/deploy/solc/solc_bin/soljson-v0.4.15+commit.bbb8e64f.js +++ b/packages/deployer/src/solc/solc_bin/soljson-v0.4.15+commit.bbb8e64f.js diff --git a/packages/contracts/deploy/solc/solc_bin/soljson-v0.4.16+commit.d7661dd9.js b/packages/deployer/src/solc/solc_bin/soljson-v0.4.16+commit.d7661dd9.js index 5a8b08af9..5a8b08af9 100644 --- a/packages/contracts/deploy/solc/solc_bin/soljson-v0.4.16+commit.d7661dd9.js +++ b/packages/deployer/src/solc/solc_bin/soljson-v0.4.16+commit.d7661dd9.js diff --git a/packages/contracts/deploy/solc/solc_bin/soljson-v0.4.17+commit.bdeb9e52.js b/packages/deployer/src/solc/solc_bin/soljson-v0.4.17+commit.bdeb9e52.js index b91555a9f..b91555a9f 100644 --- a/packages/contracts/deploy/solc/solc_bin/soljson-v0.4.17+commit.bdeb9e52.js +++ b/packages/deployer/src/solc/solc_bin/soljson-v0.4.17+commit.bdeb9e52.js diff --git a/packages/contracts/deploy/solc/solc_bin/soljson-v0.4.18+commit.9cf6e910.js b/packages/deployer/src/solc/solc_bin/soljson-v0.4.18+commit.9cf6e910.js index 5b99e8c72..5b99e8c72 100644 --- a/packages/contracts/deploy/solc/solc_bin/soljson-v0.4.18+commit.9cf6e910.js +++ b/packages/deployer/src/solc/solc_bin/soljson-v0.4.18+commit.9cf6e910.js diff --git a/packages/deployer/src/types.ts b/packages/deployer/src/types.ts new file mode 100644 index 000000000..58d1e5b4f --- /dev/null +++ b/packages/deployer/src/types.ts @@ -0,0 +1,23 @@ +export interface MultiSigConfig { + owners: string[]; + confirmationsRequired: number; + secondsRequired: number; +} + +export interface MultiSigConfigByNetwork { + [networkName: string]: MultiSigConfig; +} + +export interface Token { + address?: string; + name: string; + symbol: string; + decimals: number; + ipfsHash: string; + swarmHash: string; +} + +export interface TokenInfoByNetwork { + development: Token[]; + live: Token[]; +} diff --git a/packages/contracts/deploy/src/utils/constants.ts b/packages/deployer/src/utils/constants.ts index 8871a470d..8871a470d 100644 --- a/packages/contracts/deploy/src/utils/constants.ts +++ b/packages/deployer/src/utils/constants.ts diff --git a/packages/contracts/deploy/src/utils/contract.ts b/packages/deployer/src/utils/contract.ts index 7b6098cea..546e82dfb 100644 --- a/packages/contracts/deploy/src/utils/contract.ts +++ b/packages/deployer/src/utils/contract.ts @@ -1,62 +1,62 @@ -import {schemas, SchemaValidator} from '@0xproject/json-schemas'; -import {promisify} from '@0xproject/utils'; +import { schemas, SchemaValidator } from '@0xproject/json-schemas'; +import { promisify } from '@0xproject/utils'; import * as _ from 'lodash'; import * as Web3 from 'web3'; -import {AbiType} from './types'; +import { AbiType } from './types'; export class Contract implements Web3.ContractInstance { public address: string; public abi: Web3.ContractAbi; - private contract: Web3.ContractInstance; - private defaults: Partial<Web3.TxData>; - private validator: SchemaValidator; + private _contract: Web3.ContractInstance; + private _defaults: Partial<Web3.TxData>; + private _validator: SchemaValidator; // This class instance is going to be populated with functions and events depending on the ABI // and we don't know their types in advance [name: string]: any; constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<Web3.TxData>) { - this.contract = web3ContractInstance; + this._contract = web3ContractInstance; this.address = web3ContractInstance.address; this.abi = web3ContractInstance.abi; - this.defaults = defaults; - this.populateEvents(); - this.populateFunctions(); - this.validator = new SchemaValidator(); + this._defaults = defaults; + this._populateEvents(); + this._populateFunctions(); + this._validator = new SchemaValidator(); } - private populateFunctions(): void { - const functionsAbi = _.filter(this.abi, abiPart => abiPart.type === AbiType.Function); + private _populateFunctions(): void { + const functionsAbi = _.filter(this.abi, abiPart => abiPart.type === AbiType.Function) as Web3.FunctionAbi[]; _.forEach(functionsAbi, (functionAbi: Web3.MethodAbi) => { if (functionAbi.constant) { - const cbStyleCallFunction = this.contract[functionAbi.name].call; + const cbStyleCallFunction = this._contract[functionAbi.name].call; this[functionAbi.name] = { - callAsync: promisify(cbStyleCallFunction, this.contract), + callAsync: promisify(cbStyleCallFunction, this._contract), }; } else { - const cbStyleFunction = this.contract[functionAbi.name]; - const cbStyleEstimateGasFunction = this.contract[functionAbi.name].estimateGas; + const cbStyleFunction = this._contract[functionAbi.name]; + const cbStyleEstimateGasFunction = this._contract[functionAbi.name].estimateGas; this[functionAbi.name] = { - estimateGasAsync: promisify(cbStyleEstimateGasFunction, this.contract), - sendTransactionAsync: this.promisifyWithDefaultParams(cbStyleFunction), + estimateGasAsync: promisify(cbStyleEstimateGasFunction, this._contract), + sendTransactionAsync: this._promisifyWithDefaultParams(cbStyleFunction), }; } }); } - private populateEvents(): void { - const eventsAbi = _.filter(this.abi, abiPart => abiPart.type === AbiType.Event); + private _populateEvents(): void { + const eventsAbi = _.filter(this.abi, abiPart => abiPart.type === AbiType.Event) as Web3.EventAbi[]; _.forEach(eventsAbi, (eventAbi: Web3.EventAbi) => { - this[eventAbi.name] = this.contract[eventAbi.name]; + this[eventAbi.name] = this._contract[eventAbi.name]; }); } - private promisifyWithDefaultParams(fn: (...args: any[]) => void): (...args: any[]) => Promise<any> { + private _promisifyWithDefaultParams(fn: (...args: any[]) => void): (...args: any[]) => Promise<any> { const promisifiedWithDefaultParams = async (...args: any[]) => { const promise = new Promise((resolve, reject) => { const lastArg = args[args.length - 1]; let txData: Partial<Web3.TxData> = {}; - if (this.isTxData(lastArg)) { + if (this._isTxData(lastArg)) { txData = args.pop(); } txData = { - ...this.defaults, + ...this._defaults, ...txData, }; const callback = (err: Error, data: any) => { @@ -68,14 +68,14 @@ export class Contract implements Web3.ContractInstance { }; args.push(txData); args.push(callback); - fn.apply(this.contract, args); + fn.apply(this._contract, args); }); return promise; }; return promisifiedWithDefaultParams; } - private isTxData(lastArg: any): boolean { - const isValid = this.validator.isValid(lastArg, schemas.txDataSchema); + private _isTxData(lastArg: any): boolean { + const isValid = this._validator.isValid(lastArg, schemas.txDataSchema); return isValid; } } diff --git a/packages/contracts/deploy/src/utils/encoder.ts b/packages/deployer/src/utils/encoder.ts index 0248e9f03..d5f807774 100644 --- a/packages/contracts/deploy/src/utils/encoder.ts +++ b/packages/deployer/src/utils/encoder.ts @@ -2,7 +2,7 @@ import * as _ from 'lodash'; import * as Web3 from 'web3'; import * as web3Abi from 'web3-eth-abi'; -import {AbiType} from './types'; +import { AbiType } from './types'; export const encoder = { encodeConstructorArgsFromAbi(args: any[], abi: Web3.ContractAbi): string { diff --git a/packages/contracts/deploy/src/utils/fs_wrapper.ts b/packages/deployer/src/utils/fs_wrapper.ts index 90785d0dd..34c7caa0e 100644 --- a/packages/contracts/deploy/src/utils/fs_wrapper.ts +++ b/packages/deployer/src/utils/fs_wrapper.ts @@ -1,4 +1,4 @@ -import {promisify} from '@0xproject/utils'; +import { promisify } from '@0xproject/utils'; import * as fs from 'fs'; export const fsWrapper = { diff --git a/packages/contracts/deploy/src/utils/types.ts b/packages/deployer/src/utils/types.ts index f6b9de6e9..e054b9cc2 100644 --- a/packages/contracts/deploy/src/utils/types.ts +++ b/packages/deployer/src/utils/types.ts @@ -1,5 +1,6 @@ -import {TxData} from '@0xproject/types'; +import { TxData } from '@0xproject/types'; import * as Web3 from 'web3'; +import * as yargs from 'yargs'; export enum AbiType { Function = 'function', @@ -32,7 +33,7 @@ export interface SolcErrors { [key: string]: boolean; } -export interface CliOptions { +export interface CliOptions extends yargs.Arguments { artifactsDir: string; contractsDir: string; jsonrpcPort: number; diff --git a/packages/contracts/deploy/src/utils/utils.ts b/packages/deployer/src/utils/utils.ts index 4390d8813..4390d8813 100644 --- a/packages/contracts/deploy/src/utils/utils.ts +++ b/packages/deployer/src/utils/utils.ts diff --git a/packages/contracts/deploy/test/deploy_test.ts b/packages/deployer/test/deploy_test.ts index 7e7b98f90..5df729a04 100644 --- a/packages/contracts/deploy/test/deploy_test.ts +++ b/packages/deployer/test/deploy_test.ts @@ -1,12 +1,12 @@ import * as chai from 'chai'; import 'mocha'; -import {Compiler} from './../src/compiler'; -import {Deployer} from './../src/deployer'; -import {fsWrapper} from './../src/utils/fs_wrapper'; -import {CompilerOptions, ContractArtifact, ContractData, DeployerOptions, DoneCallback} from './../src/utils/types'; -import {constructor_args, exchange_binary} from './fixtures/exchange_bin'; -import {constants} from './util/constants'; +import { Compiler } from '../src/compiler'; +import { Deployer } from '../src/deployer'; +import { fsWrapper } from '../src/utils/fs_wrapper'; +import { CompilerOptions, ContractArtifact, ContractData, DoneCallback } from '../src/utils/types'; +import { constructor_args, exchange_binary } from './fixtures/exchange_bin'; +import { constants } from './util/constants'; const expect = chai.expect; const artifactsDir = `${__dirname}/fixtures/artifacts`; diff --git a/packages/contracts/deploy/test/fixtures/contracts/Exchange.sol b/packages/deployer/test/fixtures/contracts/Exchange.sol index 1b6819700..1b6819700 100644 --- a/packages/contracts/deploy/test/fixtures/contracts/Exchange.sol +++ b/packages/deployer/test/fixtures/contracts/Exchange.sol diff --git a/packages/contracts/deploy/test/fixtures/contracts/TokenTransferProxy.sol b/packages/deployer/test/fixtures/contracts/TokenTransferProxy.sol index 90c8e7d66..90c8e7d66 100644 --- a/packages/contracts/deploy/test/fixtures/contracts/TokenTransferProxy.sol +++ b/packages/deployer/test/fixtures/contracts/TokenTransferProxy.sol diff --git a/packages/contracts/deploy/test/fixtures/contracts/base/Ownable.sol b/packages/deployer/test/fixtures/contracts/base/Ownable.sol index 2a74c3717..2a74c3717 100644 --- a/packages/contracts/deploy/test/fixtures/contracts/base/Ownable.sol +++ b/packages/deployer/test/fixtures/contracts/base/Ownable.sol diff --git a/packages/contracts/deploy/test/fixtures/contracts/base/SafeMath.sol b/packages/deployer/test/fixtures/contracts/base/SafeMath.sol index 7414684a8..7414684a8 100644 --- a/packages/contracts/deploy/test/fixtures/contracts/base/SafeMath.sol +++ b/packages/deployer/test/fixtures/contracts/base/SafeMath.sol diff --git a/packages/contracts/deploy/test/fixtures/contracts/base/Token.sol b/packages/deployer/test/fixtures/contracts/base/Token.sol index c03f8c567..c03f8c567 100644 --- a/packages/contracts/deploy/test/fixtures/contracts/base/Token.sol +++ b/packages/deployer/test/fixtures/contracts/base/Token.sol diff --git a/packages/deployer/test/fixtures/exchange_bin.ts b/packages/deployer/test/fixtures/exchange_bin.ts new file mode 100644 index 000000000..a6eae515e --- /dev/null +++ b/packages/deployer/test/fixtures/exchange_bin.ts @@ -0,0 +1,4 @@ +export const constructor_args = + '0x000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f4980000000000000000000000008da0d80f5007ef1e431dd2127178d224e32c2ef4'; +export const exchange_binary = + '0x6060604052341561000f57600080fd5b604051604080612c4d833981016040528080519060200190919080519060200190919050505b816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b50505b612b84806100c96000396000f300606060405236156100fa576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806314df96ee146100ff578063288cdc911461014c5780632ac1262214610187578063363349be146101c2578063394c21e7146103bc5780633b30ba591461044b5780634f150787146104a0578063741bcc93146106b25780637e9abb50146107535780638163681e1461078e57806398024a8b14610812578063add1cbc51461085b578063b7b2c7d6146108b0578063baa0181d14610acd578063bc61394a14610c1f578063cfc4d0ec14610cdf578063f06bbf7514610d6d578063ffa1ad7414610d9e575b600080fd5b341561010a57600080fd5b6101326004808035906020019091908035906020019091908035906020019091905050610e2d565b604051808215151515815260200191505060405180910390f35b341561015757600080fd5b610171600480803560001916906020019091905050610e7c565b6040518082815260200191505060405180910390f35b341561019257600080fd5b6101ac600480803560001916906020019091905050610e94565b6040518082815260200191505060405180910390f35b34156101cd57600080fd5b6103a660048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b8282101561024857848483905060a002016005806020026040519081016040528092919082600560200280828437820191505050505081526020019060010190610203565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156102c457848483905060c00201600680602002604051908101604052809291908260066020028082843782019150505050508152602001906001019061027f565b5050505050919080359060200190919080351515906020019091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050610eac565b6040518082815260200191505060405180910390f35b34156103c757600080fd5b6104356004808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091908060c001906006806020026040519081016040528092919082600660200280828437820191505050505091908035906020019091905050611013565b6040518082815260200191505060405180910390f35b341561045657600080fd5b61045e6114fb565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156104ab57600080fd5b6106b060048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b8282101561052657848483905060a0020160058060200260405190810160405280929190826005602002808284378201915050505050815260200190600101906104e1565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156105a257848483905060c00201600680602002604051908101604052809291908260066020028082843782019150505050508152602001906001019061055d565b50505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091905050611520565b005b34156106bd57600080fd5b6107516004808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091908060c00190600680602002604051908101604052809291908260066020028082843782019150505050509190803590602001909190803560ff1690602001909190803560001916906020019091908035600019169060200190919050506115df565b005b341561075e57600080fd5b610778600480803560001916906020019091905050611605565b6040518082815260200191505060405180910390f35b341561079957600080fd5b6107f8600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080356000191690602001909190803560ff16906020019091908035600019169060200190919080356000191690602001909190505061164f565b604051808215151515815260200191505060405180910390f35b341561081d57600080fd5b6108456004808035906020019091908035906020019091908035906020019091905050611757565b6040518082815260200191505060405180910390f35b341561086657600080fd5b61086e611776565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156108bb57600080fd5b610acb60048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b8282101561093657848483905060a0020160058060200260405190810160405280929190826005602002808284378201915050505050815260200190600101906108f1565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b828210156109b257848483905060c00201600680602002604051908101604052809291908260066020028082843782019150505050508152602001906001019061096d565b50505050509190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091908035151590602001909190803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843782019150505050505091908035906020019082018035906020019080806020026020016040519081016040528093929190818152602001838360200280828437820191505050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190505061179c565b005b3415610ad857600080fd5b610c1d60048080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610b5357848483905060a002016005806020026040519081016040528092919082600560200280828437820191505050505081526020019060010190610b0e565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020016000905b82821015610bcf57848483905060c002016006806020026040519081016040528092919082600660200280828437820191505050505081526020019060010190610b8a565b5050505050919080359060200190820180359060200190808060200260200160405190810160405280939291908181526020018383602002808284378201915050505050509190505061185e565b005b3415610c2a57600080fd5b610cc96004808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091908060c001906006806020026040519081016040528092919082600660200280828437820191505050505091908035906020019091908035151590602001909190803560ff1690602001909190803560001916906020019091908035600019169060200190919050506118d3565b6040518082815260200191505060405180910390f35b3415610cea57600080fd5b610d4f6004808060a001906005806020026040519081016040528092919082600560200280828437820191505050505091908060c001906006806020026040519081016040528092919082600660200280828437820191505050505091905050612073565b60405180826000191660001916815260200191505060405180910390f35b3415610d7857600080fd5b610d8061231f565b604051808261ffff1661ffff16815260200191505060405180910390f35b3415610da957600080fd5b610db1612325565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610df25780820151818401525b602081019050610dd6565b50505050905090810190601f168015610e1f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60008060008486850991506000821415610e4a5760009250610e73565b610e69610e5a83620f424061235e565b610e64888761235e565b612392565b90506103e8811192505b50509392505050565b60026020528060005260406000206000915090505481565b60036020528060005260406000206000915090505481565b6000806000809150600090505b895181101561100257896000815181101515610ed157fe5b906020019060200201516003600581101515610ee957fe5b602002015173ffffffffffffffffffffffffffffffffffffffff168a82815181101515610f1257fe5b906020019060200201516003600581101515610f2a57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16141515610f5157600080fd5b610fe582610fe08c84815181101515610f6657fe5b906020019060200201518c85815181101515610f7e57fe5b90602001906020020151610f928d886123ae565b8c8c88815181101515610fa157fe5b906020019060200201518c89815181101515610fb957fe5b906020019060200201518c8a815181101515610fd157fe5b906020019060200201516118d3565b6123c8565b915087821415610ff457611002565b5b8080600101915050610eb9565b8192505b5050979650505050505050565b600061101d612a8c565b6000806101606040519081016040528088600060058110151561103c57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200188600160058110151561106b57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200188600260058110151561109a57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018860036005811015156110c957fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018860046005811015156110f857fe5b602002015173ffffffffffffffffffffffffffffffffffffffff16815260200187600060068110151561112757fe5b6020020151815260200187600160068110151561114057fe5b6020020151815260200187600260068110151561115957fe5b6020020151815260200187600360068110151561117257fe5b6020020151815260200187600460068110151561118b57fe5b6020020151815260200161119f8989612073565b6000191681525092503373ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff161415156111e657600080fd5b60008360a001511180156111fe575060008360c00151115b801561120a5750600085115b151561121557600080fd5b8261012001514210151561127257826101400151600019166000600381111561123a57fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a3600093506114f1565b61128d8360c00151611288856101400151611605565b6123ae565b915061129985836123e7565b905060008114156112f35782610140015160001916600160038111156112bb57fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a3600093506114f1565b61131d600360008561014001516000191660001916815260200190815260200160002054826123c8565b60036000856101400151600019166000191681526020019081526020016000208190555082604001518360600151604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140192505050604051809103902060001916836080015173ffffffffffffffffffffffffffffffffffffffff16846000015173ffffffffffffffffffffffffffffffffffffffff167f67d66f160bc93d925d05dae1794c90d2d6d6688b29b84ff069398a9b0458713186604001518760600151611455878a60c001518b60a00151611757565b878a6101400151604051808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200184815260200183815260200182600019166000191681526020019550505050505060405180910390a48093505b5050509392505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008090505b86518110156115d5576115c7878281518110151561154057fe5b90602001906020020151878381518110151561155857fe5b90602001906020020151878481518110151561157057fe5b90602001906020020151878581518110151561158857fe5b9060200190602002015187868151811015156115a057fe5b9060200190602002015187878151811015156115b857fe5b906020019060200201516115df565b5b8080600101915050611526565b5b50505050505050565b836115f087878760008888886118d3565b1415156115fc57600080fd5b5b505050505050565b600061164760026000846000191660001916815260200190815260200160002054600360008560001916600019168152602001908152602001600020546123c8565b90505b919050565b600060018560405180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c0182600019166000191681526020019150506040518091039020858585604051600081526020016040526000604051602001526040518085600019166000191681526020018460ff1660ff16815260200183600019166000191681526020018260001916600019168152602001945050505050602060405160208103908084039060008661646e5a03f1151561171457600080fd5b50506020604051035173ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161490505b95945050505050565b600061176c611766858461235e565b84612392565b90505b9392505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008090505b87518110156118535761184488828151811015156117bc57fe5b9060200190602002015188838151811015156117d457fe5b9060200190602002015188848151811015156117ec57fe5b9060200190602002015188888681518110151561180557fe5b90602001906020020151888781518110151561181d57fe5b90602001906020020151888881518110151561183557fe5b906020019060200201516118d3565b505b80806001019150506117a2565b5b5050505050505050565b60008090505b83518110156118cc576118bd848281518110151561187e57fe5b90602001906020020151848381518110151561189657fe5b9060200190602002015184848151811015156118ae57fe5b90602001906020020151611013565b505b8080600101915050611864565b5b50505050565b60006118dd612a8c565b600080600080610160604051908101604052808e60006005811015156118ff57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e600160058110151561192e57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e600260058110151561195d57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e600360058110151561198c57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018e60046005811015156119bb57fe5b602002015173ffffffffffffffffffffffffffffffffffffffff1681526020018d60006006811015156119ea57fe5b602002015181526020018d6001600681101515611a0357fe5b602002015181526020018d6002600681101515611a1c57fe5b602002015181526020018d6003600681101515611a3557fe5b602002015181526020018d6004600681101515611a4e57fe5b60200201518152602001611a628f8f612073565b600019168152509450600073ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff161480611ad957503373ffffffffffffffffffffffffffffffffffffffff16856020015173ffffffffffffffffffffffffffffffffffffffff16145b1515611ae457600080fd5b60008560a00151118015611afc575060008560c00151115b8015611b08575060008b115b1515611b1357600080fd5b611b2985600001518661014001518b8b8b61164f565b1515611b3457600080fd5b84610120015142101515611b91578461014001516000191660006003811115611b5957fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612063565b611bac8560c00151611ba7876101400151611605565b6123ae565b9350611bb88b856123e7565b95506000861415611c12578461014001516000191660016003811115611bda57fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612063565b611c25868660c001518760a00151610e2d565b15611c79578461014001516000191660026003811115611c4157fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612063565b89158015611c8e5750611c8c8587612401565b155b15611ce15784610140015160001916600380811115611ca957fe5b60ff167f36d86c59e00bd73dc19ba3adfe068e4b64ac7e92be35546adeddf1b956a87e9060405160405180910390a360009550612063565b611cf4868660c001518760a00151611757565b9250611d20600260008761014001516000191660001916815260200190815260200160002054876123c8565b600260008761014001516000191660001916815260200190815260200160002081905550611d58856040015186600001513386612751565b1515611d6357600080fd5b611d77856060015133876000015189612751565b1515611d8257600080fd5b600073ffffffffffffffffffffffffffffffffffffffff16856080015173ffffffffffffffffffffffffffffffffffffffff16141515611e815760008560e001511115611e1f57611ddc868660c001518760e00151611757565b9150611e136000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168660000151876080015185612751565b1515611e1e57600080fd5b5b60008561010001511115611e8057611e41868660c00151876101000151611757565b9050611e746000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1633876080015184612751565b1515611e7f57600080fd5b5b5b84604001518560600151604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140192505050604051809103902060001916856080015173ffffffffffffffffffffffffffffffffffffffff16866000015173ffffffffffffffffffffffffffffffffffffffff167f0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb33389604001518a60600151898d8a8a8f6101400151604051808973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200186815260200185815260200184815260200183815260200182600019166000191681526020019850505050505050505060405180910390a48595505b5050505050979650505050505050565b60003083600060058110151561208557fe5b602002015184600160058110151561209957fe5b60200201518560026005811015156120ad57fe5b60200201518660036005811015156120c157fe5b60200201518760046005811015156120d557fe5b60200201518760006006811015156120e957fe5b60200201518860016006811015156120fd57fe5b602002015189600260068110151561211157fe5b60200201518a600360068110151561212557fe5b60200201518b600460068110151561213957fe5b60200201518c600560068110151561214d57fe5b6020020151604051808d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018781526020018681526020018581526020018481526020018381526020018281526020019c50505050505050505050505050604051809103902090505b92915050565b61138781565b6040805190810160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b6000808284029050600084148061237f575082848281151561237c57fe5b04145b151561238757fe5b8091505b5092915050565b60008082848115156123a057fe5b0490508091505b5092915050565b60008282111515156123bc57fe5b81830390505b92915050565b60008082840190508381101515156123dc57fe5b8091505b5092915050565b60008183106123f657816123f8565b825b90505b92915050565b60008060008060008060008060003397506124258a8c60c001518d60a00151611757565b9650600073ffffffffffffffffffffffffffffffffffffffff168b6080015173ffffffffffffffffffffffffffffffffffffffff161415156126d2576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168b6040015173ffffffffffffffffffffffffffffffffffffffff161495506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168b6060015173ffffffffffffffffffffffffffffffffffffffff161494506125208a8c60c001518d60e00151611757565b93506125368a8c60c001518d6101000151611757565b925085612543578361254e565b61254d87856123c8565b5b91508461255b5782612566565b6125658a846123c8565b5b9050816125986000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168d600001516128ae565b10806125d15750816125cf6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168d60000151612972565b105b806126055750806126036000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168a6128ae565b105b806126395750806126376000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168a612972565b105b156126475760009850612743565b851580156126805750866126638c604001518d600001516128ae565b108061267f57508661267d8c604001518d60000151612972565b105b5b1561268e5760009850612743565b841580156126bf5750896126a68c606001518a6128ae565b10806126be5750896126bc8c606001518a612972565b105b5b156126cd5760009850612743565b61273e565b866126e58c604001518d600001516128ae565b10806127015750866126ff8c604001518d60000151612972565b105b806127185750896127168c606001518a6128ae565b105b8061272f57508961272d8c606001518a612972565b105b1561273d5760009850612743565b5b600198505b505050505050505092915050565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166315dacbea868686866000604051602001526040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001945050505050602060405180830381600087803b151561288857600080fd5b6102c65a03f1151561289957600080fd5b5050506040518051905090505b949350505050565b60008273ffffffffffffffffffffffffffffffffffffffff166370a0823161138761ffff16846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600088803b151561295157600080fd5b87f1151561295e57600080fd5b505050506040518051905090505b92915050565b60008273ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e61138761ffff1684600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200192505050602060405180830381600088803b1515612a6b57600080fd5b87f11515612a7857600080fd5b505050506040518051905090505b92915050565b61016060405190810160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000801916815250905600a165627a7a72305820df5cabdc3a116e993e10bfb14823d18d9b798038d4c463a1703f9a584c456b7e0029'; diff --git a/packages/contracts/deploy/test/util/constants.ts b/packages/deployer/test/util/constants.ts index a2de44b63..d52076607 100644 --- a/packages/contracts/deploy/test/util/constants.ts +++ b/packages/deployer/test/util/constants.ts @@ -1,11 +1,11 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; export const constants = { networkId: 0, jsonrpcPort: 8545, optimizerEnabled: 0, gasPrice: new BigNumber(20000000000), - timeoutMs: 12000, + timeoutMs: 20000, zrxTokenAddress: '0xe41d2489571d322189246dafa5ebde1f4699f498', tokenTransferProxyAddress: '0x8da0d80f5007ef1e431dd2127178d224e32c2ef4', }; diff --git a/packages/deployer/tsconfig.json b/packages/deployer/tsconfig.json new file mode 100644 index 000000000..4e1edb510 --- /dev/null +++ b/packages/deployer/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig", + "compilerOptions": { + "outDir": "lib", + "strictFunctionTypes": false, + "strictNullChecks": false + }, + "include": [ + "./src/**/*", + "./test/**/*", + "../../node_modules/types-bn/index.d.ts", + "../../node_modules/types-ethereumjs-util/index.d.ts", + "../../node_modules/chai-typescript-typings/index.d.ts", + "../../node_modules/web3-typescript-typings/index.d.ts" + ] +} diff --git a/packages/dev-utils/README.md b/packages/dev-utils/README.md new file mode 100644 index 000000000..5a8e71f2f --- /dev/null +++ b/packages/dev-utils/README.md @@ -0,0 +1,9 @@ +## Dev utils + +Dev utils to be shared across 0x projects and packages + +## Install + +```bash +yarn add @0xproject/dev-utils +``` diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json new file mode 100644 index 000000000..1cd54f15f --- /dev/null +++ b/packages/dev-utils/package.json @@ -0,0 +1,37 @@ +{ + "name": "@0xproject/dev-utils", + "version": "0.0.6", + "description": "0x dev TS utils", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "scripts": { + "build": "tsc", + "clean": "shx rm -rf lib", + "lint": "tslint --project . 'src/**/*.ts'" + }, + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/0xProject/0x.js.git" + }, + "bugs": { + "url": "https://github.com/0xProject/0x.js/issues" + }, + "homepage": "https://github.com/0xProject/0x.js/packages/dev-utils/README.md", + "devDependencies": { + "@0xproject/tslint-config": "^0.4.3", + "@types/lodash": "^4.14.86", + "npm-run-all": "^4.1.2", + "shx": "^0.2.2", + "tslint": "5.8.0", + "types-bn": "^0.0.1", + "types-ethereumjs-util": "0xProject/types-ethereumjs-util", + "typescript": "~2.6.1" + }, + "dependencies": { + "@0xproject/utils": "^0.2.1", + "ethereumjs-util": "^5.1.2", + "lodash": "^4.17.4", + "request-promise-native": "^1.0.5" + } +} diff --git a/packages/dev-utils/scripts/postpublish.js b/packages/dev-utils/scripts/postpublish.js new file mode 100644 index 000000000..16d67e03f --- /dev/null +++ b/packages/dev-utils/scripts/postpublish.js @@ -0,0 +1,15 @@ +const postpublish_utils = require('../../../scripts/postpublish_utils'); +const packageJSON = require('../package.json'); + +const subPackageName = packageJSON.name; + +postpublish_utils + .getLatestTagAndVersionAsync(subPackageName) + .then(function(result) { + const releaseName = postpublish_utils.getReleaseName(subPackageName, result.version); + const assets = []; + return postpublish_utils.publishReleaseNotes(result.tag, releaseName, assets); + }) + .catch(function(err) { + throw err; + }); diff --git a/packages/dev-utils/src/blockchain_lifecycle.ts b/packages/dev-utils/src/blockchain_lifecycle.ts new file mode 100644 index 000000000..18f5d5c61 --- /dev/null +++ b/packages/dev-utils/src/blockchain_lifecycle.ts @@ -0,0 +1,23 @@ +import { RPC } from './rpc'; + +export class BlockchainLifecycle { + private _rpc: RPC; + private _snapshotIdsStack: number[]; + constructor(url: string) { + this._rpc = new RPC(url); + 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`); + } + } +} diff --git a/packages/dev-utils/src/index.ts b/packages/dev-utils/src/index.ts new file mode 100644 index 000000000..9ba0cb5cf --- /dev/null +++ b/packages/dev-utils/src/index.ts @@ -0,0 +1,2 @@ +export { RPC } from './rpc'; +export { BlockchainLifecycle } from './blockchain_lifecycle'; diff --git a/packages/0x.js/test/utils/rpc.ts b/packages/dev-utils/src/rpc.ts index 309a96d5e..36f8b1ef9 100644 --- a/packages/0x.js/test/utils/rpc.ts +++ b/packages/dev-utils/src/rpc.ts @@ -1,51 +1,53 @@ 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; + private _url: string; + private _id: number; + constructor(url: string) { + this._url = url; + 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 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); + const payload = this._toPayload(method, params); + const didRevert = await this._sendAsync(payload); return didRevert; } + public async increaseTimeAsync(time: number) { + const method = 'evm_increaseTime'; + const params = [time]; + const payload = this._toPayload(method, params); + return this._sendAsync(payload); + } public async mineBlockAsync(): Promise<void> { const method = 'evm_mine'; const params: any[] = []; - const payload = this.toPayload(method, params); - await this.sendAsync(payload); + const payload = this._toPayload(method, params); + await this._sendAsync(payload); } - private toPayload(method: string, params: any[] = []): string { + private _toPayload(method: string, params: any[] = []): string { const payload = JSON.stringify({ - id: this.id, + id: this._id, method, params, }); - this.id += 1; + this._id += 1; return payload; } - private async sendAsync(payload: string): Promise<any> { + private async _sendAsync(payload: string): Promise<any> { const opts = { method: 'POST', - uri: `http://${this.host}:${this.port}`, + uri: this._url, body: payload, headers: { 'content-type': 'application/json', diff --git a/packages/dev-utils/tsconfig.json b/packages/dev-utils/tsconfig.json new file mode 100644 index 000000000..b28e45170 --- /dev/null +++ b/packages/dev-utils/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig", + "compilerOptions": { + "outDir": "lib" + }, + "include": [ + "./src/**/*", + "../../node_modules/types-bn/index.d.ts", + "../../node_modules/types-ethereumjs-util/index.d.ts" + ] +} diff --git a/packages/dev-utils/tslint.json b/packages/dev-utils/tslint.json new file mode 100644 index 000000000..ffaefe83a --- /dev/null +++ b/packages/dev-utils/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": ["@0xproject/tslint-config"] +} diff --git a/packages/json-schemas/CHANGELOG.md b/packages/json-schemas/CHANGELOG.md index 9f080adeb..28f38acc5 100644 --- a/packages/json-schemas/CHANGELOG.md +++ b/packages/json-schemas/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG -v0.6.7 - _Nov. 14, 2017_ ------------------------- +## v0.7.0 - _December 20, 2017_ + + * Rename `subscriptionOptsSchema` to `blockRangeSchema` (#272) + +## v0.6.7 - _November 14, 2017_ + * Re-publish JSON-schema previously published under NPM package 0x-json-schemas diff --git a/packages/json-schemas/README.md b/packages/json-schemas/README.md index d89f57a5e..9166f50c1 100644 --- a/packages/json-schemas/README.md +++ b/packages/json-schemas/README.md @@ -1,16 +1,16 @@ -json-schemas ------------- +## @0xproject/json-schemas Contains 0x-related json schemas -## Install: +## Installation ```bash -npm install @0xproject/json-schemas --save +yarn add @0xproject/json-schemas ``` -## Usage: -``` +## Usage + +```javascript import {SchemaValidator, ValidatorResult, schemas} from '@0xproject/json-schemas'; const {orderSchema} = schemas; @@ -22,3 +22,41 @@ const order = { const validatorResult: ValidatorResult = validator.validate(order, orderSchema); // Contains all errors const isValid: boolean = validator.isValid(order, orderSchema); // Only returns boolean ``` + +## Contributing + +We strongly encourage that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. + +Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. + +### Install Dependencies + +If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: + +```bash +yarn config set workspaces-experimental true +``` + +Then install dependencies + +```bash +yarn install +``` + +### Build + +```bash +yarn build +``` + +### Lint + +```bash +yarn lint +``` + +### Run Tests + +```bash +yarn test +``` diff --git a/packages/json-schemas/package.json b/packages/json-schemas/package.json index 52deb2254..4b500eab3 100644 --- a/packages/json-schemas/package.json +++ b/packages/json-schemas/package.json @@ -1,46 +1,45 @@ { - "name": "@0xproject/json-schemas", - "version": "0.6.9", - "description": "0x-related json schemas", - "main": "lib/src/index.js", - "types": "lib/src/index.d.ts", - "scripts": { - "lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'", - "test": "run-s clean build run_mocha", - "test:circleci": "yarn test", - "run_mocha": "mocha lib/test/**/*_test.js", - "clean": "shx rm -rf _bundles lib test_temp", - "build": "tsc" - }, - "repository": { - "type": "git", - "url": "https://github.com/0xProject/0x.js.git" - }, - "author": "", - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/0xProject/0x.js/issues" - }, - "homepage": "https://github.com/0xProject/0x.js/packages/json-schemas/README.md", - "dependencies": { - "jsonschema": "^1.2.0", - "lodash.values": "^4.3.0" - }, - "devDependencies": { - "@0xproject/tslint-config": "^0.2.0", - "@0xproject/utils": "^0.0.1", - "@types/lodash.foreach": "^4.5.3", - "@types/lodash.values": "^4.3.3", - "@types/mocha": "^2.2.42", - "bignumber.js": "~4.1.0", - "chai": "^4.0.1", - "chai-typescript-typings": "^0.0.1", - "dirty-chai": "^2.0.1", - "lodash.foreach": "^4.5.0", - "mocha": "^4.0.1", - "npm-run-all": "^4.1.2", - "shx": "^0.2.2", - "tslint": "5.8.0", - "typescript": "~2.6.1" - } + "name": "@0xproject/json-schemas", + "version": "0.7.4", + "description": "0x-related json schemas", + "main": "lib/src/index.js", + "types": "lib/src/index.d.ts", + "scripts": { + "lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'", + "test": "run-s clean build run_mocha", + "test:circleci": "yarn test", + "run_mocha": "mocha lib/test/**/*_test.js", + "clean": "shx rm -rf _bundles lib test_temp", + "build": "tsc" + }, + "repository": { + "type": "git", + "url": "https://github.com/0xProject/0x.js.git" + }, + "author": "", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/0xProject/0x.js/issues" + }, + "homepage": "https://github.com/0xProject/0x.js/packages/json-schemas/README.md", + "dependencies": { + "jsonschema": "^1.2.0", + "lodash.values": "^4.3.0" + }, + "devDependencies": { + "@0xproject/tslint-config": "^0.4.3", + "@0xproject/utils": "^0.2.1", + "@types/lodash.foreach": "^4.5.3", + "@types/lodash.values": "^4.3.3", + "@types/mocha": "^2.2.42", + "chai": "^4.0.1", + "chai-typescript-typings": "^0.0.2", + "dirty-chai": "^2.0.1", + "lodash.foreach": "^4.5.0", + "mocha": "^4.0.1", + "npm-run-all": "^4.1.2", + "shx": "^0.2.2", + "tslint": "5.8.0", + "typescript": "~2.6.1" + } } diff --git a/packages/json-schemas/schemas/subscription_opts_schema.ts b/packages/json-schemas/schemas/block_range_schema.ts index a476e6963..1f6a63151 100644 --- a/packages/json-schemas/schemas/subscription_opts_schema.ts +++ b/packages/json-schemas/schemas/block_range_schema.ts @@ -10,11 +10,11 @@ export const blockParamSchema = { ], }; -export const subscriptionOptsSchema = { - id: '/SubscriptionOpts', +export const blockRangeSchema = { + id: '/BlockRange', properties: { - fromBlock: {$ref: '/BlockParam'}, - toBlock: {$ref: '/BlockParam'}, + fromBlock: { $ref: '/BlockParam' }, + toBlock: { $ref: '/BlockParam' }, }, type: 'object', }; diff --git a/packages/json-schemas/schemas/ec_signature_schema.ts b/packages/json-schemas/schemas/ec_signature_schema.ts index 2b769f3b6..71b840dd8 100644 --- a/packages/json-schemas/schemas/ec_signature_schema.ts +++ b/packages/json-schemas/schemas/ec_signature_schema.ts @@ -12,8 +12,8 @@ export const ecSignatureSchema = { minimum: 27, maximum: 28, }, - r: {$ref: '/ECSignatureParameter'}, - s: {$ref: '/ECSignatureParameter'}, + r: { $ref: '/ECSignatureParameter' }, + s: { $ref: '/ECSignatureParameter' }, }, required: ['v', 'r', 's'], type: 'object', diff --git a/packages/json-schemas/schemas/index_filter_values_schema.ts b/packages/json-schemas/schemas/index_filter_values_schema.ts index f7e323e45..3374d63e0 100644 --- a/packages/json-schemas/schemas/index_filter_values_schema.ts +++ b/packages/json-schemas/schemas/index_filter_values_schema.ts @@ -1,11 +1,7 @@ export const indexFilterValuesSchema = { id: '/IndexFilterValues', additionalProperties: { - oneOf: [ - {$ref: '/Number'}, - {$ref: '/Address'}, - {$ref: '/OrderHashSchema'}, - ], + oneOf: [{ $ref: '/Number' }, { $ref: '/Address' }, { $ref: '/OrderHashSchema' }], }, type: 'object', }; diff --git a/packages/json-schemas/schemas/order_cancel_schema.ts b/packages/json-schemas/schemas/order_cancel_schema.ts index ac7d2ee20..ad23d01cc 100644 --- a/packages/json-schemas/schemas/order_cancel_schema.ts +++ b/packages/json-schemas/schemas/order_cancel_schema.ts @@ -3,8 +3,8 @@ export const orderCancellationRequestsSchema = { type: 'array', items: { properties: { - order: {$ref: '/Order'}, - takerTokenCancelAmount: {$ref: '/Number'}, + order: { $ref: '/Order' }, + takerTokenCancelAmount: { $ref: '/Number' }, }, required: ['order', 'takerTokenCancelAmount'], type: 'object', diff --git a/packages/json-schemas/schemas/order_fill_or_kill_requests_schema.ts b/packages/json-schemas/schemas/order_fill_or_kill_requests_schema.ts index 4ef7b069a..61f2c8849 100644 --- a/packages/json-schemas/schemas/order_fill_or_kill_requests_schema.ts +++ b/packages/json-schemas/schemas/order_fill_or_kill_requests_schema.ts @@ -3,8 +3,8 @@ export const orderFillOrKillRequestsSchema = { type: 'array', items: { properties: { - signedOrder: {$ref: '/SignedOrder'}, - fillTakerAmount: {$ref: '/Number'}, + signedOrder: { $ref: '/SignedOrder' }, + fillTakerAmount: { $ref: '/Number' }, }, required: ['signedOrder', 'fillTakerAmount'], type: 'object', diff --git a/packages/json-schemas/schemas/order_fill_requests_schema.ts b/packages/json-schemas/schemas/order_fill_requests_schema.ts index ec19dd9f8..419d0670f 100644 --- a/packages/json-schemas/schemas/order_fill_requests_schema.ts +++ b/packages/json-schemas/schemas/order_fill_requests_schema.ts @@ -3,8 +3,8 @@ export const orderFillRequestsSchema = { type: 'array', items: { properties: { - signedOrder: {$ref: '/SignedOrder'}, - takerTokenFillAmount: {$ref: '/Number'}, + signedOrder: { $ref: '/SignedOrder' }, + takerTokenFillAmount: { $ref: '/Number' }, }, required: ['signedOrder', 'takerTokenFillAmount'], type: 'object', diff --git a/packages/json-schemas/schemas/order_schemas.ts b/packages/json-schemas/schemas/order_schemas.ts index 3cce49351..6f17224ad 100644 --- a/packages/json-schemas/schemas/order_schemas.ts +++ b/packages/json-schemas/schemas/order_schemas.ts @@ -1,22 +1,30 @@ export const orderSchema = { id: '/Order', properties: { - maker: {$ref: '/Address'}, - taker: {$ref: '/Address'}, - makerFee: {$ref: '/Number'}, - takerFee: {$ref: '/Number'}, - makerTokenAmount: {$ref: '/Number'}, - takerTokenAmount: {$ref: '/Number'}, - makerTokenAddress: {$ref: '/Address'}, - takerTokenAddress: {$ref: '/Address'}, - salt: {$ref: '/Number'}, - feeRecipient: {$ref: '/Address'}, - expirationUnixTimestampSec: {$ref: '/Number'}, - exchangeContractAddress: {$ref: '/Address'}, + maker: { $ref: '/Address' }, + taker: { $ref: '/Address' }, + makerFee: { $ref: '/Number' }, + takerFee: { $ref: '/Number' }, + makerTokenAmount: { $ref: '/Number' }, + takerTokenAmount: { $ref: '/Number' }, + makerTokenAddress: { $ref: '/Address' }, + takerTokenAddress: { $ref: '/Address' }, + salt: { $ref: '/Number' }, + feeRecipient: { $ref: '/Address' }, + expirationUnixTimestampSec: { $ref: '/Number' }, + exchangeContractAddress: { $ref: '/Address' }, }, required: [ - 'maker', 'taker', 'makerFee', 'takerFee', 'makerTokenAmount', 'takerTokenAmount', - 'salt', 'feeRecipient', 'expirationUnixTimestampSec', 'exchangeContractAddress', + 'maker', + 'taker', + 'makerFee', + 'takerFee', + 'makerTokenAmount', + 'takerTokenAmount', + 'salt', + 'feeRecipient', + 'expirationUnixTimestampSec', + 'exchangeContractAddress', ], type: 'object', }; @@ -27,7 +35,7 @@ export const signedOrderSchema = { { $ref: '/Order' }, { properties: { - ecSignature: {$ref: '/ECSignature'}, + ecSignature: { $ref: '/ECSignature' }, }, required: ['ecSignature'], }, diff --git a/packages/json-schemas/schemas/relayer_api_error_response_schema.ts b/packages/json-schemas/schemas/relayer_api_error_response_schema.ts index eacbb2bce..27fdb166f 100644 --- a/packages/json-schemas/schemas/relayer_api_error_response_schema.ts +++ b/packages/json-schemas/schemas/relayer_api_error_response_schema.ts @@ -2,16 +2,16 @@ export const relayerApiErrorResponseSchema = { id: '/RelayerApiErrorResponse', type: 'object', properties: { - code: {type: 'number'}, - reason: {type: 'string'}, + code: { type: 'number' }, + reason: { type: 'string' }, validationErrors: { type: 'array', items: { type: 'object', properties: { - field: {type: 'string'}, - code: {type: 'number'}, - reason: {type: 'string'}, + field: { type: 'string' }, + code: { type: 'number' }, + reason: { type: 'string' }, }, required: ['field', 'code', 'reason'], }, diff --git a/packages/json-schemas/schemas/relayer_api_fees_payload_schema.ts b/packages/json-schemas/schemas/relayer_api_fees_payload_schema.ts index 645660844..eaaf777a1 100644 --- a/packages/json-schemas/schemas/relayer_api_fees_payload_schema.ts +++ b/packages/json-schemas/schemas/relayer_api_fees_payload_schema.ts @@ -2,18 +2,23 @@ export const relayerApiFeesPayloadSchema = { id: '/RelayerApiFeesPayload', type: 'object', properties: { - exchangeContractAddress: {$ref: '/Address'}, - maker: {$ref: '/Address'}, - taker: {$ref: '/Address'}, - makerTokenAddress: {$ref: '/Address'}, - takerTokenAddress: {$ref: '/Address'}, - makerTokenAmount: {$ref: '/Number'}, - takerTokenAmount: {$ref: '/Number'}, - expirationUnixTimestampSec: {$ref: '/Number'}, - salt: {$ref: '/Number'}, + exchangeContractAddress: { $ref: '/Address' }, + maker: { $ref: '/Address' }, + taker: { $ref: '/Address' }, + makerTokenAddress: { $ref: '/Address' }, + takerTokenAddress: { $ref: '/Address' }, + makerTokenAmount: { $ref: '/Number' }, + takerTokenAmount: { $ref: '/Number' }, + expirationUnixTimestampSec: { $ref: '/Number' }, + salt: { $ref: '/Number' }, }, required: [ - 'exchangeContractAddress', 'maker', 'taker', 'makerTokenAddress', 'takerTokenAddress', - 'expirationUnixTimestampSec', 'salt', + 'exchangeContractAddress', + 'maker', + 'taker', + 'makerTokenAddress', + 'takerTokenAddress', + 'expirationUnixTimestampSec', + 'salt', ], }; diff --git a/packages/json-schemas/schemas/relayer_api_fees_response_schema.ts b/packages/json-schemas/schemas/relayer_api_fees_response_schema.ts index 86e51feb0..e7440613f 100644 --- a/packages/json-schemas/schemas/relayer_api_fees_response_schema.ts +++ b/packages/json-schemas/schemas/relayer_api_fees_response_schema.ts @@ -2,9 +2,9 @@ export const relayerApiFeesResponseSchema = { id: '/RelayerApiFeesResponse', type: 'object', properties: { - makerFee: {$ref: '/Number'}, - takerFee: {$ref: '/Number'}, - feeRecipient: {$ref: '/Address'}, + makerFee: { $ref: '/Number' }, + takerFee: { $ref: '/Number' }, + feeRecipient: { $ref: '/Address' }, }, required: ['makerFee', 'takerFee', 'feeRecipient'], }; diff --git a/packages/json-schemas/schemas/relayer_api_orberbook_channel_subscribe_schema.ts b/packages/json-schemas/schemas/relayer_api_orberbook_channel_subscribe_schema.ts index 2f71531c6..d93fa73d6 100644 --- a/packages/json-schemas/schemas/relayer_api_orberbook_channel_subscribe_schema.ts +++ b/packages/json-schemas/schemas/relayer_api_orberbook_channel_subscribe_schema.ts @@ -2,10 +2,10 @@ export const relayerApiOrderbookChannelSubscribeSchema = { id: '/RelayerApiOrderbookChannelSubscribe', type: 'object', properties: { - type: {enum: ['subscribe']}, - channel: {enum: ['orderbook']}, - requestId: {type: 'number'}, - payload: {$ref: '/RelayerApiOrderbookChannelSubscribePayload'}, + type: { enum: ['subscribe'] }, + channel: { enum: ['orderbook'] }, + requestId: { type: 'number' }, + payload: { $ref: '/RelayerApiOrderbookChannelSubscribePayload' }, }, required: ['type', 'channel', 'requestId', 'payload'], }; @@ -14,10 +14,10 @@ export const relayerApiOrderbookChannelSubscribePayload = { id: '/RelayerApiOrderbookChannelSubscribePayload', type: 'object', properties: { - baseTokenAddress: {$ref: '/Address'}, - quoteTokenAddress: {$ref: '/Address'}, - snapshot: {type: 'boolean'}, - limit: {type: 'number'}, + baseTokenAddress: { $ref: '/Address' }, + quoteTokenAddress: { $ref: '/Address' }, + snapshot: { type: 'boolean' }, + limit: { type: 'number' }, }, required: ['baseTokenAddress', 'quoteTokenAddress'], }; diff --git a/packages/json-schemas/schemas/relayer_api_orderbook_channel_snapshot_schema.ts b/packages/json-schemas/schemas/relayer_api_orderbook_channel_snapshot_schema.ts index 99037865e..fe1510d5b 100644 --- a/packages/json-schemas/schemas/relayer_api_orderbook_channel_snapshot_schema.ts +++ b/packages/json-schemas/schemas/relayer_api_orderbook_channel_snapshot_schema.ts @@ -2,10 +2,10 @@ export const relayerApiOrderbookChannelSnapshotSchema = { id: '/RelayerApiOrderbookChannelSnapshot', type: 'object', properties: { - type: {enum: ['snapshot']}, - channel: {enum: ['orderbook']}, - requestId: {type: 'number'}, - payload: {$ref: '/RelayerApiOrderbookChannelSnapshotPayload'}, + type: { enum: ['snapshot'] }, + channel: { enum: ['orderbook'] }, + requestId: { type: 'number' }, + payload: { $ref: '/RelayerApiOrderbookChannelSnapshotPayload' }, }, required: ['type', 'channel', 'requestId', 'payload'], }; @@ -14,8 +14,8 @@ export const relayerApiOrderbookChannelSnapshotPayload = { id: '/RelayerApiOrderbookChannelSnapshotPayload', type: 'object', properties: { - bids: {$ref: '/signedOrdersSchema'}, - asks: {$ref: '/signedOrdersSchema'}, + bids: { $ref: '/signedOrdersSchema' }, + asks: { $ref: '/signedOrdersSchema' }, }, required: ['bids', 'asks'], }; diff --git a/packages/json-schemas/schemas/relayer_api_orderbook_channel_update_response_schema.ts b/packages/json-schemas/schemas/relayer_api_orderbook_channel_update_response_schema.ts index 90cfd8749..9a6d83d4c 100644 --- a/packages/json-schemas/schemas/relayer_api_orderbook_channel_update_response_schema.ts +++ b/packages/json-schemas/schemas/relayer_api_orderbook_channel_update_response_schema.ts @@ -2,10 +2,10 @@ export const relayerApiOrderbookChannelUpdateSchema = { id: '/RelayerApiOrderbookChannelUpdate', type: 'object', properties: { - type: {enum: ['update']}, - channel: {enum: ['orderbook']}, - requestId: {type: 'number'}, - payload: {$ref: '/SignedOrder'}, + type: { enum: ['update'] }, + channel: { enum: ['orderbook'] }, + requestId: { type: 'number' }, + payload: { $ref: '/SignedOrder' }, }, required: ['type', 'channel', 'requestId', 'payload'], }; diff --git a/packages/json-schemas/schemas/relayer_api_orderbook_response_schema.ts b/packages/json-schemas/schemas/relayer_api_orderbook_response_schema.ts index b592d4f8e..5c409c807 100644 --- a/packages/json-schemas/schemas/relayer_api_orderbook_response_schema.ts +++ b/packages/json-schemas/schemas/relayer_api_orderbook_response_schema.ts @@ -2,8 +2,8 @@ export const relayerApiOrderBookResponseSchema = { id: '/RelayerApiOrderBookResponse', type: 'object', properties: { - bids: {$ref: '/signedOrdersSchema'}, - asks: {$ref: '/signedOrdersSchema'}, + bids: { $ref: '/signedOrdersSchema' }, + asks: { $ref: '/signedOrdersSchema' }, }, required: ['bids', 'asks'], }; diff --git a/packages/json-schemas/schemas/relayer_api_token_pairs_response_schema.ts b/packages/json-schemas/schemas/relayer_api_token_pairs_response_schema.ts index 8ecab1424..5009c7955 100644 --- a/packages/json-schemas/schemas/relayer_api_token_pairs_response_schema.ts +++ b/packages/json-schemas/schemas/relayer_api_token_pairs_response_schema.ts @@ -3,8 +3,8 @@ export const relayerApiTokenPairsResponseSchema = { type: 'array', items: { properties: { - tokenA: {$ref: '/RelayerApiTokenTradeInfo'}, - tokenB: {$ref: '/RelayerApiTokenTradeInfo'}, + tokenA: { $ref: '/RelayerApiTokenTradeInfo' }, + tokenB: { $ref: '/RelayerApiTokenTradeInfo' }, }, required: ['tokenA', 'tokenB'], type: 'object', @@ -15,10 +15,10 @@ export const relayerApiTokenTradeInfoSchema = { id: '/RelayerApiTokenTradeInfo', type: 'object', properties: { - address: {$ref: '/Address'}, - minAmount: {$ref: '/Number'}, - maxAmount: {$ref: '/Number'}, - precision: {type: 'number'}, + address: { $ref: '/Address' }, + minAmount: { $ref: '/Number' }, + maxAmount: { $ref: '/Number' }, + precision: { type: 'number' }, }, required: ['address'], }; diff --git a/packages/json-schemas/schemas/signed_orders_schema.ts b/packages/json-schemas/schemas/signed_orders_schema.ts index c4c4a68ac..34d956836 100644 --- a/packages/json-schemas/schemas/signed_orders_schema.ts +++ b/packages/json-schemas/schemas/signed_orders_schema.ts @@ -1,5 +1,5 @@ export const signedOrdersSchema = { id: '/signedOrdersSchema', type: 'array', - items: {$ref: '/SignedOrder'}, + items: { $ref: '/SignedOrder' }, }; diff --git a/packages/json-schemas/schemas/token_schema.ts b/packages/json-schemas/schemas/token_schema.ts index aca4d4ad2..e64565c8b 100644 --- a/packages/json-schemas/schemas/token_schema.ts +++ b/packages/json-schemas/schemas/token_schema.ts @@ -1,10 +1,10 @@ export const tokenSchema = { id: '/Token', properties: { - name: {type: 'string'}, - symbol: {type: 'string'}, - decimals: {type: 'number'}, - address: {$ref: '/Address'}, + name: { type: 'string' }, + symbol: { type: 'string' }, + decimals: { type: 'number' }, + address: { $ref: '/Address' }, }, required: ['name', 'symbol', 'decimals', 'address'], type: 'object', diff --git a/packages/json-schemas/schemas/tx_data_schema.ts b/packages/json-schemas/schemas/tx_data_schema.ts index 41eaadd3c..4274c553f 100644 --- a/packages/json-schemas/schemas/tx_data_schema.ts +++ b/packages/json-schemas/schemas/tx_data_schema.ts @@ -7,25 +7,16 @@ export const jsNumber = { export const txDataSchema = { id: '/TxData', properties: { - from: {$ref: '/Address'}, - to: {$ref: '/Address'}, + from: { $ref: '/Address' }, + to: { $ref: '/Address' }, value: { - oneOf: [ - {$ref: '/Number'}, - {$ref: '/JsNumber'}, - ], + oneOf: [{ $ref: '/Number' }, { $ref: '/JsNumber' }], }, gas: { - oneOf: [ - {$ref: '/Number'}, - {$ref: '/JsNumber'}, - ], + oneOf: [{ $ref: '/Number' }, { $ref: '/JsNumber' }], }, gasPrice: { - oneOf: [ - {$ref: '/Number'}, - {$ref: '/JsNumber'}, - ], + oneOf: [{ $ref: '/Number' }, { $ref: '/JsNumber' }], }, data: { type: 'string', diff --git a/packages/json-schemas/scripts/postpublish.js b/packages/json-schemas/scripts/postpublish.js index 7fa452b08..16d67e03f 100644 --- a/packages/json-schemas/scripts/postpublish.js +++ b/packages/json-schemas/scripts/postpublish.js @@ -3,12 +3,13 @@ const packageJSON = require('../package.json'); const subPackageName = packageJSON.name; -postpublish_utils.getLatestTagAndVersionAsync(subPackageName) +postpublish_utils + .getLatestTagAndVersionAsync(subPackageName) .then(function(result) { const releaseName = postpublish_utils.getReleaseName(subPackageName, result.version); const assets = []; return postpublish_utils.publishReleaseNotes(result.tag, releaseName, assets); }) - .catch (function(err) { + .catch(function(err) { throw err; }); diff --git a/packages/json-schemas/src/index.ts b/packages/json-schemas/src/index.ts index b7cae277e..9d8470348 100644 --- a/packages/json-schemas/src/index.ts +++ b/packages/json-schemas/src/index.ts @@ -1,4 +1,4 @@ -export {ValidatorResult, Schema} from 'jsonschema'; +export { ValidatorResult, Schema } from 'jsonschema'; -export {SchemaValidator} from './schema_validator'; -export {schemas} from './schemas'; +export { SchemaValidator } from './schema_validator'; +export { schemas } from './schemas'; diff --git a/packages/json-schemas/src/schema_validator.ts b/packages/json-schemas/src/schema_validator.ts index c91f49340..e13326d2a 100644 --- a/packages/json-schemas/src/schema_validator.ts +++ b/packages/json-schemas/src/schema_validator.ts @@ -1,18 +1,18 @@ -import {Schema, Validator, ValidatorResult} from 'jsonschema'; +import { Schema, Validator, ValidatorResult } from 'jsonschema'; import values = require('lodash.values'); -import {schemas} from './schemas'; +import { schemas } from './schemas'; export class SchemaValidator { - private validator: Validator; + private _validator: Validator; constructor() { - this.validator = new Validator(); + this._validator = new Validator(); for (const schema of values(schemas)) { - this.validator.addSchema(schema, schema.id); + this._validator.addSchema(schema, schema.id); } } public addSchema(schema: Schema) { - this.validator.addSchema(schema, schema.id); + this._validator.addSchema(schema, schema.id); } // In order to validate a complex JS object using jsonschema, we must replace any complex // sub-types (e.g BigNumber) with a simpler string representation. Since BigNumber and other @@ -20,7 +20,7 @@ export class SchemaValidator { // then parse it. The resultant object can then be checked using jsonschema. public validate(instance: any, schema: Schema): ValidatorResult { const jsonSchemaCompatibleObject = JSON.parse(JSON.stringify(instance)); - return this.validator.validate(jsonSchemaCompatibleObject, schema); + return this._validator.validate(jsonSchemaCompatibleObject, schema); } public isValid(instance: any, schema: Schema): boolean { const isValid = this.validate(instance, schema).errors.length === 0; diff --git a/packages/json-schemas/src/schemas.ts b/packages/json-schemas/src/schemas.ts index 69164cbc7..5cb07acfe 100644 --- a/packages/json-schemas/src/schemas.ts +++ b/packages/json-schemas/src/schemas.ts @@ -1,39 +1,15 @@ -import { - addressSchema, - numberSchema, -} from '../schemas/basic_type_schemas'; -import { - ecSignatureParameterSchema, - ecSignatureSchema, -} from '../schemas/ec_signature_schema'; -import { - indexFilterValuesSchema, -} from '../schemas/index_filter_values_schema'; -import { - orderCancellationRequestsSchema, -} from '../schemas/order_cancel_schema'; -import { - orderFillOrKillRequestsSchema, -} from '../schemas/order_fill_or_kill_requests_schema'; -import { - orderFillRequestsSchema, -} from '../schemas/order_fill_requests_schema'; -import { - orderHashSchema, -} from '../schemas/order_hash_schema'; -import { - orderSchema, - signedOrderSchema, -} from '../schemas/order_schemas'; -import { - relayerApiErrorResponseSchema, -} from '../schemas/relayer_api_error_response_schema'; -import { - relayerApiFeesPayloadSchema, -} from '../schemas/relayer_api_fees_payload_schema'; -import { - relayerApiFeesResponseSchema, -} from '../schemas/relayer_api_fees_response_schema'; +import { addressSchema, numberSchema } from '../schemas/basic_type_schemas'; +import { blockParamSchema, blockRangeSchema } from '../schemas/block_range_schema'; +import { ecSignatureParameterSchema, ecSignatureSchema } from '../schemas/ec_signature_schema'; +import { indexFilterValuesSchema } from '../schemas/index_filter_values_schema'; +import { orderCancellationRequestsSchema } from '../schemas/order_cancel_schema'; +import { orderFillOrKillRequestsSchema } from '../schemas/order_fill_or_kill_requests_schema'; +import { orderFillRequestsSchema } from '../schemas/order_fill_requests_schema'; +import { orderHashSchema } from '../schemas/order_hash_schema'; +import { orderSchema, signedOrderSchema } from '../schemas/order_schemas'; +import { relayerApiErrorResponseSchema } from '../schemas/relayer_api_error_response_schema'; +import { relayerApiFeesPayloadSchema } from '../schemas/relayer_api_fees_payload_schema'; +import { relayerApiFeesResponseSchema } from '../schemas/relayer_api_fees_response_schema'; import { relayerApiOrderbookChannelSubscribePayload, relayerApiOrderbookChannelSubscribeSchema, @@ -42,30 +18,15 @@ import { relayerApiOrderbookChannelSnapshotPayload, relayerApiOrderbookChannelSnapshotSchema, } from '../schemas/relayer_api_orderbook_channel_snapshot_schema'; -import { - relayerApiOrderbookChannelUpdateSchema, -} from '../schemas/relayer_api_orderbook_channel_update_response_schema'; -import { - relayerApiOrderBookResponseSchema, -} from '../schemas/relayer_api_orderbook_response_schema'; +import { relayerApiOrderbookChannelUpdateSchema } from '../schemas/relayer_api_orderbook_channel_update_response_schema'; +import { relayerApiOrderBookResponseSchema } from '../schemas/relayer_api_orderbook_response_schema'; import { relayerApiTokenPairsResponseSchema, relayerApiTokenTradeInfoSchema, } from '../schemas/relayer_api_token_pairs_response_schema'; -import { - signedOrdersSchema, -} from '../schemas/signed_orders_schema'; -import { - blockParamSchema, - subscriptionOptsSchema, -} from '../schemas/subscription_opts_schema'; -import { - tokenSchema, -} from '../schemas/token_schema'; -import { - jsNumber, - txDataSchema, -} from '../schemas/tx_data_schema'; +import { signedOrdersSchema } from '../schemas/signed_orders_schema'; +import { tokenSchema } from '../schemas/token_schema'; +import { jsNumber, txDataSchema } from '../schemas/tx_data_schema'; export const schemas = { numberSchema, @@ -81,7 +42,7 @@ export const schemas = { signedOrderSchema, signedOrdersSchema, blockParamSchema, - subscriptionOptsSchema, + blockRangeSchema, tokenSchema, jsNumber, txDataSchema, diff --git a/packages/json-schemas/test/schema_test.ts b/packages/json-schemas/test/schema_test.ts index 8a2f9407d..7b058781d 100644 --- a/packages/json-schemas/test/schema_test.ts +++ b/packages/json-schemas/test/schema_test.ts @@ -1,11 +1,10 @@ -import {promisify} from '@0xproject/utils'; -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import * as dirtyChai from 'dirty-chai'; import forEach = require('lodash.foreach'); import 'mocha'; -import {schemas, SchemaValidator} from '../src/index'; +import { schemas, SchemaValidator } from '../src/index'; chai.config.includeStack = true; chai.use(dirtyChai); @@ -16,7 +15,6 @@ const { addressSchema, ecSignatureSchema, ecSignatureParameterSchema, - indexFilterValuesSchema, orderCancellationRequestsSchema, orderFillOrKillRequestsSchema, orderFillRequestsSchema, @@ -25,7 +23,7 @@ const { signedOrderSchema, signedOrdersSchema, blockParamSchema, - subscriptionOptsSchema, + blockRangeSchema, tokenSchema, jsNumber, txDataSchema, @@ -96,9 +94,9 @@ describe('Schema', () => { }); it('should fail for invalid parameters', () => { const testCases = [ - '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc3', // shorter + '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc3', // shorter '0xzzzz9190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254', // invalid characters - '40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254', // no 0x + '40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254', // no 0x ]; const shouldFail = true; validateAgainstSchema(testCases, ecSignatureParameterSchema, shouldFail); @@ -124,11 +122,7 @@ describe('Schema', () => { const v = 27; const r = '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33'; const s = '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254'; - const testCases = [ - {}, - {v}, - {r, s, v: 31}, - ]; + const testCases = [{}, { v }, { r, s, v: 31 }]; const shouldFail = true; validateAgainstSchema(testCases, ecSignatureSchema, shouldFail); }); @@ -154,39 +148,24 @@ describe('Schema', () => { }); describe('#blockParamSchema', () => { it('should validate valid block param', () => { - const testCases = [ - 42, - 'latest', - 'pending', - 'earliest', - ]; + const testCases = [42, 'latest', 'pending', 'earliest']; validateAgainstSchema(testCases, blockParamSchema); }); it('should fail for invalid block param', () => { - const testCases = [ - {}, - '42', - 'pemding', - ]; + const testCases = [{}, '42', 'pemding']; const shouldFail = true; validateAgainstSchema(testCases, blockParamSchema, shouldFail); }); }); - describe('#subscriptionOptsSchema', () => { + describe('#blockRangeSchema', () => { it('should validate valid subscription opts', () => { - const testCases = [ - {fromBlock: 42, toBlock: 'latest'}, - {fromBlock: 42}, - {}, - ]; - validateAgainstSchema(testCases, subscriptionOptsSchema); + const testCases = [{ fromBlock: 42, toBlock: 'latest' }, { fromBlock: 42 }, {}]; + validateAgainstSchema(testCases, blockRangeSchema); }); it('should fail for invalid subscription opts', () => { - const testCases = [ - {fromBlock: '42'}, - ]; + const testCases = [{ fromBlock: '42' }]; const shouldFail = true; - validateAgainstSchema(testCases, subscriptionOptsSchema, shouldFail); + validateAgainstSchema(testCases, blockRangeSchema, shouldFail); }); }); describe('#tokenSchema', () => { @@ -198,9 +177,7 @@ describe('Schema', () => { url: 'https://0xproject.com', }; it('should validate valid token', () => { - const testCases = [ - token, - ]; + const testCases = [token]; validateAgainstSchema(testCases, tokenSchema); }); it('should fail for invalid token', () => { @@ -237,9 +214,7 @@ describe('Schema', () => { }; describe('#orderSchema', () => { it('should validate valid order', () => { - const testCases = [ - order, - ]; + const testCases = [order]; validateAgainstSchema(testCases, orderSchema); }); it('should fail for invalid order', () => { @@ -269,28 +244,18 @@ describe('Schema', () => { }; describe('#signedOrdersSchema', () => { it('should validate valid signed orders', () => { - const testCases = [ - [signedOrder], - [], - ]; + const testCases = [[signedOrder], []]; validateAgainstSchema(testCases, signedOrdersSchema); }); it('should fail for invalid signed orders', () => { - const testCases = [ - [ - signedOrder, - 1, - ], - ]; + const testCases = [[signedOrder, 1]]; const shouldFail = true; validateAgainstSchema(testCases, signedOrdersSchema, shouldFail); }); }); describe('#signedOrderSchema', () => { it('should validate valid signed order', () => { - const testCases = [ - signedOrder, - ]; + const testCases = [signedOrder]; validateAgainstSchema(testCases, signedOrderSchema); }); it('should fail for invalid signed order', () => { @@ -312,9 +277,7 @@ describe('Schema', () => { }, ]; it('should validate valid order fill or kill requests', () => { - const testCases = [ - orderFillOrKillRequests, - ]; + const testCases = [orderFillOrKillRequests]; validateAgainstSchema(testCases, orderFillOrKillRequestsSchema); }); it('should fail for invalid order fill or kill requests', () => { @@ -338,9 +301,7 @@ describe('Schema', () => { }, ]; it('should validate valid order cancellation requests', () => { - const testCases = [ - orderCancellationRequests, - ]; + const testCases = [orderCancellationRequests]; validateAgainstSchema(testCases, orderCancellationRequestsSchema); }); it('should fail for invalid order cancellation requests', () => { @@ -364,9 +325,7 @@ describe('Schema', () => { }, ]; it('should validate valid order fill requests', () => { - const testCases = [ - orderFillRequests, - ]; + const testCases = [orderFillRequests]; validateAgainstSchema(testCases, orderFillRequestsSchema); }); it('should fail for invalid order fill requests', () => { @@ -561,12 +520,8 @@ describe('Schema', () => { channel: 'orderbook', requestId: 2, payload: { - bids: [ - signedOrder, - ], - asks: [ - signedOrder, - ], + bids: [signedOrder], + asks: [signedOrder], }, }, ]; @@ -579,12 +534,8 @@ describe('Schema', () => { channel: 'orderbook', requestId: 2, payload: { - bids: [ - signedOrder, - ], - asks: [ - signedOrder, - ], + bids: [signedOrder], + asks: [signedOrder], }, }, { @@ -592,24 +543,16 @@ describe('Schema', () => { channel: 'bar', requestId: 2, payload: { - bids: [ - signedOrder, - ], - asks: [ - signedOrder, - ], + bids: [signedOrder], + asks: [signedOrder], }, }, { type: 'snapshot', channel: 'orderbook', payload: { - bids: [ - signedOrder, - ], - asks: [ - signedOrder, - ], + bids: [signedOrder], + asks: [signedOrder], }, }, { @@ -617,12 +560,8 @@ describe('Schema', () => { channel: 'orderbook', requestId: '2', payload: { - bids: [ - signedOrder, - ], - asks: [ - signedOrder, - ], + bids: [signedOrder], + asks: [signedOrder], }, }, { @@ -630,9 +569,7 @@ describe('Schema', () => { channel: 'orderbook', requestId: 2, payload: { - bids: [ - signedOrder, - ], + bids: [signedOrder], }, }, { @@ -640,9 +577,7 @@ describe('Schema', () => { channel: 'orderbook', requestId: 2, payload: { - asks: [ - signedOrder, - ], + asks: [signedOrder], }, }, { @@ -650,12 +585,8 @@ describe('Schema', () => { channel: 'orderbook', requestId: 2, payload: { - bids: [ - signedOrder, - ], - asks: [ - {}, - ], + bids: [signedOrder], + asks: [{}], }, }, { @@ -663,12 +594,8 @@ describe('Schema', () => { channel: 'orderbook', requestId: 2, payload: { - bids: [ - {}, - ], - asks: [ - signedOrder, - ], + bids: [{}], + asks: [signedOrder], }, }, ]; @@ -943,18 +870,11 @@ describe('Schema', () => { }); describe('#jsNumberSchema', () => { it('should validate valid js number', () => { - const testCases = [ - 1, - 42, - ]; + const testCases = [1, 42]; validateAgainstSchema(testCases, jsNumber); }); it('should fail for invalid js number', () => { - const testCases = [ - NaN, - -1, - new BigNumber(1), - ]; + const testCases = [NaN, -1, new BigNumber(1)]; const shouldFail = true; validateAgainstSchema(testCases, jsNumber, shouldFail); }); diff --git a/packages/json-schemas/tsconfig.json b/packages/json-schemas/tsconfig.json index 40c2f0c8c..88a467ccb 100644 --- a/packages/json-schemas/tsconfig.json +++ b/packages/json-schemas/tsconfig.json @@ -1,17 +1,7 @@ { - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "lib": [ "es2017", "dom"], - "outDir": "lib", - "sourceMap": true, - "declaration": true, - "noImplicitAny": true, - "strictNullChecks": true - }, - "include": [ - "./src/**/*", - "./test/**/*", - "../../node_modules/chai-typescript-typings/index.d.ts" - ] + "extends": "../../tsconfig", + "compilerOptions": { + "outDir": "lib" + }, + "include": ["./src/**/*", "./test/**/*", "../../node_modules/chai-typescript-typings/index.d.ts"] } diff --git a/packages/json-schemas/tslint.json b/packages/json-schemas/tslint.json index a07795151..ffaefe83a 100644 --- a/packages/json-schemas/tslint.json +++ b/packages/json-schemas/tslint.json @@ -1,5 +1,3 @@ { - "extends": [ - "@0xproject/tslint-config" - ] + "extends": ["@0xproject/tslint-config"] } diff --git a/packages/kovan-faucets/Dockerfile b/packages/kovan-faucets/Dockerfile new file mode 100644 index 000000000..6d6ddc192 --- /dev/null +++ b/packages/kovan-faucets/Dockerfile @@ -0,0 +1,13 @@ +FROM node + +WORKDIR /src + +COPY package.json . +RUN npm i +RUN npm install forever -g + +COPY . . + +EXPOSE 3000 + +CMD ["forever", "./bin/server.js"] diff --git a/packages/kovan-faucets/README.md b/packages/kovan-faucets/README.md new file mode 100644 index 000000000..07bd23575 --- /dev/null +++ b/packages/kovan-faucets/README.md @@ -0,0 +1,78 @@ +## @0xproject/kovan_faucets + +This faucet dispenses 0.1 test ether to one recipient per second and 0.1 test ZRX every 5 seconds. It has a max queue size of 1000. + +## Installation + +This is a private package and therefore is not published to npm. In order to build and run this package locally, see the [Install Dependencies](#Install-Dependencies) section and onwards below. + +## Contributing + +We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. + +Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. + +### Install Dependencies + +If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: + +```bash +yarn config set workspaces-experimental true +``` + +Then install dependencies + +```bash +yarn install +``` + +### Start + +Set the following environment variables: + +```bash +export FAUCET_ENVIRONMENT=development +export DISPENSER_ADDRESS=0x5409ed021d9299bf6814279a6a1411a7e866a631 +export DISPENSER_PRIVATE_KEY=f2f48ee19680706196e2e339e5da3491186e0c4c5030670656b0e0164837257d +export FAUCET_ROLLBAR_ACCESS_KEY={GET_THIS_FROM_ROLLBAR_ACCOUNT_SETTINGS} +export INFURA_API_KEY={GET_THIS_FROM_INFURA} +``` + +Infura API Key can be requested here: https://infura.io/register.html + +Note: The above public/private keys exist when running `testrpc` with the following option `--mnemonic concert load couple harbor equip island argue ramp clarify fence smart topic`. + +```bash +yarn dev +``` + +### Endpoints + +`GET /ether/:recipient` + +Where recipient_address is a hex encoded Ethereum address prefixed with `0x`. + +`GET /zrx/:recipient` + +Where recipient_address is a hex encoded Ethereum address prefixed with `0x`. + +### Docker configs + +``` +docker run -d \ +-p 80:3000 \ +--name kovan-faucets \ +--log-opt max-size=100m \ +--log-opt max-file=20 \ +-e DISPENSER_ADDRESS=$DISPENSER_ADDRESS \ +-e DISPENSER_PRIVATE_KEY=$DISPENSER_PRIVATE_KEY \ +-e FAUCET_ROLLBAR_ACCESS_KEY=$FAUCET_ROLLBAR_ACCESS_KEY \ +-e FAUCET_ENVIRONMENT=production \ +kovan-faucets +``` + +### Lint + +```bash +yarn lint +``` diff --git a/packages/kovan-faucets/gulpfile.js b/packages/kovan-faucets/gulpfile.js new file mode 100644 index 000000000..773faf33a --- /dev/null +++ b/packages/kovan-faucets/gulpfile.js @@ -0,0 +1,92 @@ +const gulp = require('gulp'); +const nodemon = require('nodemon'); +const path = require('path'); +const webpack = require('webpack'); +const fs = require('fs'); +const nodeExternals = require('webpack-node-externals'); + +const config = { + target: 'node', + entry: [path.join(__dirname, '/src/ts/server.ts')], + output: { + path: path.join(__dirname, '/bin'), + filename: 'server.js', + }, + devtool: 'source-map', + resolve: { + modules: [ + path.join(__dirname, '/src/ts'), + 'node_modules', + ], + extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'], + alias: { + ts: path.join(__dirname, '/src/ts'), + contract_artifacts: path.join(__dirname, '/src/contract_artifacts'), + }, + }, + module: { + rules: [ + { + test: /\.js$/, + loader: 'source-map-loader', + }, + { + test: /\.tsx?$/, + loader: 'awesome-typescript-loader', + }, + ], + }, + plugins: [ + new webpack.BannerPlugin({ + banner: 'require("source-map-support").install();', + raw: true, + entryOnly: false, + }), + ], + externals: nodeExternals({ + modulesDir: path.join(__dirname, '../../node_modules') + }), + watchOptions: { + ignored: /bin|node_modules|transpiled/ + }, +}; + +gulp.task('build', function(done) { + webpack(config).run(onBuild(done)); +}); + +gulp.task('watch', function() { + webpack(config).watch(100, function(err, stats) { + onBuild()(err, stats); + nodemon.restart(); + }); +}); + +gulp.task('run', ['watch'], function() { + nodemon({ + execMap: { + js: 'node', + }, + script: path.join(__dirname, 'bin/server'), + ignore: ['*'], + watch: ['foo/'], + ext: 'noop', + }).on('restart', function() { + console.log('Restarted!'); + }); +}); + +function onBuild(done) { + return function(err, stats) { + if(err) { + console.log('Error', err); + } + else { + console.log(stats.toString()); + } + + if(done) { + done(); + } + } +} diff --git a/packages/kovan-faucets/package.json b/packages/kovan-faucets/package.json new file mode 100644 index 000000000..7dc6b0512 --- /dev/null +++ b/packages/kovan-faucets/package.json @@ -0,0 +1,43 @@ +{ + "private": true, + "name": "@0xproject/kovan_faucets", + "version": "1.0.6", + "description": "A faucet micro-service that dispenses test ERC20 tokens or Ether", + "main": "server.js", + "scripts": { + "build": "node ../../node_modules/gulp/bin/gulp.js build", + "dev": "node ../../node_modules/gulp/bin/gulp.js run", + "start": "node ./bin/server.js", + "lint": "tslint --project . 'src/**/*.ts'", + "clean": "shx rm -rf bin" + }, + "author": "Fabio Berger", + "license": "Apache-2.0", + "dependencies": { + "0x.js": "^0.30.1", + "@0xproject/utils": "^0.2.1", + "body-parser": "^1.17.1", + "ethereumjs-tx": "^1.3.3", + "express": "^4.15.2", + "lodash": "^4.17.4", + "rollbar": "^0.6.5", + "web3": "^0.20.0", + "web3-provider-engine": "^13.0.1" + }, + "devDependencies": { + "@0xproject/tslint-config": "^0.4.3", + "@types/body-parser": "^1.16.1", + "@types/express": "^4.0.35", + "@types/lodash": "^4.14.86", + "awesome-typescript-loader": "^3.1.3", + "gulp": "^3.9.1", + "nodemon": "^1.11.0", + "shx": "^0.2.2", + "source-map-loader": "^0.1.6", + "tslint": "5.8.0", + "typescript": "~2.6.1", + "web3-typescript-typings": "^0.9.5", + "webpack": "^3.1.0", + "webpack-node-externals": "^1.6.0" + } +} diff --git a/packages/kovan-faucets/scripts/postpublish.js b/packages/kovan-faucets/scripts/postpublish.js new file mode 100644 index 000000000..16d67e03f --- /dev/null +++ b/packages/kovan-faucets/scripts/postpublish.js @@ -0,0 +1,15 @@ +const postpublish_utils = require('../../../scripts/postpublish_utils'); +const packageJSON = require('../package.json'); + +const subPackageName = packageJSON.name; + +postpublish_utils + .getLatestTagAndVersionAsync(subPackageName) + .then(function(result) { + const releaseName = postpublish_utils.getReleaseName(subPackageName, result.version); + const assets = []; + return postpublish_utils.publishReleaseNotes(result.tag, releaseName, assets); + }) + .catch(function(err) { + throw err; + }); diff --git a/packages/kovan-faucets/src/ts/configs.ts b/packages/kovan-faucets/src/ts/configs.ts new file mode 100644 index 000000000..2e5a7f64d --- /dev/null +++ b/packages/kovan-faucets/src/ts/configs.ts @@ -0,0 +1,12 @@ +export const configs = { + DISPENSER_ADDRESS: (process.env.DISPENSER_ADDRESS as string).toLowerCase(), + DISPENSER_PRIVATE_KEY: process.env.DISPENSER_PRIVATE_KEY, + ENVIRONMENT: process.env.FAUCET_ENVIRONMENT, + ROLLBAR_ACCESS_KEY: process.env.FAUCET_ROLLBAR_ACCESS_KEY, + RPC_URL: + process.env.FAUCET_ENVIRONMENT === 'development' + ? 'http://127.0.0.1:8545' + : `https://kovan.infura.io/${process.env.INFURA_API_KEY}`, + ZRX_TOKEN_ADDRESS: '0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570', + KOVAN_NETWORK_ID: 42, +}; diff --git a/packages/kovan-faucets/src/ts/error_reporter.ts b/packages/kovan-faucets/src/ts/error_reporter.ts new file mode 100644 index 000000000..6865d3893 --- /dev/null +++ b/packages/kovan-faucets/src/ts/error_reporter.ts @@ -0,0 +1,40 @@ +import * as express from 'express'; +import rollbar = require('rollbar'); + +import { configs } from './configs'; +import { utils } from './utils'; + +export const errorReporter = { + setup() { + rollbar.init(configs.ROLLBAR_ACCESS_KEY, { + environment: configs.ENVIRONMENT, + }); + + rollbar.handleUncaughtExceptions(configs.ROLLBAR_ACCESS_KEY); + + process.on('unhandledRejection', async (err: Error) => { + utils.consoleLog(`Uncaught exception ${err}. Stack: ${err.stack}`); + await this.reportAsync(err); + process.exit(1); + }); + }, + async reportAsync(err: Error, req?: express.Request): Promise<any> { + if (configs.ENVIRONMENT === 'development') { + return; // Do not log development environment errors + } + + return new Promise((resolve, reject) => { + rollbar.handleError(err, req, (rollbarErr: Error) => { + if (rollbarErr) { + utils.consoleLog(`Error reporting to rollbar, ignoring: ${rollbarErr}`); + reject(rollbarErr); + } else { + resolve(); + } + }); + }); + }, + errorHandler() { + return rollbar.errorHandler(configs.ROLLBAR_ACCESS_KEY); + }, +}; diff --git a/packages/kovan-faucets/src/ts/ether_request_queue.ts b/packages/kovan-faucets/src/ts/ether_request_queue.ts new file mode 100644 index 000000000..1c4b19ab9 --- /dev/null +++ b/packages/kovan-faucets/src/ts/ether_request_queue.ts @@ -0,0 +1,27 @@ +import { promisify } from '@0xproject/utils'; +import * as _ from 'lodash'; + +import { configs } from './configs'; +import { errorReporter } from './error_reporter'; +import { RequestQueue } from './request_queue'; +import { utils } from './utils'; + +const DISPENSE_AMOUNT_ETHER = 0.1; + +export class EtherRequestQueue extends RequestQueue { + protected async processNextRequestFireAndForgetAsync(recipientAddress: string) { + utils.consoleLog(`Processing ETH ${recipientAddress}`); + const sendTransactionAsync = promisify(this.web3.eth.sendTransaction); + try { + const txHash = await sendTransactionAsync({ + from: configs.DISPENSER_ADDRESS, + to: recipientAddress, + value: this.web3.toWei(DISPENSE_AMOUNT_ETHER, 'ether'), + }); + utils.consoleLog(`Sent ${DISPENSE_AMOUNT_ETHER} ETH to ${recipientAddress} tx: ${txHash}`); + } catch (err) { + utils.consoleLog(`Unexpected err: ${err} - ${JSON.stringify(err)}`); + await errorReporter.reportAsync(err); + } + } +} diff --git a/packages/kovan-faucets/src/ts/global.d.ts b/packages/kovan-faucets/src/ts/global.d.ts new file mode 100644 index 000000000..97cd35680 --- /dev/null +++ b/packages/kovan-faucets/src/ts/global.d.ts @@ -0,0 +1,26 @@ +declare module 'rollbar'; +declare module 'web3-provider-engine'; +declare module 'web3-provider-engine/subproviders/rpc'; +declare module 'web3-provider-engine/subproviders/nonce-tracker'; +declare module 'web3-provider-engine/subproviders/hooked-wallet'; + +declare module '*.json' { + const json: any; + /* tslint:disable */ + export default json; + /* tslint:enable */ +} + +// Ethereumjs-tx declarations +declare module 'ethereumjs-tx' { + class EthereumTx { + public raw: Buffer[]; + public r: Buffer; + public s: Buffer; + public v: Buffer; + public serialize(): Buffer; + public sign(buffer: Buffer): void; + constructor(txParams: any); + } + export = EthereumTx; +} diff --git a/packages/kovan-faucets/src/ts/handler.ts b/packages/kovan-faucets/src/ts/handler.ts new file mode 100644 index 000000000..4bf776264 --- /dev/null +++ b/packages/kovan-faucets/src/ts/handler.ts @@ -0,0 +1,93 @@ +import * as express from 'express'; +import * as _ from 'lodash'; +import ProviderEngine = require('web3-provider-engine'); +import HookedWalletSubprovider = require('web3-provider-engine/subproviders/hooked-wallet'); +import NonceSubprovider = require('web3-provider-engine/subproviders/nonce-tracker'); +import RpcSubprovider = require('web3-provider-engine/subproviders/rpc'); + +import { configs } from './configs'; +import { EtherRequestQueue } from './ether_request_queue'; +import { idManagement } from './id_management'; +import { utils } from './utils'; +import { ZRXRequestQueue } from './zrx_request_queue'; + +// HACK: web3 leaks XMLHttpRequest into the global scope and causes requests to hang +// because they are using the wrong XHR package. +// Filed issue: https://github.com/ethereum/web3.js/issues/844 +// tslint:disable-next-line:ordered-imports +import * as Web3 from 'web3'; + +export class Handler { + private _etherRequestQueue: EtherRequestQueue; + private _zrxRequestQueue: ZRXRequestQueue; + private _web3: Web3; + constructor() { + // Setup provider engine to talk with RPC node + const providerObj = this._createProviderEngine(configs.RPC_URL); + this._web3 = new Web3(providerObj); + + this._etherRequestQueue = new EtherRequestQueue(this._web3); + this._zrxRequestQueue = new ZRXRequestQueue(this._web3); + } + public dispenseEther(req: express.Request, res: express.Response) { + const recipientAddress = req.params.recipient; + if (_.isUndefined(recipientAddress) || !this._isValidEthereumAddress(recipientAddress)) { + res.status(400).send('INVALID_REQUEST'); + return; + } + const lowerCaseRecipientAddress = recipientAddress.toLowerCase(); + const didAddToQueue = this._etherRequestQueue.add(lowerCaseRecipientAddress); + if (!didAddToQueue) { + res.status(503).send('QUEUE_IS_FULL'); + return; + } + utils.consoleLog(`Added ${lowerCaseRecipientAddress} to the ETH queue`); + res.status(200).end(); + } + public dispenseZRX(req: express.Request, res: express.Response) { + const recipientAddress = req.params.recipient; + if (_.isUndefined(recipientAddress) || !this._isValidEthereumAddress(recipientAddress)) { + res.status(400).send('INVALID_REQUEST'); + return; + } + const lowerCaseRecipientAddress = recipientAddress.toLowerCase(); + const didAddToQueue = this._zrxRequestQueue.add(lowerCaseRecipientAddress); + if (!didAddToQueue) { + res.status(503).send('QUEUE_IS_FULL'); + return; + } + utils.consoleLog(`Added ${lowerCaseRecipientAddress} to the ZRX queue`); + res.status(200).end(); + } + public getQueueInfo(req: express.Request, res: express.Response) { + res.setHeader('Content-Type', 'application/json'); + const payload = JSON.stringify({ + ether: { + full: this._etherRequestQueue.isFull(), + size: this._etherRequestQueue.size(), + }, + zrx: { + full: this._zrxRequestQueue.isFull(), + size: this._zrxRequestQueue.size(), + }, + }); + res.status(200).send(payload); + } + // tslint:disable-next-line:prefer-function-over-method + private _createProviderEngine(rpcUrl: string) { + const engine = new ProviderEngine(); + engine.addProvider(new NonceSubprovider()); + engine.addProvider(new HookedWalletSubprovider(idManagement)); + engine.addProvider( + new RpcSubprovider({ + rpcUrl, + }), + ); + engine.start(); + return engine; + } + private _isValidEthereumAddress(address: string): boolean { + const lowercaseAddress = address.toLowerCase(); + return this._web3.isAddress(lowercaseAddress); + } +} diff --git a/packages/kovan-faucets/src/ts/id_management.ts b/packages/kovan-faucets/src/ts/id_management.ts new file mode 100644 index 000000000..930821172 --- /dev/null +++ b/packages/kovan-faucets/src/ts/id_management.ts @@ -0,0 +1,23 @@ +import EthereumTx = require('ethereumjs-tx'); + +import { configs } from './configs'; +import { utils } from './utils'; + +type Callback = (err: Error | null, accounts: any) => void; + +export const idManagement = { + getAccounts(callback: Callback) { + utils.consoleLog(`configs.DISPENSER_ADDRESS: ${configs.DISPENSER_ADDRESS}`); + callback(null, [configs.DISPENSER_ADDRESS]); + }, + approveTransaction(txData: object, callback: Callback) { + callback(null, true); + }, + signTransaction(txData: object, callback: Callback) { + const tx = new EthereumTx(txData); + const privateKeyBuffer = new Buffer(configs.DISPENSER_PRIVATE_KEY as string, 'hex'); + tx.sign(privateKeyBuffer); + const rawTx = `0x${tx.serialize().toString('hex')}`; + callback(null, rawTx); + }, +}; diff --git a/packages/kovan-faucets/src/ts/request_queue.ts b/packages/kovan-faucets/src/ts/request_queue.ts new file mode 100644 index 000000000..2b42ca4bf --- /dev/null +++ b/packages/kovan-faucets/src/ts/request_queue.ts @@ -0,0 +1,56 @@ +import * as _ from 'lodash'; +import * as timers from 'timers'; + +// HACK: web3 leaks XMLHttpRequest into the global scope and causes requests to hang +// because they are using the wrong XHR package. +// Filed issue: https://github.com/ethereum/web3.js/issues/844 +// tslint:disable-next-line:ordered-imports +import * as Web3 from 'web3'; + +const MAX_QUEUE_SIZE = 500; +const DEFAULT_QUEUE_INTERVAL_MS = 1000; + +export class RequestQueue { + protected queueIntervalMs: number; + protected queue: string[]; + protected queueIntervalId: NodeJS.Timer; + protected web3: Web3; + constructor(web3: any) { + this.queueIntervalMs = DEFAULT_QUEUE_INTERVAL_MS; + this.queue = []; + + this.web3 = web3; + + this.start(); + } + public add(recipientAddress: string): boolean { + if (this.isFull()) { + return false; + } + this.queue.push(recipientAddress); + return true; + } + public size(): number { + return this.queue.length; + } + public isFull(): boolean { + return this.size() >= MAX_QUEUE_SIZE; + } + protected start() { + this.queueIntervalId = timers.setInterval(() => { + const recipientAddress = this.queue.shift(); + if (_.isUndefined(recipientAddress)) { + return; + } + // tslint:disable-next-line:no-floating-promises + this.processNextRequestFireAndForgetAsync(recipientAddress); + }, this.queueIntervalMs); + } + protected stop() { + clearInterval(this.queueIntervalId); + } + // tslint:disable-next-line:prefer-function-over-method + protected async processNextRequestFireAndForgetAsync(recipientAddress: string) { + throw new Error('Expected processNextRequestFireAndForgetAsync to be implemented by a superclass'); + } +} diff --git a/packages/kovan-faucets/src/ts/server.ts b/packages/kovan-faucets/src/ts/server.ts new file mode 100644 index 000000000..23642787d --- /dev/null +++ b/packages/kovan-faucets/src/ts/server.ts @@ -0,0 +1,28 @@ +import * as bodyParser from 'body-parser'; +import * as express from 'express'; + +import { errorReporter } from './error_reporter'; +import { Handler } from './handler'; + +// Setup the errorReporter to catch uncaught exceptions and unhandled rejections +errorReporter.setup(); + +const app = express(); +app.use(bodyParser.json()); // for parsing application/json +app.use((req, res, next) => { + res.header('Access-Control-Allow-Origin', '*'); + res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept'); + next(); +}); + +const handler = new Handler(); +app.get('/ping', (req: express.Request, res: express.Response) => { + res.status(200).send('pong'); +}); +app.get('/ether/:recipient', handler.dispenseEther.bind(handler)); +app.get('/zrx/:recipient', handler.dispenseZRX.bind(handler)); + +// Log to rollbar any errors unhandled by handlers +app.use(errorReporter.errorHandler()); +const port = process.env.PORT || 3000; +app.listen(port); diff --git a/packages/kovan-faucets/src/ts/utils.ts b/packages/kovan-faucets/src/ts/utils.ts new file mode 100644 index 000000000..893f82ca3 --- /dev/null +++ b/packages/kovan-faucets/src/ts/utils.ts @@ -0,0 +1,7 @@ +export const utils = { + consoleLog(message: string) { + /* tslint:disable */ + console.log(message); + /* tslint:enable */ + }, +}; diff --git a/packages/kovan-faucets/src/ts/zrx_request_queue.ts b/packages/kovan-faucets/src/ts/zrx_request_queue.ts new file mode 100644 index 000000000..bbc06f1de --- /dev/null +++ b/packages/kovan-faucets/src/ts/zrx_request_queue.ts @@ -0,0 +1,45 @@ +import { ZeroEx } from '0x.js'; +import { BigNumber } from '@0xproject/utils'; +import * as _ from 'lodash'; + +import { configs } from './configs'; +import { errorReporter } from './error_reporter'; +import { RequestQueue } from './request_queue'; +import { utils } from './utils'; + +// HACK: web3 leaks XMLHttpRequest into the global scope and causes requests to hang +// because they are using the wrong XHR package. +// Filed issue: https://github.com/ethereum/web3.js/issues/844 +// tslint:disable-next-line:ordered-imports +import * as Web3 from 'web3'; + +const DISPENSE_AMOUNT_ZRX = new BigNumber(0.1); +const QUEUE_INTERVAL_MS = 5000; + +export class ZRXRequestQueue extends RequestQueue { + private _zeroEx: ZeroEx; + constructor(web3: Web3) { + super(web3); + this.queueIntervalMs = QUEUE_INTERVAL_MS; + const zeroExConfig = { + networkId: configs.KOVAN_NETWORK_ID, + }; + this._zeroEx = new ZeroEx(web3.currentProvider, zeroExConfig); + } + protected async processNextRequestFireAndForgetAsync(recipientAddress: string) { + utils.consoleLog(`Processing ZRX ${recipientAddress}`); + const baseUnitAmount = ZeroEx.toBaseUnitAmount(DISPENSE_AMOUNT_ZRX, 18); + try { + await this._zeroEx.token.transferAsync( + configs.ZRX_TOKEN_ADDRESS, + configs.DISPENSER_ADDRESS, + recipientAddress, + baseUnitAmount, + ); + utils.consoleLog(`Sent ${DISPENSE_AMOUNT_ZRX} ZRX to ${recipientAddress}`); + } catch (err) { + utils.consoleLog(`Unexpected err: ${err} - ${JSON.stringify(err)}`); + await errorReporter.reportAsync(err); + } + } +} diff --git a/packages/kovan-faucets/tsconfig.json b/packages/kovan-faucets/tsconfig.json new file mode 100644 index 000000000..7f0c084ff --- /dev/null +++ b/packages/kovan-faucets/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig", + "compilerOptions": { + "outDir": "lib" + }, + "include": ["./src/ts/**/*", "../../node_modules/web3-typescript-typings/index.d.ts"] +} diff --git a/packages/kovan-faucets/tslint.json b/packages/kovan-faucets/tslint.json new file mode 100644 index 000000000..ffaefe83a --- /dev/null +++ b/packages/kovan-faucets/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": ["@0xproject/tslint-config"] +} diff --git a/packages/monorepo-scripts/README.md b/packages/monorepo-scripts/README.md new file mode 100644 index 000000000..bed9bd6a6 --- /dev/null +++ b/packages/monorepo-scripts/README.md @@ -0,0 +1,53 @@ +## Mono repo scripts + +This repository contains a few helpful scripts for working with this mono repo. + +## Usage + +#### Dependency versions + +In order to reduce the size of this repo, we try and use the same versions of dependencies between packages. To make it easier to discover version discrepancies between packages, you can run: + +```bash +yarn deps_versions +``` + +This will list out any dependencies that differ in versions between packages. + +## Contributing + +We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. + +Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. + +### Install Dependencies + +If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: + +```bash +yarn config set workspaces-experimental true +``` + +Then install dependencies + +```bash +yarn install +``` + +### Build + +```bash +yarn build +``` + +### Clean + +```bash +yarn clean +``` + +### Lint + +```bash +yarn lint +``` diff --git a/packages/monorepo-scripts/package.json b/packages/monorepo-scripts/package.json index ebd3c60ea..57d0d6f5f 100644 --- a/packages/monorepo-scripts/package.json +++ b/packages/monorepo-scripts/package.json @@ -1,34 +1,34 @@ { - "name": "@0xproject/monorepo-scripts", - "version": "0.0.1", - "private": true, - "description": "Helper scripts for the monorepo", - "scripts": { - "deps_versions": "node ./lib/deps_versions.js", - "lint": "tslint --project . 'src/**/*.ts'", - "clean": "shx rm -rf lib", - "build": "tsc" - }, - "repository": { - "type": "git", - "url": "https://github.com/0xProject/0x.js.git" - }, - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/0xProject/0x.js/issues" - }, - "homepage": "https://github.com/0xProject/0x.js/packages/monorepo-scripts/README.md", - "devDependencies": { - "@0xproject/tslint-config": "^0.2.0", - "@types/glob": "^5.0.33", - "@types/node": "^8.0.53", - "shx": "^0.2.2", - "tslint": "5.8.0", - "typescript": "~2.6.1" - }, - "dependencies": { - "chalk": "^2.3.0", - "glob": "^7.1.2", - "lodash": "^4.17.4" - } + "name": "@0xproject/monorepo-scripts", + "version": "0.1.5", + "private": true, + "description": "Helper scripts for the monorepo", + "scripts": { + "deps_versions": "node ./lib/deps_versions.js", + "lint": "tslint --project . 'src/**/*.ts'", + "clean": "shx rm -rf lib", + "build": "tsc" + }, + "repository": { + "type": "git", + "url": "https://github.com/0xProject/0x.js.git" + }, + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/0xProject/0x.js/issues" + }, + "homepage": "https://github.com/0xProject/0x.js/packages/monorepo-scripts/README.md", + "devDependencies": { + "@0xproject/tslint-config": "^0.4.3", + "@types/glob": "^5.0.33", + "@types/node": "^8.0.53", + "shx": "^0.2.2", + "tslint": "5.8.0", + "typescript": "~2.6.1" + }, + "dependencies": { + "chalk": "^2.3.0", + "glob": "^7.1.2", + "lodash": "^4.17.4" + } } diff --git a/packages/monorepo-scripts/scripts/postpublish.js b/packages/monorepo-scripts/scripts/postpublish.js new file mode 100644 index 000000000..16d67e03f --- /dev/null +++ b/packages/monorepo-scripts/scripts/postpublish.js @@ -0,0 +1,15 @@ +const postpublish_utils = require('../../../scripts/postpublish_utils'); +const packageJSON = require('../package.json'); + +const subPackageName = packageJSON.name; + +postpublish_utils + .getLatestTagAndVersionAsync(subPackageName) + .then(function(result) { + const releaseName = postpublish_utils.getReleaseName(subPackageName, result.version); + const assets = []; + return postpublish_utils.publishReleaseNotes(result.tag, releaseName, assets); + }) + .catch(function(err) { + throw err; + }); diff --git a/packages/monorepo-scripts/src/deps_versions.ts b/packages/monorepo-scripts/src/deps_versions.ts index 84b024427..5c9a2d6ff 100644 --- a/packages/monorepo-scripts/src/deps_versions.ts +++ b/packages/monorepo-scripts/src/deps_versions.ts @@ -2,7 +2,7 @@ import chalk from 'chalk'; import * as fs from 'fs'; -import {sync as globSync} from 'glob'; +import { sync as globSync } from 'glob'; import * as _ from 'lodash'; interface Dependencies { diff --git a/packages/monorepo-scripts/tsconfig.json b/packages/monorepo-scripts/tsconfig.json index a2d90e5dc..c56d255d5 100644 --- a/packages/monorepo-scripts/tsconfig.json +++ b/packages/monorepo-scripts/tsconfig.json @@ -1,13 +1,7 @@ { - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "lib": ["es2015", "dom"], - "outDir": "lib", - "noImplicitAny": true, - "strictNullChecks": true - }, - "include": [ - "./src/**/*" - ] + "extends": "../../tsconfig", + "compilerOptions": { + "outDir": "lib" + }, + "include": ["./src/**/*"] } diff --git a/packages/monorepo-scripts/tslint.json b/packages/monorepo-scripts/tslint.json index a07795151..ffaefe83a 100644 --- a/packages/monorepo-scripts/tslint.json +++ b/packages/monorepo-scripts/tslint.json @@ -1,5 +1,3 @@ { - "extends": [ - "@0xproject/tslint-config" - ] + "extends": ["@0xproject/tslint-config"] } diff --git a/packages/subproviders/CHANGELOG.md b/packages/subproviders/CHANGELOG.md new file mode 100644 index 000000000..0469150c0 --- /dev/null +++ b/packages/subproviders/CHANGELOG.md @@ -0,0 +1,13 @@ +# CHANGELOG + +## v0.4.0 - _January 28, 2017_ + + * Return a transaction hash from `_sendTransactionAsync` (#303) + +## v0.3.0 - _December 28, 2017_ + + * Allow LedgerSubprovider to handle `eth_sign` in addition to `personal_sign` RPC requests + +## v0.2.0 - _December 20, 2017_ + + * Improve the performance of address fetching (#271) diff --git a/packages/subproviders/README.md b/packages/subproviders/README.md index 5fa31611a..d7b80f7ee 100644 --- a/packages/subproviders/README.md +++ b/packages/subproviders/README.md @@ -1,15 +1,32 @@ -Subproviders ------------ +## @0xproject/subproviders -A few useful subproviders. +A few useful web3 subproviders including a LedgerSubprovider useful for adding Ledger Nano S support. ## Installation ``` -npm install @0xproject/subproviders --save +yarn add @0xproject/subproviders ``` -## Subproviders +## Usage + +Simply import the subprovider you are interested in using: + +```javascript +import { + ledgerEthereumBrowserClientFactoryAsync as ledgerEthereumClientFactoryAsync, + LedgerSubprovider, +} from '@0xproject/subproviders'; + +const ledgerSubprovider = new LedgerSubprovider( + networkId, + ledgerEthereumClientFactoryAsync, +); + +const accounts = await ledgerSubprovider.getAccountsAsync(); +``` + +### Subproviders #### Ledger Nano S subprovider @@ -23,17 +40,67 @@ A subprovider which attempts to send an RPC call to a list of RPC endpoints sequ A subprovider that relays all signing related requests to a particular provider (in our case the provider injected onto the web page), while sending all other requests to a different provider (perhaps your own backing Ethereum node or Infura). -### Integration tests +## Contributing + +We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. + +Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. + +### Install Dependencies + +If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: + +```bash +yarn config set workspaces-experimental true +``` + +```bash +yarn install +``` + +### Build + +```bash +yarn build +``` + +### Clean + +```bash +yarn clean +``` + +### Lint + +```bash +yarn lint +``` + +### Run tests + +#### Unit tests + +```bash +yarn run test:unit +``` + +#### Integration tests In order to run the integration tests, make sure you have a Ledger Nano S available. -- Plug it into your computer -- Unlock the device -- Open the on-device Ethereum app -- Make sure "browser support" is disabled +* Plug it into your computer +* Unlock the device +* Open the on-device Ethereum app +* Make sure "browser support" is disabled Then run: ``` yarn test:integration ``` + +#### All tests + +```bash +yarn run test:all +``` diff --git a/packages/subproviders/package.json b/packages/subproviders/package.json index c3ecfd2f0..2735f8280 100644 --- a/packages/subproviders/package.json +++ b/packages/subproviders/package.json @@ -1,53 +1,55 @@ { - "name": "@0xproject/subproviders", - "version": "0.0.1", - "main": "lib/src/index.js", - "types": "lib/src/index.d.ts", - "license": "Apache-2.0", - "scripts": { - "clean": "shx rm -rf lib", - "build": "tsc", - "lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'", - "run_mocha_unit": "mocha lib/test/unit/**/*_test.js --timeout 10000 --bail --exit", - "run_mocha_integration": "mocha lib/test/integration/**/*_test.js --timeout 10000 --bail --exit", - "test": "npm run test:unit", - "test:circleci": "npm run test:unit", - "test:all": "run-s test:unit test:integration", - "test:unit": "run-s clean build run_mocha_unit", - "test:integration": "run-s clean build run_mocha_integration" - }, - "dependencies": { - "@0xproject/assert": "^0.0.6", - "bn.js": "^4.11.8", - "es6-promisify": "^5.0.0", - "ethereum-address": "^0.0.4", - "ethereumjs-tx": "^1.3.3", - "ethereumjs-util": "^5.1.1", - "ledgerco": "0xProject/ledger-node-js-api", - "lodash": "^4.17.4", - "semaphore-async-await": "^1.5.1", - "web3": "^0.20.0", - "web3-provider-engine": "^13.0.1" - }, - "devDependencies": { - "@0xproject/tslint-config": "^0.2.0", - "@types/lodash": "^4.14.86", - "@types/mocha": "^2.2.42", - "@types/node": "^8.0.53", - "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-typescript-typings": "^0.0.1", - "dirty-chai": "^2.0.1", - "mocha": "^4.0.1", - "npm-run-all": "^4.1.2", - "shx": "^0.2.2", - "tslint": "5.8.0", - "types-bn": "^0.0.1", - "types-ethereumjs-util": "0xproject/types-ethereumjs-util", - "typescript": "~2.6.1", - "web3-typescript-typings": "^0.7.2", - "webpack": "^3.1.0" - } + "name": "@0xproject/subproviders", + "version": "0.3.2", + "main": "lib/src/index.js", + "types": "lib/src/index.d.ts", + "license": "Apache-2.0", + "scripts": { + "clean": "shx rm -rf lib", + "build": "tsc", + "lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'", + "run_mocha_unit": "mocha lib/test/unit/**/*_test.js --timeout 10000 --bail --exit", + "run_mocha_integration": "mocha lib/test/integration/**/*_test.js --timeout 10000 --bail --exit", + "test": "npm run test:unit", + "test:circleci": "npm run test:unit", + "test:all": "run-s test:unit test:integration", + "test:unit": "run-s clean build run_mocha_unit", + "test:integration": "run-s clean build run_mocha_integration" + }, + "dependencies": { + "@0xproject/assert": "^0.0.12", + "@0xproject/utils": "^0.2.1", + "bn.js": "^4.11.8", + "es6-promisify": "^5.0.0", + "ethereumjs-tx": "^1.3.3", + "ethereumjs-util": "^5.1.1", + "hdkey": "^0.7.1", + "ledgerco": "0xProject/ledger-node-js-api", + "lodash": "^4.17.4", + "semaphore-async-await": "^1.5.1", + "web3": "^0.20.0", + "web3-provider-engine": "^13.0.1" + }, + "devDependencies": { + "@0xproject/tslint-config": "^0.4.3", + "@0xproject/utils": "^0.2.1", + "@types/lodash": "^4.14.86", + "@types/mocha": "^2.2.42", + "@types/node": "^8.0.53", + "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-typescript-typings": "^0.0.2", + "dirty-chai": "^2.0.1", + "mocha": "^4.0.1", + "npm-run-all": "^4.1.2", + "shx": "^0.2.2", + "tslint": "5.8.0", + "types-bn": "^0.0.1", + "types-ethereumjs-util": "0xproject/types-ethereumjs-util", + "typescript": "~2.6.1", + "web3-typescript-typings": "^0.7.2", + "webpack": "^3.1.0" + } } diff --git a/packages/subproviders/scripts/postpublish.js b/packages/subproviders/scripts/postpublish.js new file mode 100644 index 000000000..7fa452b08 --- /dev/null +++ b/packages/subproviders/scripts/postpublish.js @@ -0,0 +1,14 @@ +const postpublish_utils = require('../../../scripts/postpublish_utils'); +const packageJSON = require('../package.json'); + +const subPackageName = packageJSON.name; + +postpublish_utils.getLatestTagAndVersionAsync(subPackageName) + .then(function(result) { + const releaseName = postpublish_utils.getReleaseName(subPackageName, result.version); + const assets = []; + return postpublish_utils.publishReleaseNotes(result.tag, releaseName, assets); + }) + .catch (function(err) { + throw err; + }); diff --git a/packages/subproviders/src/globals.d.ts b/packages/subproviders/src/globals.d.ts index 520ca9232..53457fa24 100644 --- a/packages/subproviders/src/globals.d.ts +++ b/packages/subproviders/src/globals.d.ts @@ -1,10 +1,9 @@ -/// <reference types='chai-typescript-typings' /> -/// <reference types='chai-as-promised-typescript-typings' /> declare module 'dirty-chai'; declare module 'es6-promisify'; // tslint:disable:max-classes-per-file // tslint:disable:class-name +// tslint:disable:async-suffix // tslint:disable:completed-docs // Ethereumjs-tx declarations @@ -46,19 +45,20 @@ declare module 'ledgerco' { export class eth { public comm: comm; constructor(comm: comm); - public getAddress_async(path: string, display?: boolean, chaincode?: boolean): - Promise<{publicKey: string; address: string}>; + public getAddress_async( + path: string, + display?: boolean, + chaincode?: boolean, + ): Promise<{ publicKey: string; address: string; chainCode: string }>; public signTransaction_async(path: string, rawTxHex: string): Promise<ECSignatureString>; - public getAppConfiguration_async(): Promise<{ arbitraryDataEnabled: number; version: string }>; + public getAppConfiguration_async(): Promise<{ + arbitraryDataEnabled: number; + version: string; + }>; public signPersonalMessage_async(path: string, messageHex: string): Promise<ECSignature>; } } -// ethereum-address declarations -declare module 'ethereum-address' { - export const isAddress: (address: string) => boolean; -} - // Semaphore-async-await declarations declare module 'semaphore-async-await' { class Semaphore { @@ -77,21 +77,34 @@ declare module 'web3-provider-engine/subproviders/subprovider' { declare module 'web3-provider-engine/subproviders/rpc' { import * as Web3 from 'web3'; class RpcSubprovider { - constructor(options: {rpcUrl: string}); + constructor(options: { rpcUrl: string }); public handleRequest( - payload: Web3.JSONRPCRequestPayload, next: () => void, end: (err: Error|null, data?: any) => void, + payload: Web3.JSONRPCRequestPayload, + next: () => void, + end: (err: Error | null, data?: any) => void, ): void; } export = RpcSubprovider; } declare module 'web3-provider-engine' { - class Web3ProviderEngine { - public on(event: string, handler: () => void): void; - public send(payload: any): void; - public sendAsync(payload: any, callback: (error: any, response: any) => void): void; - public addProvider(provider: any): void; - public start(): void; - public stop(): void; - } - export = Web3ProviderEngine; + class Web3ProviderEngine { + public on(event: string, handler: () => void): void; + public send(payload: any): void; + public sendAsync(payload: any, callback: (error: any, response: any) => void): void; + public addProvider(provider: any): void; + public start(): void; + public stop(): void; + } + export = Web3ProviderEngine; +} + +// hdkey declarations +declare module 'hdkey' { + class HDNode { + public publicKey: Buffer; + public chainCode: Buffer; + public constructor(); + public derive(path: string): HDNode; + } + export = HDNode; } diff --git a/packages/subproviders/src/index.ts b/packages/subproviders/src/index.ts index 9b7cab3fa..720c4362f 100644 --- a/packages/subproviders/src/index.ts +++ b/packages/subproviders/src/index.ts @@ -4,18 +4,12 @@ import { eth as LedgerEthereumClientFn, } from 'ledgerco'; -import {LedgerEthereumClient} from './types'; +import { LedgerEthereumClient } from './types'; -export {InjectedWeb3Subprovider} from './subproviders/injected_web3'; -export {RedundantRPCSubprovider} from './subproviders/redundant_rpc'; -export { - LedgerSubprovider, -} from './subproviders/ledger'; -export { - ECSignature, - LedgerWalletSubprovider, - LedgerCommunicationClient, -} from './types'; +export { InjectedWeb3Subprovider } from './subproviders/injected_web3'; +export { RedundantRPCSubprovider } from './subproviders/redundant_rpc'; +export { LedgerSubprovider } from './subproviders/ledger'; +export { ECSignature, LedgerWalletSubprovider, LedgerCommunicationClient } from './types'; /** * A factory method for creating a LedgerEthereumClient usable in a browser context. diff --git a/packages/subproviders/src/subproviders/injected_web3.ts b/packages/subproviders/src/subproviders/injected_web3.ts index 25d747a62..bd29acb22 100644 --- a/packages/subproviders/src/subproviders/injected_web3.ts +++ b/packages/subproviders/src/subproviders/injected_web3.ts @@ -9,29 +9,31 @@ import Web3ProviderEngine = require('web3-provider-engine'); * Source: https://github.com/MetaMask/provider-engine/blob/master/subproviders/subprovider.js */ export class InjectedWeb3Subprovider { - private injectedWeb3: Web3; + private _injectedWeb3: Web3; constructor(injectedWeb3: Web3) { - this.injectedWeb3 = injectedWeb3; + this._injectedWeb3 = injectedWeb3; } public handleRequest( - payload: Web3.JSONRPCRequestPayload, next: () => void, end: (err: Error|null, result: any) => void, + payload: Web3.JSONRPCRequestPayload, + next: () => void, + end: (err: Error | null, result: any) => void, ) { switch (payload.method) { case 'web3_clientVersion': - this.injectedWeb3.version.getNode(end); + this._injectedWeb3.version.getNode(end); return; case 'eth_accounts': - this.injectedWeb3.eth.getAccounts(end); + this._injectedWeb3.eth.getAccounts(end); return; case 'eth_sendTransaction': const [txParams] = payload.params; - this.injectedWeb3.eth.sendTransaction(txParams, end); + this._injectedWeb3.eth.sendTransaction(txParams, end); return; case 'eth_sign': const [address, message] = payload.params; - this.injectedWeb3.eth.sign(address, message, end); + this._injectedWeb3.eth.sign(address, message, end); return; default: diff --git a/packages/subproviders/src/subproviders/ledger.ts b/packages/subproviders/src/subproviders/ledger.ts index e0a08f792..7267a793e 100644 --- a/packages/subproviders/src/subproviders/ledger.ts +++ b/packages/subproviders/src/subproviders/ledger.ts @@ -1,9 +1,8 @@ -import {assert} from '@0xproject/assert'; -import promisify = require('es6-promisify'); -import {isAddress} from 'ethereum-address'; +import { assert } from '@0xproject/assert'; +import { addressUtils } from '@0xproject/utils'; import EthereumTx = require('ethereumjs-tx'); import ethUtil = require('ethereumjs-util'); -import * as ledger from 'ledgerco'; +import HDNode = require('hdkey'); import * as _ from 'lodash'; import Semaphore from 'semaphore-async-await'; import Web3 = require('web3'); @@ -17,13 +16,12 @@ import { ResponseWithTxParams, } from '../types'; -import {Subprovider} from './subprovider'; +import { Subprovider } from './subprovider'; const DEFAULT_DERIVATION_PATH = `44'/60'/0'`; const NUM_ADDRESSES_TO_FETCH = 10; const ASK_FOR_ON_DEVICE_CONFIRMATION = false; -const SHOULD_GET_CHAIN_CODE = false; -const HEX_REGEX = /^[0-9A-Fa-f]+$/g; +const SHOULD_GET_CHAIN_CODE = true; export class LedgerSubprovider extends Subprovider { private _nonceLock: Semaphore; @@ -34,20 +32,8 @@ export class LedgerSubprovider extends Subprovider { private _ledgerEthereumClientFactoryAsync: LedgerEthereumClientFactoryAsync; private _ledgerClientIfExists?: LedgerEthereumClient; private _shouldAlwaysAskForConfirmation: boolean; - private static isValidHex(data: string) { - if (!_.isString(data)) { - return false; - } - const isHexPrefixed = data.slice(0, 2) === '0x'; - if (!isHexPrefixed) { - return false; - } - const nonPrefixed = data.slice(2); - const isValid = nonPrefixed.match(HEX_REGEX); - return isValid; - } - private static validateSender(sender: string) { - if (_.isUndefined(sender) || !isAddress(sender)) { + private static _validateSender(sender: string) { + if (_.isUndefined(sender) || !addressUtils.isAddress(sender)) { throw new Error(LedgerSubproviderErrors.SenderInvalidOrNotSupplied); } } @@ -58,12 +44,11 @@ export class LedgerSubprovider extends Subprovider { this._networkId = config.networkId; this._ledgerEthereumClientFactoryAsync = config.ledgerEthereumClientFactoryAsync; this._derivationPath = config.derivationPath || DEFAULT_DERIVATION_PATH; - this._shouldAlwaysAskForConfirmation = !_.isUndefined(config.accountFetchingConfigs) && - !_.isUndefined( - config.accountFetchingConfigs.shouldAskForOnDeviceConfirmation, - ) ? - config.accountFetchingConfigs.shouldAskForOnDeviceConfirmation : - ASK_FOR_ON_DEVICE_CONFIRMATION; + this._shouldAlwaysAskForConfirmation = + !_.isUndefined(config.accountFetchingConfigs) && + !_.isUndefined(config.accountFetchingConfigs.shouldAskForOnDeviceConfirmation) + ? config.accountFetchingConfigs.shouldAskForOnDeviceConfirmation + : ASK_FOR_ON_DEVICE_CONFIRMATION; this._derivationPathIndex = 0; } public getPath(): string { @@ -76,7 +61,9 @@ export class LedgerSubprovider extends Subprovider { this._derivationPathIndex = pathIndex; } public async handleRequest( - payload: Web3.JSONRPCRequestPayload, next: () => void, end: (err: Error|null, result?: any) => void, + payload: Web3.JSONRPCRequestPayload, + next: () => void, + end: (err: Error | null, result?: any) => void, ) { let accounts; let txParams; @@ -102,8 +89,8 @@ export class LedgerSubprovider extends Subprovider { case 'eth_sendTransaction': txParams = payload.params[0]; try { - LedgerSubprovider.validateSender(txParams.from); - const result = await this.sendTransactionAsync(txParams); + LedgerSubprovider._validateSender(txParams.from); + const result = await this._sendTransactionAsync(txParams); end(null, result); } catch (err) { end(err); @@ -113,15 +100,16 @@ export class LedgerSubprovider extends Subprovider { case 'eth_signTransaction': txParams = payload.params[0]; try { - const result = await this.signTransactionWithoutSendingAsync(txParams); + const result = await this._signTransactionWithoutSendingAsync(txParams); end(null, result); } catch (err) { end(err); } return; + case 'eth_sign': case 'personal_sign': - const data = payload.params[0]; + const data = payload.method === 'eth_sign' ? payload.params[1] : payload.params[0]; try { if (_.isUndefined(data)) { throw new Error(LedgerSubproviderErrors.DataMissingForSignPersonalMessage); @@ -140,27 +128,38 @@ export class LedgerSubprovider extends Subprovider { } } public async getAccountsAsync(): Promise<string[]> { - this._ledgerClientIfExists = await this.createLedgerClientAsync(); + this._ledgerClientIfExists = await this._createLedgerClientAsync(); + + let ledgerResponse; + try { + ledgerResponse = await this._ledgerClientIfExists.getAddress_async( + this._derivationPath, + this._shouldAlwaysAskForConfirmation, + SHOULD_GET_CHAIN_CODE, + ); + } finally { + await this._destroyLedgerClientAsync(); + } + + const hdKey = new HDNode(); + hdKey.publicKey = new Buffer(ledgerResponse.publicKey, 'hex'); + hdKey.chainCode = new Buffer(ledgerResponse.chainCode, 'hex'); - // TODO: replace with generating addresses without hitting Ledger const accounts = []; for (let i = 0; i < NUM_ADDRESSES_TO_FETCH; i++) { - try { - const derivationPath = `${this._derivationPath}/${i + this._derivationPathIndex}`; - const result = await this._ledgerClientIfExists.getAddress_async( - derivationPath, this._shouldAlwaysAskForConfirmation, SHOULD_GET_CHAIN_CODE, - ); - accounts.push(result.address.toLowerCase()); - } catch (err) { - await this.destoryLedgerClientAsync(); - throw err; - } + const derivedHDNode = hdKey.derive(`m/${i + this._derivationPathIndex}`); + const derivedPublicKey = derivedHDNode.publicKey; + const shouldSanitizePublicKey = true; + const ethereumAddressUnprefixed = ethUtil + .publicToAddress(derivedPublicKey, shouldSanitizePublicKey) + .toString('hex'); + const ethereumAddressPrefixed = ethUtil.addHexPrefix(ethereumAddressUnprefixed); + accounts.push(ethereumAddressPrefixed.toLowerCase()); } - await this.destoryLedgerClientAsync(); return accounts; } public async signTransactionAsync(txParams: PartialTxParams): Promise<string> { - this._ledgerClientIfExists = await this.createLedgerClientAsync(); + this._ledgerClientIfExists = await this._createLedgerClientAsync(); const tx = new EthereumTx(txParams); @@ -171,7 +170,7 @@ export class LedgerSubprovider extends Subprovider { const txHex = tx.serialize().toString('hex'); try { - const derivationPath = this.getDerivationPath(); + const derivationPath = this._getDerivationPath(); const result = await this._ledgerClientIfExists.signTransaction_async(derivationPath, txHex); // Store signature in transaction tx.r = Buffer.from(result.r, 'hex'); @@ -181,43 +180,45 @@ export class LedgerSubprovider extends Subprovider { // EIP155: v should be chain_id * 2 + {35, 36} const signedChainId = Math.floor((tx.v[0] - 35) / 2); if (signedChainId !== this._networkId) { - await this.destoryLedgerClientAsync(); + await this._destroyLedgerClientAsync(); const err = new Error(LedgerSubproviderErrors.TooOldLedgerFirmware); throw err; } const signedTxHex = `0x${tx.serialize().toString('hex')}`; - await this.destoryLedgerClientAsync(); + await this._destroyLedgerClientAsync(); return signedTxHex; } catch (err) { - await this.destoryLedgerClientAsync(); + await this._destroyLedgerClientAsync(); throw err; } } public async signPersonalMessageAsync(data: string): Promise<string> { - this._ledgerClientIfExists = await this.createLedgerClientAsync(); + this._ledgerClientIfExists = await this._createLedgerClientAsync(); try { - const derivationPath = this.getDerivationPath(); + const derivationPath = this._getDerivationPath(); const result = await this._ledgerClientIfExists.signPersonalMessage_async( - derivationPath, ethUtil.stripHexPrefix(data)); + derivationPath, + ethUtil.stripHexPrefix(data), + ); const v = result.v - 27; let vHex = v.toString(16); if (vHex.length < 2) { vHex = `0${v}`; } const signature = `0x${result.r}${result.s}${vHex}`; - await this.destoryLedgerClientAsync(); + await this._destroyLedgerClientAsync(); return signature; } catch (err) { - await this.destoryLedgerClientAsync(); + await this._destroyLedgerClientAsync(); throw err; } } - private getDerivationPath() { + private _getDerivationPath() { const derivationPath = `${this.getPath()}/${this._derivationPathIndex}`; return derivationPath; } - private async createLedgerClientAsync(): Promise<LedgerEthereumClient> { + private async _createLedgerClientAsync(): Promise<LedgerEthereumClient> { await this._connectionLock.wait(); if (!_.isUndefined(this._ledgerClientIfExists)) { this._connectionLock.signal(); @@ -227,7 +228,7 @@ export class LedgerSubprovider extends Subprovider { this._connectionLock.signal(); return ledgerEthereumClient; } - private async destoryLedgerClientAsync() { + private async _destroyLedgerClientAsync() { await this._connectionLock.wait(); if (_.isUndefined(this._ledgerClientIfExists)) { this._connectionLock.signal(); @@ -237,11 +238,11 @@ export class LedgerSubprovider extends Subprovider { this._ledgerClientIfExists = undefined; this._connectionLock.signal(); } - private async sendTransactionAsync(txParams: PartialTxParams): Promise<Web3.JSONRPCResponsePayload> { + private async _sendTransactionAsync(txParams: PartialTxParams): Promise<string> { await this._nonceLock.wait(); try { // fill in the extras - const filledParams = await this.populateMissingTxParamsAsync(txParams); + const filledParams = await this._populateMissingTxParamsAsync(txParams); // sign it const signedTx = await this.signTransactionAsync(filledParams); // emit a submit @@ -251,17 +252,17 @@ export class LedgerSubprovider extends Subprovider { }; const result = await this.emitPayloadAsync(payload); this._nonceLock.signal(); - return result; + return result.result; } catch (err) { this._nonceLock.signal(); throw err; } } - private async signTransactionWithoutSendingAsync(txParams: PartialTxParams): Promise<ResponseWithTxParams> { + private async _signTransactionWithoutSendingAsync(txParams: PartialTxParams): Promise<ResponseWithTxParams> { await this._nonceLock.wait(); try { // fill in the extras - const filledParams = await this.populateMissingTxParamsAsync(txParams); + const filledParams = await this._populateMissingTxParamsAsync(txParams); // sign it const signedTx = await this.signTransactionAsync(filledParams); @@ -276,7 +277,7 @@ export class LedgerSubprovider extends Subprovider { throw err; } } - private async populateMissingTxParamsAsync(txParams: PartialTxParams): Promise<PartialTxParams> { + private async _populateMissingTxParamsAsync(txParams: PartialTxParams): Promise<PartialTxParams> { if (_.isUndefined(txParams.gasPrice)) { const gasPriceResult = await this.emitPayloadAsync({ method: 'eth_gasPrice', diff --git a/packages/subproviders/src/subproviders/redundant_rpc.ts b/packages/subproviders/src/subproviders/redundant_rpc.ts index 80462bbfb..a3cb463a8 100644 --- a/packages/subproviders/src/subproviders/redundant_rpc.ts +++ b/packages/subproviders/src/subproviders/redundant_rpc.ts @@ -1,17 +1,19 @@ -import {promisify} from '@0xproject/utils'; +import { promisify } from '@0xproject/utils'; import * as _ from 'lodash'; import RpcSubprovider = require('web3-provider-engine/subproviders/rpc'); -import {JSONRPCPayload} from '../types'; +import { JSONRPCPayload } from '../types'; -import {Subprovider} from './subprovider'; +import { Subprovider } from './subprovider'; export class RedundantRPCSubprovider extends Subprovider { - private rpcs: RpcSubprovider[]; - private static async firstSuccessAsync( - rpcs: RpcSubprovider[], payload: JSONRPCPayload, next: () => void, + private _rpcs: RpcSubprovider[]; + private static async _firstSuccessAsync( + rpcs: RpcSubprovider[], + payload: JSONRPCPayload, + next: () => void, ): Promise<any> { - let lastErr: Error|undefined; + let lastErr: Error | undefined; for (const rpc of rpcs) { try { const data = await promisify(rpc.handleRequest.bind(rpc))(payload, next); @@ -27,21 +29,24 @@ export class RedundantRPCSubprovider extends Subprovider { } constructor(endpoints: string[]) { super(); - this.rpcs = _.map(endpoints, endpoint => { + this._rpcs = _.map(endpoints, endpoint => { return new RpcSubprovider({ rpcUrl: endpoint, }); }); } - public async handleRequest(payload: JSONRPCPayload, next: () => void, - end: (err: Error|null, data?: any) => void): Promise<void> { - const rpcsCopy = this.rpcs.slice(); + // tslint:disable-next-line:async-suffix + public async handleRequest( + payload: JSONRPCPayload, + next: () => void, + end: (err: Error | null, data?: any) => void, + ): Promise<void> { + const rpcsCopy = this._rpcs.slice(); try { - const data = await RedundantRPCSubprovider.firstSuccessAsync(rpcsCopy, payload, next); + const data = await RedundantRPCSubprovider._firstSuccessAsync(rpcsCopy, payload, next); end(null, data); } catch (err) { end(err); } - } } diff --git a/packages/subproviders/src/subproviders/subprovider.ts b/packages/subproviders/src/subproviders/subprovider.ts index 64d97b958..6435c9f65 100644 --- a/packages/subproviders/src/subproviders/subprovider.ts +++ b/packages/subproviders/src/subproviders/subprovider.ts @@ -1,19 +1,16 @@ import promisify = require('es6-promisify'); import Web3 = require('web3'); -import { - JSONRPCPayload, -} from '../types'; +import { JSONRPCPayload } from '../types'; /* * A version of the base class Subprovider found in providerEngine * This one has an async/await `emitPayloadAsync` and also defined types. * Altered version of: https://github.com/MetaMask/provider-engine/blob/master/subproviders/subprovider.js */ export class Subprovider { - private engine: any; - private currentBlock: any; + private _engine: any; // Ported from: https://github.com/MetaMask/provider-engine/blob/master/util/random-id.js - private static getRandomId() { + private static _getRandomId() { const extraDigits = 3; // 13 time digits const datePart = new Date().getTime() * Math.pow(10, extraDigits); @@ -22,10 +19,10 @@ export class Subprovider { // 16 digits return datePart + extraPart; } - private static createFinalPayload(payload: JSONRPCPayload): Web3.JSONRPCRequestPayload { + private static _createFinalPayload(payload: JSONRPCPayload): Web3.JSONRPCRequestPayload { const finalPayload = { // defaults - id: Subprovider.getRandomId(), + id: Subprovider._getRandomId(), jsonrpc: '2.0', params: [], ...payload, @@ -33,14 +30,11 @@ export class Subprovider { return finalPayload; } public setEngine(engine: any): void { - this.engine = engine; - engine.on('block', (block: any) => { - this.currentBlock = block; - }); + this._engine = engine; } public async emitPayloadAsync(payload: JSONRPCPayload): Promise<any> { - const finalPayload = Subprovider.createFinalPayload(payload); - const response = await promisify(this.engine.sendAsync, this.engine)(finalPayload); + const finalPayload = Subprovider._createFinalPayload(payload); + const response = await promisify(this._engine.sendAsync, this._engine)(finalPayload); return response; } } diff --git a/packages/subproviders/src/types.ts b/packages/subproviders/src/types.ts index 38dc1e67e..3db8be943 100644 --- a/packages/subproviders/src/types.ts +++ b/packages/subproviders/src/types.ts @@ -1,5 +1,4 @@ import * as _ from 'lodash'; -import * as Web3 from 'web3'; export interface LedgerCommunicationClient { close_async: () => Promise<void>; @@ -11,8 +10,13 @@ export interface LedgerCommunicationClient { * NodeJs and Browser communication are supported. */ export interface LedgerEthereumClient { - getAddress_async: (derivationPath: string, askForDeviceConfirmation: boolean, - shouldGetChainCode: boolean) => Promise<LedgerGetAddressResult>; + // shouldGetChainCode is defined as `true` instead of `boolean` because other types rely on the assumption + // that we get back the chain code and we don't have dependent types to express it properly + getAddress_async: ( + derivationPath: string, + askForDeviceConfirmation: boolean, + shouldGetChainCode: true, + ) => Promise<LedgerGetAddressResult>; signPersonalMessage_async: (derivationPath: string, messageHex: string) => Promise<ECSignature>; signTransaction_async: (derivationPath: string, txHex: string) => Promise<ECSignatureString>; comm: LedgerCommunicationClient; @@ -64,6 +68,8 @@ export interface SignatureData { export interface LedgerGetAddressResult { address: string; + publicKey: string; + chainCode: string; } export interface LedgerWalletSubprovider { diff --git a/packages/subproviders/test/integration/ledger_subprovider_test.ts b/packages/subproviders/test/integration/ledger_subprovider_test.ts index 75f6d47fe..628b532d7 100644 --- a/packages/subproviders/test/integration/ledger_subprovider_test.ts +++ b/packages/subproviders/test/integration/ledger_subprovider_test.ts @@ -2,23 +2,14 @@ import * as chai from 'chai'; import promisify = require('es6-promisify'); import * as ethUtils from 'ethereumjs-util'; import * as _ from 'lodash'; -import * as mocha from 'mocha'; import Web3 = require('web3'); import Web3ProviderEngine = require('web3-provider-engine'); import RpcSubprovider = require('web3-provider-engine/subproviders/rpc'); -import { - ECSignature, - ledgerEthereumNodeJsClientFactoryAsync, - LedgerSubprovider, -} from '../../src'; -import { - DoneCallback, - LedgerGetAddressResult, - PartialTxParams, -} from '../../src/types'; -import {chaiSetup} from '../chai_setup'; -import {reportCallbackErrors} from '../utils/report_callback_errors'; +import { ledgerEthereumNodeJsClientFactoryAsync, LedgerSubprovider } from '../../src'; +import { DoneCallback } from '../../src/types'; +import { chaiSetup } from '../chai_setup'; +import { reportCallbackErrors } from '../utils/report_callback_errors'; chaiSetup.configure(); const expect = chai.expect; @@ -55,8 +46,9 @@ describe('LedgerSubprovider', () => { chainId: 3, }; const txHex = await ledgerSubprovider.signTransactionAsync(tx); - // tslint:disable-next-line:max-line-length - expect(txHex).to.be.equal('0xf85f8080822710940000000000000000000000000000000000000000808077a088a95ef1378487bc82be558e82c8478baf840c545d5b887536bb1da63673a98ba0019f4a4b9a107d1e6752bf7f701e275f28c13791d6e76af895b07373462cefaa'); + expect(txHex).to.be.equal( + '0xf85f8080822710940000000000000000000000000000000000000000808077a088a95ef1378487bc82be558e82c8478baf840c545d5b887536bb1da63673a98ba0019f4a4b9a107d1e6752bf7f701e275f28c13791d6e76af895b07373462cefaa', + ); }); }); describe('calls through a provider', () => { @@ -89,7 +81,27 @@ describe('LedgerSubprovider', () => { }); ledgerProvider.sendAsync(payload, callback); }); - it('signs a personal message', (done: DoneCallback) => { + it('signs a personal message with eth_sign', (done: DoneCallback) => { + (async () => { + const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer('hello world')); + const accounts = await ledgerSubprovider.getAccountsAsync(); + const signer = accounts[0]; + const payload = { + jsonrpc: '2.0', + method: 'eth_sign', + params: [signer, messageHex], + id: 1, + }; + const callback = reportCallbackErrors(done)((err: Error, response: Web3.JSONRPCResponsePayload) => { + expect(err).to.be.a('null'); + expect(response.result.length).to.be.equal(132); + expect(response.result.substr(0, 2)).to.be.equal('0x'); + done(); + }); + ledgerProvider.sendAsync(payload, callback); + })().catch(done); + }); + it('signs a personal message with personal_sign', (done: DoneCallback) => { (async () => { const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer('hello world')); const accounts = await ledgerSubprovider.getAccountsAsync(); diff --git a/packages/subproviders/test/unit/ledger_subprovider_test.ts b/packages/subproviders/test/unit/ledger_subprovider_test.ts index 964df5db9..1c70dd3a6 100644 --- a/packages/subproviders/test/unit/ledger_subprovider_test.ts +++ b/packages/subproviders/test/unit/ledger_subprovider_test.ts @@ -5,23 +5,14 @@ import Web3 = require('web3'); import Web3ProviderEngine = require('web3-provider-engine'); import RpcSubprovider = require('web3-provider-engine/subproviders/rpc'); -import { - ECSignature, - LedgerSubprovider, -} from '../../src'; -import { - DoneCallback, - ECSignatureString, - LedgerCommunicationClient, - LedgerGetAddressResult, - LedgerSubproviderErrors, -} from '../../src/types'; -import {chaiSetup} from '../chai_setup'; -import {reportCallbackErrors} from '../utils/report_callback_errors'; +import { LedgerSubprovider } from '../../src'; +import { DoneCallback, LedgerCommunicationClient, LedgerSubproviderErrors } from '../../src/types'; +import { chaiSetup } from '../chai_setup'; +import { reportCallbackErrors } from '../utils/report_callback_errors'; chaiSetup.configure(); const expect = chai.expect; -const FAKE_ADDRESS = '0x9901c66f2d4b95f7074b553da78084d708beca70'; +const FAKE_ADDRESS = '0xb088a3bc93f71b4de97b9de773e9647645983688'; describe('LedgerSubprovider', () => { const networkId: number = 42; @@ -31,8 +22,14 @@ describe('LedgerSubprovider', () => { // tslint:disable:no-object-literal-type-assertion const ledgerEthClient = { getAddress_async: async () => { + const publicKey = + '04f428290f4c5ed6a198f71b8205f488141dbb3f0840c923bbfa798ecbee6370986c03b5575d94d506772fb48a6a44e345e4ebd4f028a6f609c44b655d6d3e71a1'; + const chainCode = 'ac055a5537c0c7e9e02d14a197cad6b857836da2a12043b46912a37d959b5ae8'; + const address = '0xBa388BA5e5EEF2c6cE42d831c2B3A28D3c99bdB1'; return { - address: FAKE_ADDRESS, + publicKey, + address, + chainCode, }; }, signPersonalMessage_async: async () => { @@ -73,17 +70,20 @@ describe('LedgerSubprovider', () => { it('signs a personal message', async () => { const data = ethUtils.bufferToHex(ethUtils.toBuffer('hello world')); const ecSignatureHex = await ledgerSubprovider.signPersonalMessageAsync(data); - // tslint:disable-next-line:max-line-length - expect(ecSignatureHex).to.be.equal('0xa6cc284bff14b42bdf5e9286730c152be91719d478605ec46b3bebcd0ae491480652a1a7b742ceb0213d1e744316e285f41f878d8af0b8e632cbca4c279132d001'); + expect(ecSignatureHex).to.be.equal( + '0xa6cc284bff14b42bdf5e9286730c152be91719d478605ec46b3bebcd0ae491480652a1a7b742ceb0213d1e744316e285f41f878d8af0b8e632cbca4c279132d001', + ); }); }); describe('failure cases', () => { it('cannot open multiple simultaneous connections to the Ledger device', async () => { const data = ethUtils.bufferToHex(ethUtils.toBuffer('hello world')); - return expect(Promise.all([ - ledgerSubprovider.getAccountsAsync(), - ledgerSubprovider.signPersonalMessageAsync(data), - ])).to.be.rejectedWith(LedgerSubproviderErrors.MultipleOpenConnectionsDisallowed); + return expect( + Promise.all([ + ledgerSubprovider.getAccountsAsync(), + ledgerSubprovider.signPersonalMessageAsync(data), + ]), + ).to.be.rejectedWith(LedgerSubproviderErrors.MultipleOpenConnectionsDisallowed); }); }); }); @@ -114,7 +114,24 @@ describe('LedgerSubprovider', () => { }); provider.sendAsync(payload, callback); }); - it('signs a personal message', (done: DoneCallback) => { + it('signs a personal message with eth_sign', (done: DoneCallback) => { + const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer('hello world')); + const payload = { + jsonrpc: '2.0', + method: 'eth_sign', + params: ['0x0000000000000000000000000000000000000000', messageHex], + id: 1, + }; + const callback = reportCallbackErrors(done)((err: Error, response: Web3.JSONRPCResponsePayload) => { + expect(err).to.be.a('null'); + expect(response.result).to.be.equal( + '0xa6cc284bff14b42bdf5e9286730c152be91719d478605ec46b3bebcd0ae491480652a1a7b742ceb0213d1e744316e285f41f878d8af0b8e632cbca4c279132d001', + ); + done(); + }); + provider.sendAsync(payload, callback); + }); + it('signs a personal message with personal_sign', (done: DoneCallback) => { const messageHex = ethUtils.bufferToHex(ethUtils.toBuffer('hello world')); const payload = { jsonrpc: '2.0', @@ -124,8 +141,9 @@ describe('LedgerSubprovider', () => { }; const callback = reportCallbackErrors(done)((err: Error, response: Web3.JSONRPCResponsePayload) => { expect(err).to.be.a('null'); - // tslint:disable-next-line:max-line-length - expect(response.result).to.be.equal('0xa6cc284bff14b42bdf5e9286730c152be91719d478605ec46b3bebcd0ae491480652a1a7b742ceb0213d1e744316e285f41f878d8af0b8e632cbca4c279132d001'); + expect(response.result).to.be.equal( + '0xa6cc284bff14b42bdf5e9286730c152be91719d478605ec46b3bebcd0ae491480652a1a7b742ceb0213d1e744316e285f41f878d8af0b8e632cbca4c279132d001', + ); done(); }); provider.sendAsync(payload, callback); @@ -154,6 +172,21 @@ describe('LedgerSubprovider', () => { }); }); describe('failure cases', () => { + it('should throw if `data` param not hex when calling eth_sign', (done: DoneCallback) => { + const nonHexMessage = 'hello world'; + const payload = { + jsonrpc: '2.0', + method: 'eth_sign', + params: ['0x0000000000000000000000000000000000000000', nonHexMessage], + id: 1, + }; + const callback = reportCallbackErrors(done)((err: Error, response: Web3.JSONRPCResponsePayload) => { + expect(err).to.not.be.a('null'); + expect(err.message).to.be.equal('Expected data to be of type HexString, encountered: hello world'); + done(); + }); + provider.sendAsync(payload, callback); + }); it('should throw if `data` param not hex when calling personal_sign', (done: DoneCallback) => { const nonHexMessage = 'hello world'; const payload = { @@ -187,8 +220,7 @@ describe('LedgerSubprovider', () => { }); provider.sendAsync(payload, callback); }); - it('should throw if `from` param invalid address when calling eth_sendTransaction', - (done: DoneCallback) => { + it('should throw if `from` param invalid address when calling eth_sendTransaction', (done: DoneCallback) => { const tx = { to: '0xafa3f8684e54059998bc3a7b0d2b0da075154d66', from: '0xIncorrectEthereumAddress', diff --git a/packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts b/packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts index edeb1d5a2..c3170745c 100644 --- a/packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts +++ b/packages/subproviders/test/unit/redundant_rpc_subprovider_test.ts @@ -3,22 +3,19 @@ import * as _ from 'lodash'; import Web3 = require('web3'); import Web3ProviderEngine = require('web3-provider-engine'); -import {RedundantRPCSubprovider} from '../../src'; -import { - DoneCallback, -} from '../../src/types'; -import {chaiSetup} from '../chai_setup'; -import {reportCallbackErrors} from '../utils/report_callback_errors'; +import { RedundantRPCSubprovider } from '../../src'; +import { DoneCallback } from '../../src/types'; +import { chaiSetup } from '../chai_setup'; +import { reportCallbackErrors } from '../utils/report_callback_errors'; const expect = chai.expect; +chaiSetup.configure(); describe('RedundantRpcSubprovider', () => { let provider: Web3ProviderEngine; it('succeeds when supplied a healthy endpoint', (done: DoneCallback) => { provider = new Web3ProviderEngine(); - const endpoints = [ - 'http://localhost:8545', - ]; + const endpoints = ['http://localhost:8545']; const redundantSubprovider = new RedundantRPCSubprovider(endpoints); provider.addProvider(redundantSubprovider); provider.start(); @@ -38,10 +35,7 @@ describe('RedundantRpcSubprovider', () => { }); it('succeeds when supplied at least one healthy endpoint', (done: DoneCallback) => { provider = new Web3ProviderEngine(); - const endpoints = [ - 'http://does-not-exist:3000', - 'http://localhost:8545', - ]; + const endpoints = ['http://does-not-exist:3000', 'http://localhost:8545']; const redundantSubprovider = new RedundantRPCSubprovider(endpoints); provider.addProvider(redundantSubprovider); provider.start(); diff --git a/packages/subproviders/tsconfig.json b/packages/subproviders/tsconfig.json index 24adf4637..9a65a0a97 100644 --- a/packages/subproviders/tsconfig.json +++ b/packages/subproviders/tsconfig.json @@ -1,22 +1,15 @@ { - "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/web3-typescript-typings/index.d.ts", - "../../node_modules/chai-typescript-typings/index.d.ts", - "../../node_modules/types-bn/index.d.ts", - "../../node_modules/types-ethereumjs-util/index.d.ts", - "../../node_modules/chai-as-promised-typescript-typings/index.d.ts" - ] + "extends": "../../tsconfig", + "compilerOptions": { + "outDir": "lib" + }, + "include": [ + "./src/**/*", + "./test/**/*", + "../../node_modules/chai-typescript-typings/index.d.ts", + "../../node_modules/web3-typescript-typings/index.d.ts", + "../../node_modules/types-bn/index.d.ts", + "../../node_modules/types-ethereumjs-util/index.d.ts", + "../../node_modules/chai-as-promised-typescript-typings/index.d.ts" + ] } diff --git a/packages/subproviders/tslint.json b/packages/subproviders/tslint.json index a07795151..ffaefe83a 100644 --- a/packages/subproviders/tslint.json +++ b/packages/subproviders/tslint.json @@ -1,5 +1,3 @@ { - "extends": [ - "@0xproject/tslint-config" - ] + "extends": ["@0xproject/tslint-config"] } diff --git a/packages/tslint-config/CHANGELOG.md b/packages/tslint-config/CHANGELOG.md index 7a6ba41c0..1d56bca5b 100644 --- a/packages/tslint-config/CHANGELOG.md +++ b/packages/tslint-config/CHANGELOG.md @@ -1,6 +1,15 @@ # CHANGELOG -v0.1.0 - _Nov. 14, 2017_ ------------------------- +## v0.4.0 - _December 28, 2017_ + + * Added custom 'underscore-privates' rule, requiring underscores to be prepended to private variable names + * Because our tools can be used in both a TS and JS environment, we want to make the private methods of any public facing interface show up at the bottom of auto-complete lists. Additionally, we wanted to remain consistent with respect to our usage of underscores in order to enforce this rule with a linter rule, rather then manual code reviews. + +## v0.3.0 - _December 20, 2017_ + + * Added rules for unused imports, variables and Async suffixes (#265) + +## v0.1.0 - _Nov. 14, 2017_ + * Re-published TsLintConfig previously published under NPM package `tslint-config-0xproject` * Updated to TSLint v5.8.0, requiring several rule additions to keep our conventions aligned. diff --git a/packages/tslint-config/README.md b/packages/tslint-config/README.md index 38a6bce45..8a6fa8a2f 100644 --- a/packages/tslint-config/README.md +++ b/packages/tslint-config/README.md @@ -1,10 +1,57 @@ -tslint-config -------------- +## @0xproject/tslint-config -Lint rules related to 0xProject for TSLint. +TSLint configuration and custom linter rules used by 0xProject. -## Install: +## Installation ```bash -npm install @0xproject/tslint-config --save-dev +yarn add --dev @0xproject/tslint-config +``` + +## Usage + +Add the following to your `tslint.json` file + +```json +{ + "extends": ["@0xproject/tslint-config"] +} +``` + +## Contributing + +We strongly encourage that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. + +Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. + +### Install Dependencies + +If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: + +```bash +yarn config set workspaces-experimental true +``` + +Then install dependencies + +```bash +yarn install +``` + +### Build + +```bash +yarn build +``` + +### Lint + +```bash +yarn lint +``` + +### Run Tests + +```bash +yarn test ``` diff --git a/packages/tslint-config/package.json b/packages/tslint-config/package.json index 2b08d4f56..bcffe5a8e 100644 --- a/packages/tslint-config/package.json +++ b/packages/tslint-config/package.json @@ -1,38 +1,47 @@ { - "name": "@0xproject/tslint-config", - "version": "0.2.0", - "description": "Lint rules related to 0xProject for TSLint", - "main": "tslint.json", - "files": [ - "tslint.js", - "README.md", - "LICENSE" - ], - "repository": { - "type": "git", - "url": "git://github.com/0xProject/0x.js.git" - }, - "keywords": [ - "tslint", - "config", - "0xProject", - "typescript", - "ts" - ], - "author": { - "name": "Fabio Berger", - "email": "fabio@0xproject.com" - }, - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/0xProject/0x.js/issues" - }, - "homepage": "https://github.com/0xProject/0x.js/packages/tslint-config/README.md", - "devDependencies": { - "tslint": "5.8.0", - "typescript": "~2.6.1" - }, - "dependencies": { - "tslint-react": "^3.2.0" - } + "name": "@0xproject/tslint-config", + "version": "0.4.3", + "description": "Lint rules related to 0xProject for TSLint", + "main": "tslint.json", + "scripts": { + "build": "tsc", + "clean": "shx rm -rf lib", + "lint": "tslint --project . 'rules/**/*.ts'" + }, + "files": [ + "tslint.js", + "README.md", + "LICENSE" + ], + "repository": { + "type": "git", + "url": "git://github.com/0xProject/0x.js.git" + }, + "keywords": [ + "tslint", + "config", + "0xProject", + "typescript", + "ts" + ], + "author": { + "name": "Fabio Berger", + "email": "fabio@0xproject.com" + }, + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/0xProject/0x.js/issues" + }, + "homepage": "https://github.com/0xProject/0x.js/packages/tslint-config/README.md", + "devDependencies": { + "@types/lodash": "^4.14.86", + "shx": "^0.2.2", + "tslint": "5.8.0", + "tslint-eslint-rules": "^4.1.1", + "typescript": "~2.6.1" + }, + "dependencies": { + "lodash": "^4.17.4", + "tslint-react": "^3.2.0" + } } diff --git a/packages/tslint-config/rules/asyncSuffixRule.ts b/packages/tslint-config/rules/asyncSuffixRule.ts new file mode 100644 index 000000000..5215c7151 --- /dev/null +++ b/packages/tslint-config/rules/asyncSuffixRule.ts @@ -0,0 +1,10 @@ +import * as Lint from 'tslint'; +import * as ts from 'typescript'; + +import { AsyncSuffixWalker } from './walkers/async_suffix'; + +export class Rule extends Lint.Rules.AbstractRule { + public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { + return this.applyWithWalker(new AsyncSuffixWalker(sourceFile, this.getOptions())); + } +} diff --git a/packages/tslint-config/rules/underscorePrivatesRule.ts b/packages/tslint-config/rules/underscorePrivatesRule.ts new file mode 100644 index 000000000..472ea09ff --- /dev/null +++ b/packages/tslint-config/rules/underscorePrivatesRule.ts @@ -0,0 +1,61 @@ +import * as Lint from 'tslint'; +import * as ts from 'typescript'; + +const UNDERSCORE = '_'; + +type RelevantClassMember = + | ts.MethodDeclaration + | ts.PropertyDeclaration + | ts.GetAccessorDeclaration + | ts.SetAccessorDeclaration; + +// Copied from: https://github.com/DanielRosenwasser/underscore-privates-tslint-rule +// The version on github is not published on npm +export class Rule extends Lint.Rules.AbstractRule { + public static FAILURE_STRING = 'private members must be prefixed with an underscore'; + + public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { + return this.applyWithFunction(sourceFile, walk); + } +} +function walk(ctx: Lint.WalkContext<void>): void { + traverse(ctx.sourceFile); + + function traverse(node: ts.Node): void { + checkNodeForViolations(ctx, node); + return ts.forEachChild(node, traverse); + } +} +function checkNodeForViolations(ctx: Lint.WalkContext<void>, node: ts.Node): void { + if (!isRelevantClassMember(node)) { + return; + } + // The declaration might have a computed property name or a numeric name. + const name = node.name; + if (!nameIsIdentifier(name)) { + return; + } + if (!nameStartsWithUnderscore(name.text) && memberIsPrivate(node)) { + ctx.addFailureAtNode(name, Rule.FAILURE_STRING); + } +} +function isRelevantClassMember(node: ts.Node): node is RelevantClassMember { + switch (node.kind) { + case ts.SyntaxKind.MethodDeclaration: + case ts.SyntaxKind.PropertyDeclaration: + case ts.SyntaxKind.GetAccessor: + case ts.SyntaxKind.SetAccessor: + return true; + default: + return false; + } +} +function nameStartsWithUnderscore(text: string) { + return text.charCodeAt(0) === UNDERSCORE.charCodeAt(0); +} +function memberIsPrivate(node: ts.Declaration) { + return Lint.hasModifier(node.modifiers, ts.SyntaxKind.PrivateKeyword); +} +function nameIsIdentifier(node: ts.Node): node is ts.Identifier { + return node.kind === ts.SyntaxKind.Identifier; +} diff --git a/packages/tslint-config/rules/walkers/async_suffix.ts b/packages/tslint-config/rules/walkers/async_suffix.ts new file mode 100644 index 000000000..eaec9c5f6 --- /dev/null +++ b/packages/tslint-config/rules/walkers/async_suffix.ts @@ -0,0 +1,26 @@ +import * as _ from 'lodash'; +import * as Lint from 'tslint'; +import * as ts from 'typescript'; + +export class AsyncSuffixWalker extends Lint.RuleWalker { + public static FAILURE_STRING = 'async functions must have an Async suffix'; + public visitMethodDeclaration(node: ts.MethodDeclaration): void { + const methodNameNode = node.name; + const methodName = methodNameNode.getText(); + if (!_.isUndefined(node.type)) { + if (node.type.kind === ts.SyntaxKind.TypeReference) { + // tslint:disable-next-line:no-unnecessary-type-assertion + const returnTypeName = (node.type as ts.TypeReferenceNode).typeName.getText(); + if (returnTypeName === 'Promise' && !methodName.endsWith('Async')) { + const failure = this.createFailure( + methodNameNode.getStart(), + methodNameNode.getWidth(), + AsyncSuffixWalker.FAILURE_STRING, + ); + this.addFailure(failure); + } + } + } + super.visitMethodDeclaration(node); + } +} diff --git a/packages/tslint-config/tsconfig.json b/packages/tslint-config/tsconfig.json new file mode 100644 index 000000000..15da53092 --- /dev/null +++ b/packages/tslint-config/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig", + "compilerOptions": { + "outDir": "lib" + }, + "include": ["./rules/**/*"] +} diff --git a/packages/tslint-config/tslint.json b/packages/tslint-config/tslint.json index 0921a3954..971588b08 100644 --- a/packages/tslint-config/tslint.json +++ b/packages/tslint-config/tslint.json @@ -1,105 +1,101 @@ { - "extends": [ - "tslint:latest", - "tslint-react" - ], - "rules": { - "adjacent-overload-signatures": true, - "arrow-parens": [true, "ban-single-arg-parens"], - "arrow-return-shorthand": true, - "await-promise": true, - "binary-expression-operand-order": true, - "callable-types": true, - "class-name": true, - "completed-docs": [ - true, - { - "functions": {"visibilities": ["exported"]}, - "methods": {"locations": "instance", "privacies": ["public", "protected"]} - } - ], - "curly": true, - "eofline": true, - "encoding": true, - "import-spacing": true, - "indent": [true, "spaces", 4], - "interface-name": false, - "interface-over-type-literal": true, - "linebreak-style": [true, "LF"], - "max-classes-per-file": false, - "max-classes-per-file": [true, 1], - "max-file-line-count": [true, 500], - "max-line-length": [true, 120], - "member-access": true, - "member-ordering": [true, - "public-before-private", - "static-before-instance", - "variables-before-functions" - ], - "newline-before-return": false, - "new-parens": true, - "no-angle-bracket-type-assertion": true, - "no-boolean-literal-compare": true, - "no-default-export": true, - "no-empty-interface": false, - "no-floating-promises": true, - "no-non-null-assertion": true, - "no-parameter-reassignment": true, - "no-redundant-jsdoc": true, - "no-return-await": true, - "no-string-throw": true, - "no-submodule-imports": false, - "no-unnecessary-type-assertion": true, - "no-implicit-dependencies": [true, "dev"], - "number-literal-format": true, - "object-literal-sort-keys": false, - "ordered-imports": [ - true, - { - "grouped-imports": true - } - ], - "prefer-const": true, - "prefer-for-of": true, - "prefer-function-over-method": true, - "promise-function-async": true, - "quotemark": [true, "single", "avoid-escape", "jsx-double"], - "semicolon": [true, "always"], - "space-before-function-paren": [ - true, - { - "anonymous": "never", - "named": "never", - "method": "never", - "constructor": "never", - "asyncArrow": "always" - } - ], - "space-within-parens": false, - "type-literal-delimiter": true, - "variable-name": [true, - "ban-keywords", - "allow-pascal-case" - ], - "whitespace": [ - true, - "check-branch", - "check-decl", - "check-operator", - "check-separator", - "check-rest-spread", - "check-type", - "check-typecast", - "check-preblock" - ], - "jsx-alignment": true, - "jsx-boolean-value": true, - "jsx-curly-spacing": [true, "never"], - "jsx-no-lambda": true, - "jsx-no-multiline-js": false, - "jsx-no-string-ref": true, - "jsx-self-close": true, - "jsx-wrap-multiline": false, - "jsx-no-bind": false - } + "extends": ["tslint:latest", "tslint-react", "tslint-eslint-rules"], + "rules": { + "adjacent-overload-signatures": true, + "arrow-parens": [true, "ban-single-arg-parens"], + "arrow-return-shorthand": true, + "async-suffix": true, + "await-promise": true, + "binary-expression-operand-order": true, + "callable-types": true, + "class-name": true, + "completed-docs": [ + true, + { + "functions": { "visibilities": ["exported"] }, + "methods": { "locations": "instance", "privacies": ["public", "protected"] } + } + ], + "curly": true, + "eofline": true, + "encoding": true, + "import-spacing": true, + "indent": [true, "spaces", 4], + "interface-name": false, + "interface-over-type-literal": true, + "linebreak-style": [true, "LF"], + "max-classes-per-file": false, + "max-classes-per-file": [true, 1], + "max-line-length": false, + "max-file-line-count": [true, 500], + "member-access": true, + "member-ordering": [true, "public-before-private", "static-before-instance", "variables-before-functions"], + "newline-before-return": false, + "new-parens": true, + "no-angle-bracket-type-assertion": true, + "no-boolean-literal-compare": true, + "no-default-export": true, + "no-empty-interface": false, + "no-floating-promises": true, + "no-non-null-assertion": true, + "no-parameter-reassignment": true, + "no-redundant-jsdoc": true, + "no-return-await": true, + "no-string-throw": true, + "no-submodule-imports": false, + "no-unnecessary-type-assertion": true, + "no-unused-variable": [true, { "ignore-pattern": "^_\\d*" }], + "no-implicit-dependencies": [true, "dev"], + "number-literal-format": true, + "object-literal-sort-keys": false, + "object-literal-key-quotes": false, + "ordered-imports": [ + true, + { + "grouped-imports": true + } + ], + "prefer-const": true, + "prefer-for-of": true, + "prefer-function-over-method": true, + "promise-function-async": true, + "quotemark": [true, "single", "avoid-escape", "jsx-double"], + "restrict-plus-operands": true, + "semicolon": [true, "always"], + "space-before-function-paren": [ + true, + { + "anonymous": "never", + "named": "never", + "method": "never", + "constructor": "never", + "asyncArrow": "always" + } + ], + "space-within-parens": false, + "type-literal-delimiter": true, + "underscore-privates": true, + "variable-name": [true, "ban-keywords", "allow-pascal-case"], + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-rest-spread", + "check-type", + "check-typecast", + "check-preblock" + ], + "jsx-alignment": true, + "jsx-boolean-value": true, + "jsx-curly-spacing": [true, "never"], + "jsx-no-lambda": true, + "jsx-no-multiline-js": false, + "jsx-no-string-ref": true, + "jsx-self-close": true, + "jsx-wrap-multiline": false, + "jsx-no-bind": false + }, + "rulesDirectory": "lib" } diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md new file mode 100644 index 000000000..899482c4c --- /dev/null +++ b/packages/types/CHANGELOG.md @@ -0,0 +1,3 @@ +# CHANGELOG + +## vx.x.x diff --git a/packages/types/README.md b/packages/types/README.md index d4d48b1fe..d63970150 100644 --- a/packages/types/README.md +++ b/packages/types/README.md @@ -1,10 +1,47 @@ -0x types ------- +## @0xproject/types -TS types shared across 0x projects and packages +Typescript types shared across 0x projects and packages -## Install +## Installation ```bash yarn add -D @0xproject/types ``` + +## Usage + +```javascript +import { TransactionReceipt, TxData, TxDataPayable } from '@0xproject/types'; +``` + +## Contributing + +We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. + +Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. + +### Install Dependencies + +If you don't have yarn workspaces e`nabled (Yarn < v1.0) - enable them: + +```bash +yarn config set workspaces-experimental true +``` + +Then install dependencies + +```bash +yarn install +``` + +### Build + +```bash +yarn build +``` + +### Lint + +```bash +yarn lint +``` diff --git a/packages/types/package.json b/packages/types/package.json index f55be284e..8a8244950 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,32 +1,31 @@ { - "name": "@0xproject/types", - "version": "0.0.1", - "description": "0x types", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "scripts": { - "build": "tsc", - "clean": "shx rm -rf lib", - "lint": "tslint --project . 'src/**/*.ts'" - }, - "license": "Apache-2.0", - "repository": { - "type": "git", - "url": "https://github.com/0xProject/0x.js.git" - }, - "bugs": { - "url": "https://github.com/0xProject/0x.js/issues" - }, - "homepage": "https://github.com/0xProject/0x.js/packages/types/README.md", - "devDependencies": { - "@0xproject/tslint-config": "^0.2.0", - "bignumber.js": "^5.0.0", - "shx": "^0.2.2", - "tslint": "5.8.0", - "typescript": "~2.6.1" - }, - "dependencies": { - "bignumber.js": "~4.1.0", - "web3": "^0.20.0" - } + "name": "@0xproject/types", + "version": "0.1.5", + "description": "0x types", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "scripts": { + "build": "tsc", + "clean": "shx rm -rf lib", + "lint": "tslint --project . 'src/**/*.ts'" + }, + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/0xProject/0x.js.git" + }, + "bugs": { + "url": "https://github.com/0xProject/0x.js/issues" + }, + "homepage": "https://github.com/0xProject/0x.js/packages/types/README.md", + "devDependencies": { + "@0xproject/tslint-config": "^0.4.3", + "shx": "^0.2.2", + "tslint": "5.8.0", + "typescript": "~2.6.1" + }, + "dependencies": { + "@0xproject/utils": "^0.2.1", + "web3": "^0.20.0" + } } diff --git a/packages/types/scripts/postpublish.js b/packages/types/scripts/postpublish.js new file mode 100644 index 000000000..7fa452b08 --- /dev/null +++ b/packages/types/scripts/postpublish.js @@ -0,0 +1,14 @@ +const postpublish_utils = require('../../../scripts/postpublish_utils'); +const packageJSON = require('../package.json'); + +const subPackageName = packageJSON.name; + +postpublish_utils.getLatestTagAndVersionAsync(subPackageName) + .then(function(result) { + const releaseName = postpublish_utils.getReleaseName(subPackageName, result.version); + const assets = []; + return postpublish_utils.publishReleaseNotes(result.tag, releaseName, assets); + }) + .catch (function(err) { + throw err; + }); diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 8d69af63d..9cf9bc7af 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -1,4 +1,4 @@ -import {BigNumber} from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as Web3 from 'web3'; export interface TxData { @@ -8,6 +8,10 @@ export interface TxData { nonce?: number; } +export interface TxDataPayable extends TxData { + value?: BigNumber; +} + export interface TransactionReceipt { blockHash: string; blockNumber: number; @@ -15,9 +19,9 @@ export interface TransactionReceipt { transactionIndex: number; from: string; to: string; - status: null|0|1; + status: null | 0 | 1; cumulativeGasUsed: number; gasUsed: number; - contractAddress: string|null; + contractAddress: string | null; logs: Web3.LogEntry[]; } diff --git a/packages/types/tsconfig.json b/packages/types/tsconfig.json index de186cfc4..3d967d05f 100644 --- a/packages/types/tsconfig.json +++ b/packages/types/tsconfig.json @@ -1,16 +1,7 @@ { - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "lib": [ "es2017", "dom"], - "outDir": "lib", - "sourceMap": true, - "declaration": true, - "noImplicitAny": true, - "strictNullChecks": true - }, - "include": [ - "./src/**/*", - "../../node_modules/web3-typescript-typings/index.d.ts" - ] + "extends": "../../tsconfig", + "compilerOptions": { + "outDir": "lib" + }, + "include": ["./src/**/*", "../../node_modules/web3-typescript-typings/index.d.ts"] } diff --git a/packages/types/tslint.json b/packages/types/tslint.json index a07795151..ffaefe83a 100644 --- a/packages/types/tslint.json +++ b/packages/types/tslint.json @@ -1,5 +1,3 @@ { - "extends": [ - "@0xproject/tslint-config" - ] + "extends": ["@0xproject/tslint-config"] } diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md new file mode 100644 index 000000000..efee30dd1 --- /dev/null +++ b/packages/utils/CHANGELOG.md @@ -0,0 +1,6 @@ +# CHANGELOG + +## v0.2.0 - _January 17, 2018_ + +* Add `onError` parameter to `intervalUtils.setAsyncExcludingInterval` (#312) +* Add `intervalUtils.setInterval` (#312) diff --git a/packages/utils/README.md b/packages/utils/README.md index 5191e0350..d6cacfa11 100644 --- a/packages/utils/README.md +++ b/packages/utils/README.md @@ -1,10 +1,47 @@ -utils ------- +## @0xproject/utils Utils to be shared across 0x projects and packages -## Install +## Installation ```bash yarn add @0xproject/utils ``` + +## Usage + +```javascript +import { addressUtils, bigNumberConfigs, classUtils, intervalUtils, promisify } from '@0xproject/utils'; +``` + +## Contributing + +We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. + +Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. + +### Install Dependencies + +If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: + +```bash +yarn config set workspaces-experimental true +``` + +Then install dependencies + +```bash +yarn install +``` + +### Build + +```bash +yarn build +``` + +### Lint + +```bash +yarn lint +``` diff --git a/packages/utils/package.json b/packages/utils/package.json index f49a95f28..b1f8b3792 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,33 +1,34 @@ { - "name": "@0xproject/utils", - "version": "0.0.1", - "description": "0x TS utils", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "scripts": { - "build": "tsc", - "clean": "shx rm -rf lib", - "lint": "tslint --project . 'src/**/*.ts'" - }, - "license": "Apache-2.0", - "repository": { - "type": "git", - "url": "https://github.com/0xProject/0x.js.git" - }, - "bugs": { - "url": "https://github.com/0xProject/0x.js/issues" - }, - "homepage": "https://github.com/0xProject/0x.js/packages/utils/README.md", - "devDependencies": { - "@0xproject/tslint-config": "^0.2.0", - "@types/lodash": "^4.14.86", - "npm-run-all": "^4.1.2", - "shx": "^0.2.2", - "tslint": "5.8.0", - "typescript": "~2.6.1" - }, - "dependencies": { - "bignumber.js": "~4.1.0", - "lodash": "^4.17.4" - } + "name": "@0xproject/utils", + "version": "0.2.1", + "description": "0x TS utils", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "scripts": { + "build": "tsc", + "clean": "shx rm -rf lib", + "lint": "tslint --project . 'src/**/*.ts'" + }, + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/0xProject/0x.js.git" + }, + "bugs": { + "url": "https://github.com/0xProject/0x.js/issues" + }, + "homepage": "https://github.com/0xProject/0x.js/packages/utils/README.md", + "devDependencies": { + "@0xproject/tslint-config": "^0.4.3", + "@types/lodash": "^4.14.86", + "npm-run-all": "^4.1.2", + "shx": "^0.2.2", + "tslint": "5.8.0", + "typescript": "~2.6.1" + }, + "dependencies": { + "bignumber.js": "~4.1.0", + "js-sha3": "^0.7.0", + "lodash": "^4.17.4" + } } diff --git a/packages/utils/scripts/postpublish.js b/packages/utils/scripts/postpublish.js new file mode 100644 index 000000000..7fa452b08 --- /dev/null +++ b/packages/utils/scripts/postpublish.js @@ -0,0 +1,14 @@ +const postpublish_utils = require('../../../scripts/postpublish_utils'); +const packageJSON = require('../package.json'); + +const subPackageName = packageJSON.name; + +postpublish_utils.getLatestTagAndVersionAsync(subPackageName) + .then(function(result) { + const releaseName = postpublish_utils.getReleaseName(subPackageName, result.version); + const assets = []; + return postpublish_utils.publishReleaseNotes(result.tag, releaseName, assets); + }) + .catch (function(err) { + throw err; + }); diff --git a/packages/utils/src/address_utils.ts b/packages/utils/src/address_utils.ts new file mode 100644 index 000000000..f94985441 --- /dev/null +++ b/packages/utils/src/address_utils.ts @@ -0,0 +1,36 @@ +import * as jsSHA3 from 'js-sha3'; + +const BASIC_ADDRESS_REGEX = /^(0x)?[0-9a-f]{40}$/i; +const SAME_CASE_ADDRESS_REGEX = /^(0x)?([0-9a-f]{40}|[0-9A-F]{40})$/; + +export const addressUtils = { + isChecksumAddress(address: string): boolean { + // Check each case + const unprefixedAddress = address.replace('0x', ''); + const addressHash = jsSHA3.keccak256(unprefixedAddress.toLowerCase()); + + for (let i = 0; i < 40; i++) { + // The nth letter should be uppercase if the nth digit of casemap is 1 + if ( + (parseInt(addressHash[i], 16) > 7 && unprefixedAddress[i].toUpperCase() !== unprefixedAddress[i]) || + (parseInt(addressHash[i], 16) <= 7 && unprefixedAddress[i].toLowerCase() !== unprefixedAddress[i]) + ) { + return false; + } + } + return true; + }, + isAddress(address: string): boolean { + if (!BASIC_ADDRESS_REGEX.test(address)) { + // Check if it has the basic requirements of an address + return false; + } else if (SAME_CASE_ADDRESS_REGEX.test(address)) { + // If it's all small caps or all all caps, return true + return true; + } else { + // Otherwise check each case + const isValidChecksummedAddress = addressUtils.isChecksumAddress(address); + return isValidChecksummedAddress; + } + }, +}; diff --git a/packages/0x.js/src/utils/class_utils.ts b/packages/utils/src/class_utils.ts index 04e60ee57..04e60ee57 100644 --- a/packages/0x.js/src/utils/class_utils.ts +++ b/packages/utils/src/class_utils.ts diff --git a/packages/utils/src/configured_bignumber.ts b/packages/utils/src/configured_bignumber.ts new file mode 100644 index 000000000..e44c062c2 --- /dev/null +++ b/packages/utils/src/configured_bignumber.ts @@ -0,0 +1,9 @@ +import { BigNumber } from 'bignumber.js'; + +// 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, +}); + +export { BigNumber }; diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index a61f04ad2..2768e49ab 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -1 +1,5 @@ -export {promisify} from './promisify'; +export { promisify } from './promisify'; +export { addressUtils } from './address_utils'; +export { classUtils } from './class_utils'; +export { intervalUtils } from './interval_utils'; +export { BigNumber } from './configured_bignumber'; diff --git a/packages/utils/src/interval_utils.ts b/packages/utils/src/interval_utils.ts new file mode 100644 index 000000000..ebecc7015 --- /dev/null +++ b/packages/utils/src/interval_utils.ts @@ -0,0 +1,37 @@ +import * as _ from 'lodash'; + +export const intervalUtils = { + setAsyncExcludingInterval(fn: () => Promise<void>, intervalMs: number, onError: (err: Error) => void) { + let locked = false; + const intervalId = setInterval(async () => { + if (locked) { + return; + } else { + locked = true; + try { + await fn(); + } catch (err) { + onError(err); + } + locked = false; + } + }, intervalMs); + return intervalId; + }, + clearAsyncExcludingInterval(intervalId: NodeJS.Timer): void { + clearInterval(intervalId); + }, + setInterval(fn: () => void, intervalMs: number, onError: (err: Error) => void) { + const intervalId = setInterval(() => { + try { + fn(); + } catch (err) { + onError(err); + } + }, intervalMs); + return intervalId; + }, + clearInterval(intervalId: NodeJS.Timer): void { + clearInterval(intervalId); + }, +}; diff --git a/packages/utils/src/promisify.ts b/packages/utils/src/promisify.ts index c114cf32f..29d626b61 100644 --- a/packages/utils/src/promisify.ts +++ b/packages/utils/src/promisify.ts @@ -5,16 +5,11 @@ import * as _ from 'lodash'; * Promisify provides a default callback of the form (error, result) and rejects when `error` is not null. You can also * supply thisArg object as the second argument which will be passed to `apply`. */ -export function promisify<T>( - originalFn: ( - ...args: any[], - // HACK: This can't be properly typed without variadic kinds https://github.com/Microsoft/TypeScript/issues/5453 - ) => void, - thisArg?: any, -): (...callArgs: any[]) => Promise<T> { +// HACK: This can't be properly typed without variadic kinds https://github.com/Microsoft/TypeScript/issues/5453 +export function promisify<T>(originalFn: (...args: any[]) => void, thisArg?: any): (...callArgs: any[]) => Promise<T> { const promisifiedFunction = async (...callArgs: any[]): Promise<T> => { return new Promise<T>((resolve, reject) => { - const callback = (err: Error|null, data?: T) => { + const callback = (err: Error | null, data?: T) => { _.isNull(err) ? resolve(data) : reject(err); }; originalFn.apply(thisArg, [...callArgs, callback]); diff --git a/packages/utils/tsconfig.json b/packages/utils/tsconfig.json index 111df6d3b..3d967d05f 100644 --- a/packages/utils/tsconfig.json +++ b/packages/utils/tsconfig.json @@ -1,15 +1,7 @@ { - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "lib": [ "es2017", "dom"], - "outDir": "lib", - "sourceMap": true, - "declaration": true, - "noImplicitAny": true, - "strictNullChecks": true - }, - "include": [ - "./src/**/*" - ] + "extends": "../../tsconfig", + "compilerOptions": { + "outDir": "lib" + }, + "include": ["./src/**/*", "../../node_modules/web3-typescript-typings/index.d.ts"] } diff --git a/packages/utils/tslint.json b/packages/utils/tslint.json index a07795151..ffaefe83a 100644 --- a/packages/utils/tslint.json +++ b/packages/utils/tslint.json @@ -1,5 +1,3 @@ { - "extends": [ - "@0xproject/tslint-config" - ] + "extends": ["@0xproject/tslint-config"] } diff --git a/packages/web3-typescript-typings/.gitignore b/packages/web3-typescript-typings/.gitignore new file mode 100644 index 000000000..85dcc16df --- /dev/null +++ b/packages/web3-typescript-typings/.gitignore @@ -0,0 +1,2 @@ +.git +node_modules diff --git a/packages/web3-typescript-typings/CHANGELOG.md b/packages/web3-typescript-typings/CHANGELOG.md new file mode 100644 index 000000000..46f70d864 --- /dev/null +++ b/packages/web3-typescript-typings/CHANGELOG.md @@ -0,0 +1,6 @@ +# CHANGELOG + +## v0.9.3 - _January 11, 2018_ + +* Add type for getData on a contract +* Fixed the `defaultAccount` not allowing for `undefined` value (#320) diff --git a/packages/web3-typescript-typings/README.md b/packages/web3-typescript-typings/README.md new file mode 100644 index 000000000..95c193287 --- /dev/null +++ b/packages/web3-typescript-typings/README.md @@ -0,0 +1,49 @@ +## web3-typescript-typings + +There currently isn't an official [Web3][web3] +type definition included in the [DefinitelyTyped][definitelytyped] project. +Until that happens, we will continue to improve our own type definition. +If it get's close to comprehensive, we'll add it to [DefinitelyTyped][definitelytyped]. + +[web3]: https://github.com/ethereum/web3.js/ +[definitelytyped]: https://github.com/DefinitelyTyped/DefinitelyTyped + +## Installation + +```bash +yarn add -D web3-typescript-typings +``` + +## Usage + +Add the following line within an `include` section of your `tsconfig.json` + +```json +"./node_modules/web3-typescript-typings/index.d.ts" +``` + +## Contributing + +We strongly encourage that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. + +Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. + +### Install Dependencies + +If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: + +```bash +yarn config set workspaces-experimental true +``` + +Then install dependencies + +```bash +yarn install +``` + +### Lint + +```bash +yarn lint +``` diff --git a/packages/web3-typescript-typings/index.d.ts b/packages/web3-typescript-typings/index.d.ts new file mode 100644 index 000000000..ff379cb3d --- /dev/null +++ b/packages/web3-typescript-typings/index.d.ts @@ -0,0 +1,422 @@ +declare module 'web3' { + import * as BigNumber from 'bignumber.js'; + + type MixedData = string | number | object | any[] | BigNumber.BigNumber; + + class Web3 { + public static providers: typeof providers; + public currentProvider: Web3.Provider; + + public eth: Web3.EthApi; + public personal: Web3.PersonalApi | undefined; + public version: Web3.VersionApi; + public net: Web3.NetApi; + + public constructor(provider?: Web3.Provider); + + public isConnected(): boolean; + public setProvider(provider: Web3.Provider): void; + public reset(keepIsSyncing: boolean): void; + public toHex(data: MixedData): string; + public toAscii(hex: string): string; + public fromAscii(ascii: string, padding?: number): string; + public toDecimal(hex: string): number; + public fromDecimal(value: number | string): string; + public fromWei(value: number | string, unit: Web3.Unit): string; + public fromWei(value: BigNumber.BigNumber, unit: Web3.Unit): BigNumber.BigNumber; + public toWei(amount: number | string, unit: Web3.Unit): string; + public toWei(amount: BigNumber.BigNumber, unit: Web3.Unit): BigNumber.BigNumber; + public toBigNumber(value: number | string): BigNumber.BigNumber; + public isAddress(address: string): boolean; + public isChecksumAddress(address: string): boolean; + public sha3(value: string, options?: Web3.Sha3Options): string; + } + + namespace providers { + class HttpProvider implements Web3.Provider { + constructor(url?: string, timeout?: number, username?: string, password?: string); + public sendAsync( + payload: Web3.JSONRPCRequestPayload, + callback: (err: Error, result: Web3.JSONRPCResponsePayload) => void, + ): void; + } + } + + namespace Web3 { + type ContractAbi = AbiDefinition[]; + + type AbiDefinition = FunctionAbi | EventAbi; + + type FunctionAbi = MethodAbi | ConstructorAbi | FallbackAbi; + + enum AbiType { + Function = 'function', + Constructor = 'constructor', + Event = 'event', + Fallback = 'fallback', + } + + type ConstructorStateMutability = 'nonpayable' | 'payable'; + type StateMutability = 'pure' | 'view' | ConstructorStateMutability; + + interface MethodAbi { + type: AbiType.Function; + name: string; + inputs: FunctionParameter[]; + outputs: FunctionParameter[]; + constant: boolean; + stateMutability: StateMutability; + payable: boolean; + } + + interface ConstructorAbi { + type: AbiType.Constructor; + inputs: FunctionParameter[]; + payable: boolean; + stateMutability: ConstructorStateMutability; + } + + interface FallbackAbi { + type: AbiType.Fallback; + payable: boolean; + } + + interface EventParameter { + name: string; + type: string; + indexed: boolean; + } + + interface EventAbi { + type: AbiType.Event; + name: string; + inputs: EventParameter[]; + anonymous: boolean; + } + + interface FunctionParameter { + name: string; + type: string; + } + + interface ContractInstance { + address: string; + abi: Web3.ContractAbi; + [name: string]: any; + } + + interface Contract<A extends ContractInstance> { + at(address: string): A; + getData(...args: any[]): string; + 'new'(...args: any[]): A; + } + + interface FilterObject { + fromBlock?: number | string; + toBlock?: number | string; + address?: string; + topics?: LogTopic[]; + } + + type LogTopic = null | string | string[]; + + interface DecodedLogEntry<A> extends LogEntry { + event: string; + args: A; + } + + interface DecodedLogEntryEvent<A> extends DecodedLogEntry<A> { + removed: boolean; + } + + interface LogEntryEvent extends LogEntry { + removed: boolean; + } + + interface FilterResult { + get(callback: () => void): void; + watch(callback: (err: Error, result: LogEntryEvent) => void): void; + stopWatching(callback?: () => void): void; + } + + export interface JSONRPCRequestPayload { + params: any[]; + method: string; + id: number; + jsonrpc: string; + } + + export interface JSONRPCResponsePayload { + result: any; + id: number; + jsonrpc: string; + } + + interface Provider { + sendAsync( + payload: JSONRPCRequestPayload, + callback: (err: Error, result: JSONRPCResponsePayload) => void, + ): void; + } + + interface Sha3Options { + encoding: 'hex'; + } + + interface EthApi { + coinbase: string; + mining: boolean; + hashrate: number; + gasPrice: BigNumber.BigNumber; + accounts: string[]; + blockNumber: number; + defaultAccount?: string; + defaultBlock: Web3.BlockParam; + syncing: Web3.SyncingResult; + compile: { + solidity(sourceString: string, cb?: (err: Error, result: any) => void): object; + }; + getMining(cd: (err: Error, mining: boolean) => void): void; + getHashrate(cd: (err: Error, hashrate: number) => void): void; + getGasPrice(cd: (err: Error, gasPrice: BigNumber.BigNumber) => void): void; + getAccounts(cd: (err: Error, accounts: string[]) => void): void; + getBlockNumber(callback: (err: Error, blockNumber: number) => void): void; + getSyncing(cd: (err: Error, syncing: Web3.SyncingResult) => void): void; + isSyncing(cb: (err: Error, isSyncing: boolean, syncingState: Web3.SyncingState) => void): Web3.IsSyncing; + + getBlock(hashStringOrBlockNumber: string | Web3.BlockParam): Web3.BlockWithoutTransactionData; + getBlock( + hashStringOrBlockNumber: string | Web3.BlockParam, + callback: (err: Error, blockObj: Web3.BlockWithoutTransactionData) => void, + ): void; + getBlock( + hashStringOrBlockNumber: string | Web3.BlockParam, + returnTransactionObjects: true, + ): Web3.BlockWithTransactionData; + getBlock( + hashStringOrBlockNumber: string | Web3.BlockParam, + returnTransactionObjects: true, + callback: (err: Error, blockObj: Web3.BlockWithTransactionData) => void, + ): void; + + getBlockTransactionCount(hashStringOrBlockNumber: string | Web3.BlockParam): number; + getBlockTransactionCount( + hashStringOrBlockNumber: string | Web3.BlockParam, + callback: (err: Error, blockTransactionCount: number) => void, + ): void; + + // TODO returnTransactionObjects + getUncle( + hashStringOrBlockNumber: string | Web3.BlockParam, + uncleNumber: number, + ): Web3.BlockWithoutTransactionData; + getUncle( + hashStringOrBlockNumber: string | Web3.BlockParam, + uncleNumber: number, + callback: (err: Error, uncle: Web3.BlockWithoutTransactionData) => void, + ): void; + + getTransaction(transactionHash: string): Web3.Transaction; + getTransaction( + transactionHash: string, + callback: (err: Error, transaction: Web3.Transaction) => void, + ): void; + + getTransactionFromBlock( + hashStringOrBlockNumber: string | Web3.BlockParam, + indexNumber: number, + ): Web3.Transaction; + getTransactionFromBlock( + hashStringOrBlockNumber: string | Web3.BlockParam, + indexNumber: number, + callback: (err: Error, transaction: Web3.Transaction) => void, + ): void; + + contract(abi: Web3.AbiDefinition[]): Web3.Contract<any>; + + // TODO block param + getBalance(addressHexString: string): BigNumber.BigNumber; + getBalance(addressHexString: string, callback: (err: Error, result: BigNumber.BigNumber) => void): void; + + // TODO block param + getStorageAt(address: string, position: number): string; + getStorageAt(address: string, position: number, callback: (err: Error, storage: string) => void): void; + + // TODO block param + getCode(addressHexString: string): string; + getCode(addressHexString: string, callback: (err: Error, code: string) => void): void; + + filter(value: string | Web3.FilterObject): Web3.FilterResult; + + sendTransaction(txData: Web3.TxData): string; + sendTransaction(txData: Web3.TxData, callback: (err: Error, value: string) => void): void; + + sendRawTransaction(rawTxData: string): string; + sendRawTransaction(rawTxData: string, callback: (err: Error, value: string) => void): void; + + sign(address: string, data: string): string; + sign(address: string, data: string, callback: (err: Error, signature: string) => void): void; + + getTransactionReceipt(txHash: string): Web3.TransactionReceipt; + getTransactionReceipt( + txHash: string, + callback: (err: Error, receipt: Web3.TransactionReceipt) => void, + ): void; + + // TODO block param + call(callData: Web3.CallData): string; + call(callData: Web3.CallData, callback: (err: Error, result: string) => void): void; + + estimateGas(callData: Web3.CallData): number; + estimateGas(callData: Web3.CallData, callback: (err: Error, gas: number) => void): void; + + // TODO defaultBlock + getTransactionCount(address: string): number; + getTransactionCount(address: string, callback: (err: Error, count: number) => void): void; + } + + interface VersionApi { + api: string; + network: string; + node: string; + ethereum: string; + whisper: string; + getNetwork(cd: (err: Error, networkId: string) => void): void; + getNode(cd: (err: Error, nodeVersion: string) => void): void; + getEthereum(cd: (err: Error, ethereum: string) => void): void; + getWhisper(cd: (err: Error, whisper: string) => void): void; + } + + interface PersonalApi { + listAccounts: string[] | undefined; + newAccount(password?: string): string; + unlockAccount(address: string, password?: string, duration?: number): boolean; + lockAccount(address: string): boolean; + sign(message: string, account: string, password: string): string; + sign(hexMessage: string, account: string, callback: (error: Error, signature: string) => void): void; + } + + interface NetApi { + listening: boolean; + peerCount: boolean; + getListening(cd: (err: Error, listening: boolean) => void): void; + getPeerCount(cd: (err: Error, peerCount: number) => void): void; + } + + type BlockParam = number | 'earliest' | 'latest' | 'pending'; + + type Unit = + | 'kwei' + | 'ada' + | 'mwei' + | 'babbage' + | 'gwei' + | 'shannon' + | 'szabo' + | 'finney' + | 'ether' + | 'kether' + | 'grand' + | 'einstein' + | 'mether' + | 'gether' + | 'tether'; + + interface SyncingState { + startingBlock: number; + currentBlock: number; + highestBlock: number; + } + type SyncingResult = false | SyncingState; + + interface IsSyncing { + addCallback(cb: (err: Error, isSyncing: boolean, syncingState: SyncingState) => void): void; + stopWatching(): void; + } + + interface AbstractBlock { + number: number | null; + hash: string | null; + parentHash: string; + nonce: string | null; + sha3Uncles: string; + logsBloom: string | null; + transactionsRoot: string; + stateRoot: string; + miner: string; + difficulty: BigNumber.BigNumber; + totalDifficulty: BigNumber.BigNumber; + extraData: string; + size: number; + gasLimit: number; + gasUsed: number; + timestamp: number; + uncles: string[]; + } + interface BlockWithoutTransactionData extends AbstractBlock { + transactions: string[]; + } + interface BlockWithTransactionData extends AbstractBlock { + transactions: Transaction[]; + } + + interface Transaction { + hash: string; + nonce: number; + blockHash: string | null; + blockNumber: number | null; + transactionIndex: number | null; + from: string; + to: string | null; + value: BigNumber.BigNumber; + gasPrice: BigNumber.BigNumber; + gas: number; + input: string; + } + + interface CallTxDataBase { + to?: string; + value?: number | string | BigNumber.BigNumber; + gas?: number | string | BigNumber.BigNumber; + gasPrice?: number | string | BigNumber.BigNumber; + data?: string; + nonce?: number; + } + + interface TxData extends CallTxDataBase { + from: string; + } + + interface CallData extends CallTxDataBase { + from?: string; + } + + interface TransactionReceipt { + blockHash: string; + blockNumber: number; + transactionHash: string; + transactionIndex: number; + from: string; + to: string; + status: null | string | 0 | 1; + cumulativeGasUsed: number; + gasUsed: number; + contractAddress: string | null; + logs: LogEntry[]; + } + + interface LogEntry { + logIndex: number | null; + transactionIndex: number | null; + transactionHash: string; + blockHash: string | null; + blockNumber: number | null; + address: string; + data: string; + topics: string[]; + } + } + /* tslint:disable */ + export = Web3; + /* tslint:enable */ +} diff --git a/packages/web3-typescript-typings/package.json b/packages/web3-typescript-typings/package.json new file mode 100644 index 000000000..6dddf22aa --- /dev/null +++ b/packages/web3-typescript-typings/package.json @@ -0,0 +1,32 @@ +{ + "name": "web3-typescript-typings", + "version": "0.9.5", + "description": "Typescript type definitions for web3", + "main": "index.d.ts", + "types": "index.d.ts", + "scripts": { + "lint": "tslint index.d.ts" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/0xProject/0x.js.git" + }, + "author": "Fabio Berger", + "contributors": [ + "Leonid Logvinov <logvinov.leon@gmail.com>" + ], + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/0xProject/0x.js/issues" + }, + "homepage": "https://github.com/0xProject/0x.js/packages/web3-typescript-typings#readme", + "devDependencies": { + "@types/bignumber.js": "^4.0.2", + "tslint": "^5.5.0", + "tslint-config-0xproject": "^0.0.2", + "typescript": "~2.6.1" + }, + "dependencies": { + "bignumber.js": "~4.1.0" + } +} diff --git a/packages/web3-typescript-typings/scripts/postpublish.js b/packages/web3-typescript-typings/scripts/postpublish.js new file mode 100644 index 000000000..16d67e03f --- /dev/null +++ b/packages/web3-typescript-typings/scripts/postpublish.js @@ -0,0 +1,15 @@ +const postpublish_utils = require('../../../scripts/postpublish_utils'); +const packageJSON = require('../package.json'); + +const subPackageName = packageJSON.name; + +postpublish_utils + .getLatestTagAndVersionAsync(subPackageName) + .then(function(result) { + const releaseName = postpublish_utils.getReleaseName(subPackageName, result.version); + const assets = []; + return postpublish_utils.publishReleaseNotes(result.tag, releaseName, assets); + }) + .catch(function(err) { + throw err; + }); diff --git a/packages/web3-typescript-typings/tslint.json b/packages/web3-typescript-typings/tslint.json new file mode 100644 index 000000000..9a93a1f74 --- /dev/null +++ b/packages/web3-typescript-typings/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": ["tslint-config-0xproject"] +} diff --git a/packages/web3-typescript-typings/yarn.lock b/packages/web3-typescript-typings/yarn.lock new file mode 100644 index 000000000..f1d0f843a --- /dev/null +++ b/packages/web3-typescript-typings/yarn.lock @@ -0,0 +1,197 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/bignumber.js@^4.0.2": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/bignumber.js/-/bignumber.js-4.0.2.tgz#22a16946c9faa9f2c9c0ad4c7c3734a3033320ae" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +babel-code-frame@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" + dependencies: + chalk "^1.1.0" + esutils "^2.0.2" + js-tokens "^3.0.0" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +bignumber.js@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-4.0.2.tgz#2d1dc37ee5968867ecea90b6da4d16e68608d21d" + +brace-expansion@^1.1.7: + version "1.1.8" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +chalk@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +colors@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" + +commander@^2.9.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +diff@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.0.tgz#056695150d7aa93237ca7e378ac3b1682b7963b9" + +escape-string-regexp@^1.0.2: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +glob@^7.1.1: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +js-tokens@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-parse@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + +resolve@^1.3.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5" + dependencies: + path-parse "^1.0.5" + +semver@^5.3.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" + +strip-ansi@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +tslib@^1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.7.1.tgz#bc8004164691923a79fe8378bbeb3da2017538ec" + +tslint-config-0xproject@^0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/tslint-config-0xproject/-/tslint-config-0xproject-0.0.2.tgz#39901e0c0b3e9388f00092a28b90c015395d5bba" + dependencies: + tslint-react "^3.0.0" + +tslint-react@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/tslint-react/-/tslint-react-3.1.0.tgz#a4de1a22fef41b663fa44daae27cbf04dc8a59d6" + dependencies: + tsutils "^1.7.0" + +tslint@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.5.0.tgz#10e8dab3e3061fa61e9442e8cee3982acf20a6aa" + dependencies: + babel-code-frame "^6.22.0" + colors "^1.1.2" + commander "^2.9.0" + diff "^3.2.0" + glob "^7.1.1" + minimatch "^3.0.4" + resolve "^1.3.2" + semver "^5.3.0" + tslib "^1.7.1" + tsutils "^2.5.1" + +tsutils@^1.7.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-1.9.1.tgz#b9f9ab44e55af9681831d5f28d0aeeaf5c750cb0" + +tsutils@^2.5.1: + version "2.8.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.8.0.tgz#0160173729b3bf138628dd14a1537e00851d814a" + dependencies: + tslib "^1.7.1" + +typescript@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.4.2.tgz#f8395f85d459276067c988aa41837a8f82870844" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" diff --git a/packages/web3-wrapper/CHANGELOG.md b/packages/web3-wrapper/CHANGELOG.md new file mode 100644 index 000000000..899482c4c --- /dev/null +++ b/packages/web3-wrapper/CHANGELOG.md @@ -0,0 +1,3 @@ +# CHANGELOG + +## vx.x.x diff --git a/packages/web3-wrapper/README.md b/packages/web3-wrapper/README.md index 0df8c6333..5b22aefd4 100644 --- a/packages/web3-wrapper/README.md +++ b/packages/web3-wrapper/README.md @@ -1,10 +1,57 @@ -Web3 wrapper ------- +## @0xproject/web3-wrapper -Wrapped version of web3 with nicer interface to be used across 0x projects and packages +Wrapped version of web3 with a nicer interface that is used across 0x projects and packages -## Install +## Installation ```bash yarn add @0xproject/web3-wrapper ``` + +## Usage + +```typescript +import {Web3Wrapper} from '@0xproject/web3-wrapper'; + +const web3 = ...; +const web3Wrapper = new Web3Wrapper(web3.currentProvider); +const availableAddresses = await web3Wrapper.getAvailableAddressesAsync(); +``` + +## Contributing + +We strongly encourage that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. + +Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. + +### Install Dependencies + +If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: + +```bash +yarn config set workspaces-experimental true +``` + +Then install dependencies + +```bash +yarn install +``` + +### Build + +```bash +yarn build +``` + +### Lint + +```bash +yarn lint +``` + +### Run Tests + +```bash +yarn test +``` diff --git a/packages/web3-wrapper/package.json b/packages/web3-wrapper/package.json index 4eea7ed31..a0e15b48d 100644 --- a/packages/web3-wrapper/package.json +++ b/packages/web3-wrapper/package.json @@ -1,37 +1,36 @@ { - "name": "@0xproject/web3-wrapper", - "version": "0.0.1", - "description": "Wraps around web3 and gives a nicer interface", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "scripts": { - "build": "tsc", - "clean": "shx rm -rf lib", - "lint": "tslint --project . 'src/**/*.ts'" - }, - "license": "Apache-2.0", - "repository": { - "type": "git", - "url": "https://github.com/0xProject/0x.js.git" - }, - "bugs": { - "url": "https://github.com/0xProject/0x.js/issues" - }, - "homepage": "https://github.com/0xProject/0x.js/packages/web3-wrapper/README.md", - "devDependencies": { - "@0xproject/tslint-config": "^0.2.0", - "@0xproject/types": "^0.0.1", - "@types/lodash": "^4.14.86", - "npm-run-all": "^4.1.2", - "shx": "^0.2.2", - "tslint": "5.8.0", - "typescript": "~2.6.1", - "web3-typescript-typings": "^0.7.2" - }, - "dependencies": { - "@0xproject/utils": "^0.0.1", - "bignumber.js": "~4.1.0", - "lodash": "^4.17.4", - "web3": "^0.20.0" - } + "name": "@0xproject/web3-wrapper", + "version": "0.1.6", + "description": "Wraps around web3 and gives a nicer interface", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "scripts": { + "build": "tsc", + "clean": "shx rm -rf lib", + "lint": "tslint --project . 'src/**/*.ts'" + }, + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/0xProject/0x.js.git" + }, + "bugs": { + "url": "https://github.com/0xProject/0x.js/issues" + }, + "homepage": "https://github.com/0xProject/0x.js/packages/web3-wrapper/README.md", + "devDependencies": { + "@0xproject/tslint-config": "^0.4.3", + "@0xproject/types": "^0.1.5", + "@types/lodash": "^4.14.86", + "npm-run-all": "^4.1.2", + "shx": "^0.2.2", + "tslint": "5.8.0", + "typescript": "~2.6.1", + "web3-typescript-typings": "^0.9.5" + }, + "dependencies": { + "@0xproject/utils": "^0.2.1", + "lodash": "^4.17.4", + "web3": "^0.20.0" + } } diff --git a/packages/web3-wrapper/scripts/postpublish.js b/packages/web3-wrapper/scripts/postpublish.js new file mode 100644 index 000000000..7fa452b08 --- /dev/null +++ b/packages/web3-wrapper/scripts/postpublish.js @@ -0,0 +1,14 @@ +const postpublish_utils = require('../../../scripts/postpublish_utils'); +const packageJSON = require('../package.json'); + +const subPackageName = packageJSON.name; + +postpublish_utils.getLatestTagAndVersionAsync(subPackageName) + .then(function(result) { + const releaseName = postpublish_utils.getReleaseName(subPackageName, result.version); + const assets = []; + return postpublish_utils.publishReleaseNotes(result.tag, releaseName, assets); + }) + .catch (function(err) { + throw err; + }); diff --git a/packages/web3-wrapper/src/index.ts b/packages/web3-wrapper/src/index.ts index 7df24e9a5..c4826f2be 100644 --- a/packages/web3-wrapper/src/index.ts +++ b/packages/web3-wrapper/src/index.ts @@ -1,24 +1,23 @@ -import {TransactionReceipt, TxData} from '@0xproject/types'; -import {promisify} from '@0xproject/utils'; -import BigNumber from 'bignumber.js'; +import { TransactionReceipt, TxData } from '@0xproject/types'; +import { BigNumber, promisify } from '@0xproject/utils'; import * as _ from 'lodash'; import * as Web3 from 'web3'; interface RawLogEntry { - logIndex: string|null; - transactionIndex: string|null; + logIndex: string | null; + transactionIndex: string | null; transactionHash: string; - blockHash: string|null; - blockNumber: string|null; + blockHash: string | null; + blockNumber: string | null; address: string; data: string; topics: string[]; } export class Web3Wrapper { - private web3: Web3; - private defaults: Partial<TxData>; - private jsonRpcRequestId: number; + private _web3: Web3; + private _defaults: Partial<TxData>; + private _jsonRpcRequestId: number; constructor(provider: Web3.Provider, defaults?: Partial<TxData>) { if (_.isUndefined((provider as any).sendAsync)) { // Web3@1.0 provider doesn't support synchronous http requests, @@ -26,87 +25,87 @@ export class Web3Wrapper { // We re-assign the send method so that Web3@1.0 providers work with 0x.js (provider as any).sendAsync = (provider as any).send; } - this.web3 = new Web3(); - this.web3.setProvider(provider); - this.defaults = defaults || {}; - this.jsonRpcRequestId = 0; + this._web3 = new Web3(); + this._web3.setProvider(provider); + this._defaults = defaults || {}; + this._jsonRpcRequestId = 0; } public getContractDefaults(): Partial<TxData> { - return this.defaults; + return this._defaults; } - public setProvider(provider: Web3.Provider, networkId: number) { - this.web3.setProvider(provider); + public setProvider(provider: Web3.Provider) { + this._web3.setProvider(provider); } public isAddress(address: string): boolean { - return this.web3.isAddress(address); + return this._web3.isAddress(address); } public async isSenderAddressAvailableAsync(senderAddress: string): Promise<boolean> { const addresses = await this.getAvailableAddressesAsync(); return _.includes(addresses, senderAddress); } public async getNodeVersionAsync(): Promise<string> { - const nodeVersion = await promisify<string>(this.web3.version.getNode)(); + const nodeVersion = await promisify<string>(this._web3.version.getNode)(); return nodeVersion; } public async getNetworkIdAsync(): Promise<number> { - const networkIdStr = await promisify<string>(this.web3.version.getNetwork)(); + const networkIdStr = await promisify<string>(this._web3.version.getNetwork)(); const networkId = _.parseInt(networkIdStr); return networkId; } public async getTransactionReceiptAsync(txHash: string): Promise<TransactionReceipt> { - const transactionReceipt = await promisify<TransactionReceipt>(this.web3.eth.getTransactionReceipt)(txHash); + const transactionReceipt = await promisify<TransactionReceipt>(this._web3.eth.getTransactionReceipt)(txHash); if (!_.isNull(transactionReceipt)) { - transactionReceipt.status = this.normalizeTxReceiptStatus(transactionReceipt.status); + transactionReceipt.status = this._normalizeTxReceiptStatus(transactionReceipt.status); } return transactionReceipt; } public getCurrentProvider(): Web3.Provider { - return this.web3.currentProvider; + return this._web3.currentProvider; } public toWei(ethAmount: BigNumber): BigNumber { - const balanceWei = this.web3.toWei(ethAmount, 'ether'); + const balanceWei = this._web3.toWei(ethAmount, 'ether'); return balanceWei; } public async getBalanceInWeiAsync(owner: string): Promise<BigNumber> { - let balanceInWei = await promisify<BigNumber>(this.web3.eth.getBalance)(owner); + let balanceInWei = await promisify<BigNumber>(this._web3.eth.getBalance)(owner); // Rewrap in a new BigNumber balanceInWei = new BigNumber(balanceInWei); return balanceInWei; } public async doesContractExistAtAddressAsync(address: string): Promise<boolean> { - const code = await promisify<string>(this.web3.eth.getCode)(address); + const code = await promisify<string>(this._web3.eth.getCode)(address); // Regex matches 0x0, 0x00, 0x in order to accommodate poorly implemented clients const codeIsEmpty = /^0x0{0,40}$/i.test(code); return !codeIsEmpty; } public async signTransactionAsync(address: string, message: string): Promise<string> { - const signData = await promisify<string>(this.web3.eth.sign)(address, message); + const signData = await promisify<string>(this._web3.eth.sign)(address, message); return signData; } public async getBlockNumberAsync(): Promise<number> { - const blockNumber = await promisify<number>(this.web3.eth.getBlockNumber)(); + const blockNumber = await promisify<number>(this._web3.eth.getBlockNumber)(); return blockNumber; } - public async getBlockAsync(blockParam: string|Web3.BlockParam): Promise<Web3.BlockWithoutTransactionData> { - const block = await promisify<Web3.BlockWithoutTransactionData>(this.web3.eth.getBlock)(blockParam); + public async getBlockAsync(blockParam: string | Web3.BlockParam): Promise<Web3.BlockWithoutTransactionData> { + const block = await promisify<Web3.BlockWithoutTransactionData>(this._web3.eth.getBlock)(blockParam); return block; } - public async getBlockTimestampAsync(blockParam: string|Web3.BlockParam): Promise<number> { - const {timestamp} = await this.getBlockAsync(blockParam); + public async getBlockTimestampAsync(blockParam: string | Web3.BlockParam): Promise<number> { + const { timestamp } = await this.getBlockAsync(blockParam); return timestamp; } public async getAvailableAddressesAsync(): Promise<string[]> { - const addresses = await promisify<string[]>(this.web3.eth.getAccounts)(); + const addresses = await promisify<string[]>(this._web3.eth.getAccounts)(); return addresses; } public async getLogsAsync(filter: Web3.FilterObject): Promise<Web3.LogEntry[]> { let fromBlock = filter.fromBlock; if (_.isNumber(fromBlock)) { - fromBlock = this.web3.toHex(fromBlock); + fromBlock = this._web3.toHex(fromBlock); } let toBlock = filter.toBlock; if (_.isNumber(toBlock)) { - toBlock = this.web3.toHex(toBlock); + toBlock = this._web3.toHex(toBlock); } const serializedFilter = { ...filter, @@ -115,16 +114,16 @@ export class Web3Wrapper { }; const payload = { jsonrpc: '2.0', - id: this.jsonRpcRequestId++, + id: this._jsonRpcRequestId++, method: 'eth_getLogs', params: [serializedFilter], }; - const rawLogs = await this.sendRawPayloadAsync<RawLogEntry[]>(payload); - const formattedLogs = _.map(rawLogs, this.formatLog.bind(this)); + const rawLogs = await this._sendRawPayloadAsync<RawLogEntry[]>(payload); + const formattedLogs = _.map(rawLogs, this._formatLog.bind(this)); return formattedLogs; } public getContractFromAbi(abi: Web3.ContractAbi): Web3.Contract<any> { - const web3Contract = this.web3.eth.contract(abi); + const web3Contract = this._web3.eth.contract(abi); return web3Contract; } public getContractInstance(abi: Web3.ContractAbi, address: string): Web3.ContractInstance { @@ -132,43 +131,43 @@ export class Web3Wrapper { return web3ContractInstance; } public async estimateGasAsync(data: string): Promise<number> { - const gas = await promisify<number>(this.web3.eth.estimateGas)({data}); + const gas = await promisify<number>(this._web3.eth.estimateGas)({ data }); return gas; } - private async sendRawPayloadAsync<A>(payload: Web3.JSONRPCRequestPayload): Promise<A> { - const sendAsync = this.web3.currentProvider.sendAsync.bind(this.web3.currentProvider); + private async _sendRawPayloadAsync<A>(payload: Web3.JSONRPCRequestPayload): Promise<A> { + const sendAsync = this._web3.currentProvider.sendAsync.bind(this._web3.currentProvider); const response = await promisify<Web3.JSONRPCResponsePayload>(sendAsync)(payload); const result = response.result; return result; } - private normalizeTxReceiptStatus(status: undefined|null|string|0|1): null|0|1 { + private _normalizeTxReceiptStatus(status: undefined | null | string | 0 | 1): null | 0 | 1 { // Transaction status might have four values // undefined - Testrpc and other old clients // null - New clients on old transactions // number - Parity // hex - Geth if (_.isString(status)) { - return this.web3.toDecimal(status) as 0|1; + return this._web3.toDecimal(status) as 0 | 1; } else if (_.isUndefined(status)) { return null; } else { return status; } } - private formatLog(rawLog: RawLogEntry): Web3.LogEntry { + private _formatLog(rawLog: RawLogEntry): Web3.LogEntry { const formattedLog = { ...rawLog, - logIndex: this.hexToDecimal(rawLog.logIndex), - blockNumber: this.hexToDecimal(rawLog.blockNumber), - transactionIndex: this.hexToDecimal(rawLog.transactionIndex), + logIndex: this._hexToDecimal(rawLog.logIndex), + blockNumber: this._hexToDecimal(rawLog.blockNumber), + transactionIndex: this._hexToDecimal(rawLog.transactionIndex), }; return formattedLog; } - private hexToDecimal(hex: string|null): number|null { + private _hexToDecimal(hex: string | null): number | null { if (_.isNull(hex)) { return null; } - const decimal = this.web3.toDecimal(hex); + const decimal = this._web3.toDecimal(hex); return decimal; } } diff --git a/packages/web3-wrapper/tsconfig.json b/packages/web3-wrapper/tsconfig.json index de186cfc4..3d967d05f 100644 --- a/packages/web3-wrapper/tsconfig.json +++ b/packages/web3-wrapper/tsconfig.json @@ -1,16 +1,7 @@ { - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "lib": [ "es2017", "dom"], - "outDir": "lib", - "sourceMap": true, - "declaration": true, - "noImplicitAny": true, - "strictNullChecks": true - }, - "include": [ - "./src/**/*", - "../../node_modules/web3-typescript-typings/index.d.ts" - ] + "extends": "../../tsconfig", + "compilerOptions": { + "outDir": "lib" + }, + "include": ["./src/**/*", "../../node_modules/web3-typescript-typings/index.d.ts"] } diff --git a/packages/web3-wrapper/tslint.json b/packages/web3-wrapper/tslint.json index a07795151..ffaefe83a 100644 --- a/packages/web3-wrapper/tslint.json +++ b/packages/web3-wrapper/tslint.json @@ -1,5 +1,3 @@ { - "extends": [ - "@0xproject/tslint-config" - ] + "extends": ["@0xproject/tslint-config"] } diff --git a/packages/website/CHANGELOG.md b/packages/website/CHANGELOG.md new file mode 100644 index 000000000..6cb8cd0b0 --- /dev/null +++ b/packages/website/CHANGELOG.md @@ -0,0 +1,5 @@ +# CHANGELOG + +## v0.x.x - _TBD_ + + * Added new team members to the about page (#317) diff --git a/packages/website/README.md b/packages/website/README.md index 128477372..7d3187781 100644 --- a/packages/website/README.md +++ b/packages/website/README.md @@ -1,8 +1,4 @@ -<img src="https://github.com/0xProject/branding/blob/master/0x_Black_CMYK.png" width="200px" > - ---- - -[0x][website-url] is an open protocol that facilitates trustless, low friction exchange of Ethereum-based assets. A full description of the protocol may be found in our [whitepaper][whitepaper-url]. +## Website & 0x Portal DApp This repository contains our website and [0x Portal DApp][portal-url] (over-the-counter exchange), facilitating trustless over-the-counter trading of Ethereum-based tokens using 0x protocol. @@ -10,10 +6,13 @@ This repository contains our website and [0x Portal DApp][portal-url] (over-the- [whitepaper-url]: https://0xproject.com/pdfs/0x_white_paper.pdf [portal-url]: https://0xproject.com/portal -[![Join the chat at https://gitter.im/0xProject/contracts](https://badges.gitter.im/0xProject/contracts.svg)](https://gitter.im/0xProject/contracts?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) +## Contributing + +We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. -### Local Dev Setup +Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. + +## Local Dev Setup Requires Node version 6.9.5 or higher. @@ -23,38 +22,47 @@ Add the following to your `/etc/hosts` file: 127.0.0.1 0xproject.localhost ``` -Clone the [0x contracts repo](https://github.com/0xProject/contracts) into the same parent directory as this project. +### Install dependencies: -Install [yarn](https://yarnpkg.com/lang/en/docs/install/) in order to install the project dependencies more deterministically. +```bash +yarn install +``` -Install dependencies: +### Run dev server -``` -yarn +```bash +yarn run dev ``` -Import smart contract artifacts from `contracts` repo: +Visit [0xproject.localhost:3572](http://0xproject.localhost:3572) in your browser. -``` -yarn run update_contracts +### Build + +```bash +yarn build ``` -Start dev server: +### Clean -``` -yarn run dev +```bash +yarn clean ``` -Visit [0xproject.localhost:3572](http://0xproject.localhost:3572) in your browser. +### Lint +```bash +yarn lint +``` -##### Recommended Atom packages: +### Resources -- [atom-typescript](https://atom.io/packages/atom-typescript) -- [linter-tslint](https://atom.io/packages/linter-tslint) +##### Toolkit -##### Resources +* [Material Design Icon Font](http://zavoloklom.github.io/material-design-iconic-font/icons.html#directional) +* [BassCSS toolkit](http://basscss.com/) +* [Material-UI component library](http://www.material-ui.com/#/) + +##### Recommended Atom packages: -- [Material Design Icon Font](http://zavoloklom.github.io/material-design-iconic-font/icons.html#directional) -- [BassCSS toolkit](http://basscss.com/) -- [Material-UI](http://www.material-ui.com/#/) +* [atom-typescript](https://atom.io/packages/atom-typescript) +* [linter-tslint](https://atom.io/packages/linter-tslint) diff --git a/packages/website/contracts/Mintable.json b/packages/website/contracts/Mintable.json index 52dc7507f..dc46dc829 100644 --- a/packages/website/contracts/Mintable.json +++ b/packages/website/contracts/Mintable.json @@ -1,189 +1,190 @@ { - "contract_name": "Mintable", - "abi": [ - { - "constant": false, - "inputs": [ - { - "name": "_spender", - "type": "address" + "contract_name": "Mintable", + "abi": [ + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "type": "function" }, { - "name": "_value", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "_from", - "type": "address" + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "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": "", + "type": "bool" + } + ], + "payable": false, + "type": "function" }, { - "name": "_value", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "_owner", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "_value", - "type": "uint256" - } - ], - "name": "mint", - "outputs": [], - "payable": false, - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "_to", - "type": "address" - }, - { - "name": "_value", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "_owner", - "type": "address" + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "type": "function" }, { - "name": "_spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "type": "function" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "_from", - "type": "address" + "constant": false, + "inputs": [ + { + "name": "_value", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "payable": false, + "type": "function" }, { - "indexed": true, - "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" }, { - "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": "", + "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" - } - ], - "unlinked_binary": "0x6060604052341561000c57fe5b5b6105018061001c6000396000f300606060405236156100675763ffffffff60e060020a600035041663095ea7b3811461006957806318160ddd1461009c57806323b872dd146100be57806370a08231146100f7578063a0712d6814610125578063a9059cbb1461013a578063dd62ed3e1461016d575bfe5b341561007157fe5b610088600160a060020a03600435166024356101a1565b604080519115158252519081900360200190f35b34156100a457fe5b6100ac61020c565b60408051918252519081900360200190f35b34156100c657fe5b610088600160a060020a0360043581169060243516604435610212565b604080519115158252519081900360200190f35b34156100ff57fe5b6100ac600160a060020a0360043516610335565b60408051918252519081900360200190f35b341561012d57fe5b610138600435610354565b005b341561014257fe5b610088600160a060020a03600435166024356103bc565b604080519115158252519081900360200190f35b341561017557fe5b6100ac600160a060020a036004358116906024351661046e565b60408051918252519081900360200190f35b600160a060020a03338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60025481565b600160a060020a03808416600081815260016020908152604080832033909516835293815283822054928252819052918220548390108015906102555750828110155b801561027b5750600160a060020a03841660009081526020819052604090205483810110155b1561032757600160a060020a03808516600090815260208190526040808220805487019055918716815220805484900390556000198110156102e557600160a060020a03808616600090815260016020908152604080832033909416835292905220805484900390555b83600160a060020a031685600160a060020a03166000805160206104b6833981519152856040518082815260200191505060405180910390a36001915061032c565b600091505b5b509392505050565b600160a060020a0381166000908152602081905260409020545b919050565b68056bc75e2d6310000081111561036b5760006000fd5b600160a060020a03331660009081526020819052604090205461038f90829061049b565b600160a060020a0333166000908152602081905260409020556002546103b5908261049b565b6002555b50565b600160a060020a0333166000908152602081905260408120548290108015906103ff5750600160a060020a03831660009081526020819052604090205482810110155b1561045f57600160a060020a0333811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191936000805160206104b6833981519152929081900390910190a3506001610206565b506000610206565b5b92915050565b600160a060020a038083166000908152600160209081526040808320938516835292905220545b92915050565b6000828201838110156104aa57fe5b8091505b50929150505600ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a72305820998c8326b9629e063eb4867166e72c68a8c2e3ebca6a9d35ebc78c041c7aa47b0029", - "networks": {}, - "schema_version": "0.0.5", - "updated_at": 1503413048892 -}
\ No newline at end of file + ], + "unlinked_binary": + "0x6060604052341561000c57fe5b5b6105018061001c6000396000f300606060405236156100675763ffffffff60e060020a600035041663095ea7b3811461006957806318160ddd1461009c57806323b872dd146100be57806370a08231146100f7578063a0712d6814610125578063a9059cbb1461013a578063dd62ed3e1461016d575bfe5b341561007157fe5b610088600160a060020a03600435166024356101a1565b604080519115158252519081900360200190f35b34156100a457fe5b6100ac61020c565b60408051918252519081900360200190f35b34156100c657fe5b610088600160a060020a0360043581169060243516604435610212565b604080519115158252519081900360200190f35b34156100ff57fe5b6100ac600160a060020a0360043516610335565b60408051918252519081900360200190f35b341561012d57fe5b610138600435610354565b005b341561014257fe5b610088600160a060020a03600435166024356103bc565b604080519115158252519081900360200190f35b341561017557fe5b6100ac600160a060020a036004358116906024351661046e565b60408051918252519081900360200190f35b600160a060020a03338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60025481565b600160a060020a03808416600081815260016020908152604080832033909516835293815283822054928252819052918220548390108015906102555750828110155b801561027b5750600160a060020a03841660009081526020819052604090205483810110155b1561032757600160a060020a03808516600090815260208190526040808220805487019055918716815220805484900390556000198110156102e557600160a060020a03808616600090815260016020908152604080832033909416835292905220805484900390555b83600160a060020a031685600160a060020a03166000805160206104b6833981519152856040518082815260200191505060405180910390a36001915061032c565b600091505b5b509392505050565b600160a060020a0381166000908152602081905260409020545b919050565b68056bc75e2d6310000081111561036b5760006000fd5b600160a060020a03331660009081526020819052604090205461038f90829061049b565b600160a060020a0333166000908152602081905260409020556002546103b5908261049b565b6002555b50565b600160a060020a0333166000908152602081905260408120548290108015906103ff5750600160a060020a03831660009081526020819052604090205482810110155b1561045f57600160a060020a0333811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191936000805160206104b6833981519152929081900390910190a3506001610206565b506000610206565b5b92915050565b600160a060020a038083166000908152600160209081526040808320938516835292905220545b92915050565b6000828201838110156104aa57fe5b8091505b50929150505600ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a72305820998c8326b9629e063eb4867166e72c68a8c2e3ebca6a9d35ebc78c041c7aa47b0029", + "networks": {}, + "schema_version": "0.0.5", + "updated_at": 1503413048892 +} diff --git a/packages/website/md/docs/0xjs/async.md b/packages/website/md/docs/0xjs/async.md index 63924c76c..8abaef331 100644 --- a/packages/website/md/docs/0xjs/async.md +++ b/packages/website/md/docs/0xjs/async.md @@ -1,6 +1,7 @@ 0x.js is a promise-based library. This means that whenever an asynchronous call is required, the library method will return a native Javascript promise. You can therefore choose between using `promise` or `async/await` syntax when calling our async methods. -*Async/await syntax (recommended):* +_Async/await syntax (recommended):_ + ```javascript try { var availableAddresses = await zeroEx.getAvailableAddressesAsync(); @@ -9,9 +10,11 @@ try { } ``` -*Promise syntax:* +_Promise syntax:_ + ```javascript -zeroEx.getAvailableAddressesAsync() +zeroEx + .getAvailableAddressesAsync() .then(function(availableAddresses) { console.log(availableAddresses); }) diff --git a/packages/website/md/docs/0xjs/installation.md b/packages/website/md/docs/0xjs/installation.md index 457b27a04..5f5c9137e 100644 --- a/packages/website/md/docs/0xjs/installation.md +++ b/packages/website/md/docs/0xjs/installation.md @@ -1,6 +1,6 @@ 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** @@ -11,7 +11,7 @@ npm install 0x.js --save **Import** ```javascript -import {ZeroEx} from '0x.js'; +import { ZeroEx } from '0x.js'; ``` #### UMD: diff --git a/packages/website/md/docs/connect/installation.md b/packages/website/md/docs/connect/installation.md index b14bc1b52..184fa6e0d 100644 --- a/packages/website/md/docs/connect/installation.md +++ b/packages/website/md/docs/connect/installation.md @@ -7,7 +7,7 @@ npm install @0xproject/connect --save **Import** ```javascript -import {HttpClient} from '@0xproject/connect'; +import { HttpClient } from '@0xproject/connect'; ``` ### Wiki diff --git a/packages/website/md/docs/smart_contracts/introduction.md b/packages/website/md/docs/smart_contracts/introduction.md index 406177f84..20396289b 100644 --- a/packages/website/md/docs/smart_contracts/introduction.md +++ b/packages/website/md/docs/smart_contracts/introduction.md @@ -2,7 +2,7 @@ Welcome to the [0x smart contracts](https://github.com/0xProject/contracts) docu ### Helpful wiki articles: -- [Overview of 0x protocol architecture](https://0xproject.com/wiki#Architecture) -- [0x smart contract interactions](https://0xproject.com/wiki#Contract-Interactions) -- [Deployed smart contract addresses](https://0xproject.com/wiki#Deployed-Addresses) -- [0x protocol message format](https://0xproject.com/wiki#Message-Format) +* [Overview of 0x protocol architecture](https://0xproject.com/wiki#Architecture) +* [0x smart contract interactions](https://0xproject.com/wiki#Contract-Interactions) +* [Deployed smart contract addresses](https://0xproject.com/wiki#Deployed-Addresses) +* [0x protocol message format](https://0xproject.com/wiki#Message-Format) diff --git a/packages/website/package.json b/packages/website/package.json index 9234ad601..fcfa12301 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -1,107 +1,106 @@ { - "name": "website", - "version": "0.0.1", - "private": true, - "description": "Website and 0x portal dapp", - "scripts": { - "build": "NODE_ENV=production webpack; exit 0;", - "clean": "shx rm -f public/bundle*", - "lint": "tslint --project . 'ts/**/*.ts' 'ts/**/*.tsx'", - "dev": "webpack-dev-server --content-base public --https", - "update_contracts": "for i in ${npm_package_config_artifacts}; do copyfiles -u 4 ../contracts/build/contracts/$i.json ../website/contracts; done;", - "deploy_staging": "npm run build; aws s3 sync ./public/. s3://staging-0xproject --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers", - "deploy_live": "npm run build; aws s3 sync ./public/. s3://0xproject.com --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers" - }, - "config": { - "artifacts": "Mintable" - }, - "author": "Fabio Berger", - "license": "Apache-2.0", - "dependencies": { - "@0xproject/subproviders": "0.0.1", - "0x.js": "0xproject/0x.js/packages/0x.js#0x.js@0.27.1", - "accounting": "^0.4.1", - "basscss": "^8.0.3", - "bignumber.js": "~4.1.0", - "blockies": "^0.0.2", - "compare-versions": "^3.0.1", - "dateformat": "^2.0.0", - "deep-equal": "^1.0.1", - "dharma-loan-frame": "^0.0.12", - "ethereum-address": "^0.0.4", - "ethereumjs-tx": "^1.3.3", - "ethereumjs-util": "^5.1.1", - "find-versions": "^2.0.0", - "is-mobile": "^0.2.2", - "jsonschema": "^1.2.0", - "ledgerco": "0xProject/ledger-node-js-api", - "less": "^2.7.2", - "lodash": "^4.17.4", - "material-ui": "^0.17.1", - "moment": "^2.18.1", - "query-string": "^5.0.1", - "react": "15.6.1", - "react-copy-to-clipboard": "^4.2.3", - "react-document-title": "^2.0.3", - "react-dom": "15.6.1", - "react-highlight": "^0.10.0", - "react-html5video": "^2.1.0", - "react-inlinesvg": "^0.5.5", - "react-markdown": "^2.5.0", - "react-recaptcha": "^2.3.2", - "react-redux": "^5.0.3", - "react-router-dom": "^4.1.1", - "react-router-hash-link": "^1.1.0", - "react-scroll": "^1.5.2", - "react-tap-event-plugin": "^2.0.1", - "react-tooltip": "^3.2.7", - "react-waypoint": "^7.0.4", - "redux": "^3.6.0", - "scroll-to-element": "^2.0.0", - "semver-sort": "0.0.4", - "thenby": "^1.2.3", - "truffle-contract": "2.0.1", - "tslint-config-0xproject": "^0.0.2", - "web3": "^0.20.0", - "web3-provider-engine": "^13.0.1", - "whatwg-fetch": "^2.0.3", - "xml-js": "^1.3.2" - }, - "devDependencies": { - "@types/accounting": "^0.4.1", - "@types/dateformat": "^1.0.1", - "@types/deep-equal": "^1.0.0", - "@types/jsonschema": "^1.1.1", - "@types/lodash": "^4.14.86", - "@types/material-ui": "0.18.0", - "@types/moment": "^2.13.0", - "@types/node": "^8.0.53", - "@types/query-string": "^5.0.1", - "@types/react": "^15.0.15", - "@types/react-copy-to-clipboard": "^4.2.0", - "@types/react-dom": "^0.14.23", - "@types/react-redux": "^4.4.37", - "@types/react-router-dom": "^4.0.4", - "@types/react-scroll": "0.0.31", - "@types/react-tap-event-plugin": "0.0.30", - "@types/redux": "^3.6.0", - "awesome-typescript-loader": "^3.1.3", - "copy-webpack-plugin": "^4.0.1", - "copyfiles": "^1.2.0", - "css-loader": "0.23.x", - "exports-loader": "0.6.x", - "imports-loader": "0.6.x", - "json-loader": "^0.5.4", - "less-loader": "^2.2.3", - "raw-loader": "^0.5.1", - "shx": "^0.2.2", - "source-map-loader": "^0.1.6", - "style-loader": "0.13.x", - "tslint": "5.8.0", - "typescript": "~2.6.1", - "web3-typescript-typings": "^0.7.2", - "webpack": "^3.1.0", - "webpack-dev-middleware": "^1.10.0", - "webpack-dev-server": "^2.5.0" - } + "name": "@0xproject/website", + "version": "0.0.8", + "private": true, + "description": "Website and 0x portal dapp", + "scripts": { + "build": "NODE_ENV=production webpack; exit 0;", + "clean": "shx rm -f public/bundle*", + "lint": "tslint --project . 'ts/**/*.ts' 'ts/**/*.tsx'", + "dev": "webpack-dev-server --content-base public --https", + "update_contracts": "for i in ${npm_package_config_artifacts}; do copyfiles -u 4 ../contracts/build/contracts/$i.json ../website/contracts; done;", + "deploy_staging": "npm run build; aws s3 sync ./public/. s3://staging-0xproject --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers", + "deploy_live": "npm run build; aws s3 sync ./public/. s3://0xproject.com --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers" + }, + "config": { + "artifacts": "Mintable" + }, + "author": "Fabio Berger", + "license": "Apache-2.0", + "dependencies": { + "0x.js": "^0.30.1", + "@0xproject/subproviders": "^0.3.2", + "@0xproject/utils": "^0.2.1", + "accounting": "^0.4.1", + "basscss": "^8.0.3", + "blockies": "^0.0.2", + "compare-versions": "^3.0.1", + "dateformat": "^2.0.0", + "deep-equal": "^1.0.1", + "dharma-loan-frame": "^0.0.12", + "ethereumjs-tx": "^1.3.3", + "ethereumjs-util": "^5.1.1", + "find-versions": "^2.0.0", + "is-mobile": "^0.2.2", + "jsonschema": "^1.2.0", + "ledgerco": "0xProject/ledger-node-js-api", + "less": "^2.7.2", + "lodash": "^4.17.4", + "material-ui": "^0.17.1", + "moment": "^2.18.1", + "query-string": "^5.0.1", + "react": "15.6.1", + "react-copy-to-clipboard": "^4.2.3", + "react-document-title": "^2.0.3", + "react-dom": "15.6.1", + "react-highlight": "^0.10.0", + "react-html5video": "^2.1.0", + "react-inlinesvg": "^0.5.5", + "react-markdown": "^2.5.0", + "react-recaptcha": "^2.3.2", + "react-redux": "^5.0.3", + "react-router-dom": "^4.1.1", + "react-router-hash-link": "^1.1.0", + "react-scroll": "^1.5.2", + "react-tap-event-plugin": "^2.0.1", + "react-tooltip": "^3.2.7", + "react-waypoint": "^7.0.4", + "redux": "^3.6.0", + "scroll-to-element": "^2.0.0", + "semver-sort": "0.0.4", + "thenby": "^1.2.3", + "truffle-contract": "2.0.1", + "tslint-config-0xproject": "^0.0.2", + "web3": "^0.20.0", + "web3-provider-engine": "^13.0.1", + "whatwg-fetch": "^2.0.3", + "xml-js": "^1.3.2" + }, + "devDependencies": { + "@types/accounting": "^0.4.1", + "@types/dateformat": "^1.0.1", + "@types/deep-equal": "^1.0.0", + "@types/jsonschema": "^1.1.1", + "@types/lodash": "^4.14.86", + "@types/material-ui": "0.18.0", + "@types/moment": "^2.13.0", + "@types/node": "^8.0.53", + "@types/query-string": "^5.0.1", + "@types/react": "^15.0.15", + "@types/react-copy-to-clipboard": "^4.2.0", + "@types/react-dom": "^0.14.23", + "@types/react-redux": "^4.4.37", + "@types/react-router-dom": "^4.0.4", + "@types/react-scroll": "0.0.31", + "@types/react-tap-event-plugin": "0.0.30", + "@types/redux": "^3.6.0", + "awesome-typescript-loader": "^3.1.3", + "copy-webpack-plugin": "^4.0.1", + "copyfiles": "^1.2.0", + "css-loader": "0.23.x", + "exports-loader": "0.6.x", + "imports-loader": "0.6.x", + "json-loader": "^0.5.4", + "less-loader": "^2.2.3", + "raw-loader": "^0.5.1", + "shx": "^0.2.2", + "source-map-loader": "^0.1.6", + "style-loader": "0.13.x", + "tslint": "5.8.0", + "typescript": "~2.6.1", + "web3-typescript-typings": "^0.9.5", + "webpack": "^3.1.0", + "webpack-dev-middleware": "^1.10.0", + "webpack-dev-server": "^2.5.0" + } } diff --git a/packages/website/public/images/ether.png b/packages/website/public/images/ether.png Binary files differindex 6a40a976d..c92f45681 100644 --- a/packages/website/public/images/ether.png +++ b/packages/website/public/images/ether.png diff --git a/packages/website/public/images/social/discourse.png b/packages/website/public/images/social/discourse.png Binary files differnew file mode 100644 index 000000000..4bca3de0d --- /dev/null +++ b/packages/website/public/images/social/discourse.png diff --git a/packages/website/public/images/team/jacob.jpg b/packages/website/public/images/team/jacob.jpg Binary files differnew file mode 100644 index 000000000..62ff412d2 --- /dev/null +++ b/packages/website/public/images/team/jacob.jpg diff --git a/packages/website/public/images/team/tom.jpg b/packages/website/public/images/team/tom.jpg Binary files differnew file mode 100644 index 000000000..a6b763816 --- /dev/null +++ b/packages/website/public/images/team/tom.jpg diff --git a/packages/website/public/images/token_icons/augur.png b/packages/website/public/images/token_icons/augur.png Binary files differindex 31c257ba9..b7d61100a 100644 --- a/packages/website/public/images/token_icons/augur.png +++ b/packages/website/public/images/token_icons/augur.png diff --git a/packages/website/public/images/token_icons/default.png b/packages/website/public/images/token_icons/default.png Binary files differindex 7ce754030..5c9ea4b0f 100644 --- a/packages/website/public/images/token_icons/default.png +++ b/packages/website/public/images/token_icons/default.png diff --git a/packages/website/public/images/token_icons/district0x.png b/packages/website/public/images/token_icons/district0x.png Binary files differindex edb8f2238..7427b1146 100644 --- a/packages/website/public/images/token_icons/district0x.png +++ b/packages/website/public/images/token_icons/district0x.png diff --git a/packages/website/public/images/token_icons/ether_erc20.png b/packages/website/public/images/token_icons/ether_erc20.png Binary files differindex f4154db7b..bc8beae8b 100644 --- a/packages/website/public/images/token_icons/ether_erc20.png +++ b/packages/website/public/images/token_icons/ether_erc20.png diff --git a/packages/website/public/images/token_icons/firstblood.jpg b/packages/website/public/images/token_icons/firstblood.jpg Binary files differindex 64bb65605..9cd23b10e 100644 --- a/packages/website/public/images/token_icons/firstblood.jpg +++ b/packages/website/public/images/token_icons/firstblood.jpg diff --git a/packages/website/public/images/token_icons/qtum.png b/packages/website/public/images/token_icons/qtum.png Binary files differindex 97e227c5c..b7f09dfd2 100644 --- a/packages/website/public/images/token_icons/qtum.png +++ b/packages/website/public/images/token_icons/qtum.png diff --git a/packages/website/public/images/token_icons/zero_ex.png b/packages/website/public/images/token_icons/zero_ex.png Binary files differindex 6c6deef11..8ed9a984b 100644 --- a/packages/website/public/images/token_icons/zero_ex.png +++ b/packages/website/public/images/token_icons/zero_ex.png diff --git a/packages/website/public/images/wrapped_eth_gray.png b/packages/website/public/images/wrapped_eth_gray.png Binary files differnew file mode 100644 index 000000000..397b31b1c --- /dev/null +++ b/packages/website/public/images/wrapped_eth_gray.png diff --git a/packages/website/ts/blockchain.ts b/packages/website/ts/blockchain.ts index 76640a072..5530701c0 100644 --- a/packages/website/ts/blockchain.ts +++ b/packages/website/ts/blockchain.ts @@ -1,7 +1,7 @@ import { BlockParam, + BlockRange, DecodedLogEvent, - ExchangeContractErrs, ExchangeContractEventArgs, ExchangeEvents, IndexedFilterValues, @@ -10,11 +10,9 @@ import { LogWithDecodedArgs, Order, SignedOrder, - SubscriptionOpts, Token as ZeroExToken, TransactionReceiptWithDecodedLogs, ZeroEx, - ZeroExError, } from '0x.js'; import { InjectedWeb3Subprovider, @@ -23,24 +21,19 @@ import { LedgerWalletSubprovider, RedundantRPCSubprovider, } from '@0xproject/subproviders'; -import {promisify} from '@0xproject/utils'; -import BigNumber from 'bignumber.js'; -import compareVersions = require('compare-versions'); -import ethUtil = require('ethereumjs-util'); -import findVersions = require('find-versions'); +import { BigNumber, intervalUtils, promisify } from '@0xproject/utils'; import * as _ from 'lodash'; import * as React from 'react'; import contract = require('truffle-contract'); -import {TokenSendCompleted} from 'ts/components/flash_messages/token_send_completed'; -import {TransactionSubmitted} from 'ts/components/flash_messages/transaction_submitted'; -import {trackedTokenStorage} from 'ts/local_storage/tracked_token_storage'; -import {tradeHistoryStorage} from 'ts/local_storage/trade_history_storage'; -import {Dispatcher} from 'ts/redux/dispatcher'; +import { TokenSendCompleted } from 'ts/components/flash_messages/token_send_completed'; +import { TransactionSubmitted } from 'ts/components/flash_messages/transaction_submitted'; +import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage'; +import { tradeHistoryStorage } from 'ts/local_storage/trade_history_storage'; +import { Dispatcher } from 'ts/redux/dispatcher'; import { BlockchainCallErrs, BlockchainErrs, ContractInstance, - ContractResponse, EtherscanLinkSuffixes, ProviderType, Side, @@ -49,58 +42,55 @@ import { TokenByAddress, TokenStateByAddress, } from 'ts/types'; -import {configs} from 'ts/utils/configs'; -import {constants} from 'ts/utils/constants'; -import {errorReporter} from 'ts/utils/error_reporter'; -import {utils} from 'ts/utils/utils'; -import {Web3Wrapper} from 'ts/web3_wrapper'; +import { configs } from 'ts/utils/configs'; +import { constants } from 'ts/utils/constants'; +import { errorReporter } from 'ts/utils/error_reporter'; +import { utils } from 'ts/utils/utils'; +import { Web3Wrapper } from 'ts/web3_wrapper'; import Web3 = require('web3'); import ProviderEngine = require('web3-provider-engine'); import FilterSubprovider = require('web3-provider-engine/subproviders/filters'); import * as MintableArtifacts from '../contracts/Mintable.json'; -const ALLOWANCE_TO_ZERO_GAS_AMOUNT = 45730; const BLOCK_NUMBER_BACK_TRACK = 50; export class Blockchain { public networkId: number; public nodeVersion: string; - private zeroEx: ZeroEx; - private dispatcher: Dispatcher; - private web3Wrapper?: Web3Wrapper; - private exchangeAddress: string; - private tokenTransferProxy: ContractInstance; - private tokenRegistry: ContractInstance; - private userAddress: string; - private cachedProvider: Web3.Provider; - private ledgerSubprovider: LedgerWalletSubprovider; - private zrxPollIntervalId: number; - private static async onPageLoadAsync() { + private _zeroEx: ZeroEx; + private _dispatcher: Dispatcher; + private _web3Wrapper?: Web3Wrapper; + private _exchangeAddress: string; + private _userAddress: string; + private _cachedProvider: Web3.Provider; + private _ledgerSubprovider: LedgerWalletSubprovider; + private _zrxPollIntervalId: NodeJS.Timer; + private static async _onPageLoadAsync(): Promise<void> { if (document.readyState === 'complete') { return; // Already loaded } - return new Promise((resolve, reject) => { - window.onload = resolve; + return new Promise<void>((resolve, reject) => { + window.onload = () => resolve(); }); } - private static getNameGivenProvider(provider: Web3.Provider): string { + private static _getNameGivenProvider(provider: Web3.Provider): string { if (!_.isUndefined((provider as any).isMetaMask)) { - return constants.METAMASK_PROVIDER_NAME; + return constants.PROVIDER_NAME_METAMASK; } // HACK: We use the fact that Parity Signer's provider is an instance of their // internal `Web3FrameProvider` class. const isParitySigner = _.startsWith(provider.constructor.toString(), 'function Web3FrameProvider'); if (isParitySigner) { - return constants.PARITY_SIGNER_PROVIDER_NAME; + return constants.PROVIDER_NAME_PARITY_SIGNER; } - return constants.GENERIC_PROVIDER_NAME; + return constants.PROVIDER_NAME_GENERIC; } - private static async getProviderAsync(injectedWeb3: Web3, networkIdIfExists: number) { + private static async _getProviderAsync(injectedWeb3: Web3, networkIdIfExists: number) { const doesInjectedWeb3Exist = !_.isUndefined(injectedWeb3); - const publicNodeUrlsIfExistsForNetworkId = constants.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkIdIfExists]; + const publicNodeUrlsIfExistsForNetworkId = configs.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkIdIfExists]; const isPublicNodeAvailableForNetworkId = !_.isUndefined(publicNodeUrlsIfExistsForNetworkId); let provider; @@ -110,9 +100,7 @@ export class Blockchain { provider = new ProviderEngine(); provider.addProvider(new InjectedWeb3Subprovider(injectedWeb3)); provider.addProvider(new FilterSubprovider()); - provider.addProvider(new RedundantRPCSubprovider( - publicNodeUrlsIfExistsForNetworkId, - )); + provider.addProvider(new RedundantRPCSubprovider(publicNodeUrlsIfExistsForNetworkId)); provider.start(); } else if (doesInjectedWeb3Exist) { // Since no public node for this network, all requests go to injectedWeb3 instance @@ -123,41 +111,37 @@ export class Blockchain { // injected into their browser. provider = new ProviderEngine(); provider.addProvider(new FilterSubprovider()); - const networkId = configs.isMainnetEnabled ? - constants.MAINNET_NETWORK_ID : - constants.TESTNET_NETWORK_ID; - provider.addProvider(new RedundantRPCSubprovider( - constants.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkId], - )); + const networkId = configs.IS_MAINNET_ENABLED ? constants.NETWORK_ID_MAINNET : constants.NETWORK_ID_TESTNET; + provider.addProvider(new RedundantRPCSubprovider(configs.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkId])); provider.start(); } return provider; } constructor(dispatcher: Dispatcher, isSalePage: boolean = false) { - this.dispatcher = dispatcher; - this.userAddress = ''; + this._dispatcher = dispatcher; + this._userAddress = ''; // tslint:disable-next-line:no-floating-promises - this.onPageLoadInitFireAndForgetAsync(); + this._onPageLoadInitFireAndForgetAsync(); } public async networkIdUpdatedFireAndForgetAsync(newNetworkId: number) { const isConnected = !_.isUndefined(newNetworkId); if (!isConnected) { this.networkId = newNetworkId; - this.dispatcher.encounteredBlockchainError(BlockchainErrs.DISCONNECTED_FROM_ETHEREUM_NODE); - this.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); + this._dispatcher.encounteredBlockchainError(BlockchainErrs.DisconnectedFromEthereumNode); + this._dispatcher.updateShouldBlockchainErrDialogBeOpen(true); } else if (this.networkId !== newNetworkId) { this.networkId = newNetworkId; - this.dispatcher.encounteredBlockchainError(''); - await this.fetchTokenInformationAsync(); - await this.rehydrateStoreWithContractEvents(); + this._dispatcher.encounteredBlockchainError(BlockchainErrs.NoError); + await this._fetchTokenInformationAsync(); + await this._rehydrateStoreWithContractEvents(); } } public async userAddressUpdatedFireAndForgetAsync(newUserAddress: string) { - if (this.userAddress !== newUserAddress) { - this.userAddress = newUserAddress; - await this.fetchTokenInformationAsync(); - await this.rehydrateStoreWithContractEvents(); + if (this._userAddress !== newUserAddress) { + this._userAddress = newUserAddress; + await this._fetchTokenInformationAsync(); + await this._rehydrateStoreWithContractEvents(); } } public async nodeVersionUpdatedFireAndForgetAsync(nodeVersion: string) { @@ -166,80 +150,85 @@ export class Blockchain { } } public async isAddressInTokenRegistryAsync(tokenAddress: string): Promise<boolean> { - utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.'); - const tokenIfExists = await this.zeroEx.tokenRegistry.getTokenIfExistsAsync(tokenAddress); + utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.'); + // HACK: temporarily whitelist the new WETH token address `as if` they were + // already in the tokenRegistry. + // TODO: Remove this hack once we've updated the TokenRegistries + // Airtable task: https://airtable.com/tblFe0Q9JuKJPYbTn/viwsOG2Y97qdIeCIO/recv3VGmIorFzHBVz + if (configs.SHOULD_DEPRECATE_OLD_WETH_TOKEN && tokenAddress === configs.NEW_WRAPPED_ETHERS[this.networkId]) { + return true; + } + const tokenIfExists = await this._zeroEx.tokenRegistry.getTokenIfExistsAsync(tokenAddress); return !_.isUndefined(tokenIfExists); } public getLedgerDerivationPathIfExists(): string { - if (_.isUndefined(this.ledgerSubprovider)) { + if (_.isUndefined(this._ledgerSubprovider)) { return undefined; } - const path = this.ledgerSubprovider.getPath(); + const path = this._ledgerSubprovider.getPath(); return path; } public updateLedgerDerivationPathIfExists(path: string) { - if (_.isUndefined(this.ledgerSubprovider)) { + if (_.isUndefined(this._ledgerSubprovider)) { return; // noop } - this.ledgerSubprovider.setPath(path); + this._ledgerSubprovider.setPath(path); } public updateLedgerDerivationIndex(pathIndex: number) { - if (_.isUndefined(this.ledgerSubprovider)) { + if (_.isUndefined(this._ledgerSubprovider)) { return; // noop } - this.ledgerSubprovider.setPathIndex(pathIndex); + this._ledgerSubprovider.setPathIndex(pathIndex); } public async providerTypeUpdatedFireAndForgetAsync(providerType: ProviderType) { - utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.'); + utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.'); // Should actually be Web3.Provider|ProviderEngine union type but it causes issues // later on in the logic. let provider; switch (providerType) { - case ProviderType.LEDGER: { + case ProviderType.Ledger: { const isU2FSupported = await utils.isU2FSupportedAsync(); if (!isU2FSupported) { throw new Error('Cannot update providerType to LEDGER without U2F support'); } // Cache injected provider so that we can switch the user back to it easily - this.cachedProvider = this.web3Wrapper.getProviderObj(); + this._cachedProvider = this._web3Wrapper.getProviderObj(); - this.dispatcher.updateUserAddress(''); // Clear old userAddress + this._dispatcher.updateUserAddress(''); // Clear old userAddress provider = new ProviderEngine(); const ledgerWalletConfigs = { networkId: this.networkId, ledgerEthereumClientFactoryAsync: ledgerEthereumBrowserClientFactoryAsync, }; - this.ledgerSubprovider = new LedgerSubprovider(ledgerWalletConfigs); - provider.addProvider(this.ledgerSubprovider); + this._ledgerSubprovider = new LedgerSubprovider(ledgerWalletConfigs); + provider.addProvider(this._ledgerSubprovider); provider.addProvider(new FilterSubprovider()); - const networkId = configs.isMainnetEnabled ? - constants.MAINNET_NETWORK_ID : - constants.TESTNET_NETWORK_ID; - provider.addProvider(new RedundantRPCSubprovider( - constants.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkId], - )); + const networkId = configs.IS_MAINNET_ENABLED + ? constants.NETWORK_ID_MAINNET + : constants.NETWORK_ID_TESTNET; + provider.addProvider(new RedundantRPCSubprovider(configs.PUBLIC_NODE_URLS_BY_NETWORK_ID[networkId])); provider.start(); - this.web3Wrapper.destroy(); + this._web3Wrapper.destroy(); const shouldPollUserAddress = false; - this.web3Wrapper = new Web3Wrapper(this.dispatcher, provider, this.networkId, shouldPollUserAddress); - this.zeroEx.setProvider(provider, networkId); - await this.postInstantiationOrUpdatingProviderZeroExAsync(); + this._web3Wrapper = new Web3Wrapper(this._dispatcher, provider, this.networkId, shouldPollUserAddress); + this._zeroEx.setProvider(provider, networkId); + await this._postInstantiationOrUpdatingProviderZeroExAsync(); break; } - case ProviderType.INJECTED: { - if (_.isUndefined(this.cachedProvider)) { + case ProviderType.Injected: { + if (_.isUndefined(this._cachedProvider)) { return; // Going from injected to injected, so we noop } - provider = this.cachedProvider; + provider = this._cachedProvider; const shouldPollUserAddress = true; - this.web3Wrapper = new Web3Wrapper(this.dispatcher, provider, this.networkId, shouldPollUserAddress); - this.zeroEx.setProvider(provider, this.networkId); - await this.postInstantiationOrUpdatingProviderZeroExAsync(); - delete this.ledgerSubprovider; - delete this.cachedProvider; + this._web3Wrapper = new Web3Wrapper(this._dispatcher, provider, this.networkId, shouldPollUserAddress); + this._zeroEx.setProvider(provider, this.networkId); + await this._postInstantiationOrUpdatingProviderZeroExAsync(); + delete this._ledgerSubprovider; + delete this._cachedProvider; break; } @@ -247,40 +236,54 @@ export class Blockchain { throw utils.spawnSwitchErr('providerType', providerType); } - await this.fetchTokenInformationAsync(); + await this._fetchTokenInformationAsync(); } public async setProxyAllowanceAsync(token: Token, amountInBaseUnits: BigNumber): Promise<void> { - utils.assert(this.isValidAddress(token.address), BlockchainCallErrs.TOKEN_ADDRESS_IS_INVALID); - utils.assert(this.doesUserAddressExist(), BlockchainCallErrs.USER_HAS_NO_ASSOCIATED_ADDRESSES); - utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.'); + utils.assert(this.isValidAddress(token.address), BlockchainCallErrs.TokenAddressIsInvalid); + utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); + utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.'); - const txHash = await this.zeroEx.token.setProxyAllowanceAsync( - token.address, this.userAddress, amountInBaseUnits, + const txHash = await this._zeroEx.token.setProxyAllowanceAsync( + token.address, + this._userAddress, + amountInBaseUnits, ); - await this.showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); + await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); const allowance = amountInBaseUnits; - this.dispatcher.replaceTokenAllowanceByAddress(token.address, allowance); + this._dispatcher.replaceTokenAllowanceByAddress(token.address, allowance); } - public async transferAsync(token: Token, toAddress: string, - amountInBaseUnits: BigNumber): Promise<void> { - const txHash = await this.zeroEx.token.transferAsync( - token.address, this.userAddress, toAddress, amountInBaseUnits, - ); - await this.showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); - const etherScanLinkIfExists = utils.getEtherScanLinkIfExists(txHash, this.networkId, EtherscanLinkSuffixes.tx); - this.dispatcher.showFlashMessage(React.createElement(TokenSendCompleted, { - etherScanLinkIfExists, - token, + public async transferAsync(token: Token, toAddress: string, amountInBaseUnits: BigNumber): Promise<void> { + const txHash = await this._zeroEx.token.transferAsync( + token.address, + this._userAddress, toAddress, amountInBaseUnits, - })); - } - public portalOrderToSignedOrder(maker: string, taker: string, makerTokenAddress: string, - takerTokenAddress: string, makerTokenAmount: BigNumber, - takerTokenAmount: BigNumber, makerFee: BigNumber, - takerFee: BigNumber, expirationUnixTimestampSec: BigNumber, - feeRecipient: string, - signatureData: SignatureData, salt: BigNumber): SignedOrder { + ); + await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); + const etherScanLinkIfExists = utils.getEtherScanLinkIfExists(txHash, this.networkId, EtherscanLinkSuffixes.Tx); + this._dispatcher.showFlashMessage( + React.createElement(TokenSendCompleted, { + etherScanLinkIfExists, + token, + toAddress, + amountInBaseUnits, + }), + ); + } + public portalOrderToSignedOrder( + maker: string, + taker: string, + makerTokenAddress: string, + takerTokenAddress: string, + makerTokenAmount: BigNumber, + takerTokenAmount: BigNumber, + makerFee: BigNumber, + takerFee: BigNumber, + expirationUnixTimestampSec: BigNumber, + feeRecipient: string, + signatureData: SignatureData, + salt: BigNumber, + ): SignedOrder { const ecSignature = signatureData; const exchangeContractAddress = this.getExchangeContractAddressIfExists(); const takerOrNullAddress = _.isEmpty(taker) ? constants.NULL_ADDRESS : taker; @@ -301,127 +304,140 @@ export class Blockchain { }; return signedOrder; } - public async fillOrderAsync(signedOrder: SignedOrder, - fillTakerTokenAmount: BigNumber): Promise<BigNumber> { - utils.assert(this.doesUserAddressExist(), BlockchainCallErrs.USER_HAS_NO_ASSOCIATED_ADDRESSES); + public async fillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber): Promise<BigNumber> { + utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); const shouldThrowOnInsufficientBalanceOrAllowance = true; - const txHash = await this.zeroEx.exchange.fillOrderAsync( - signedOrder, fillTakerTokenAmount, shouldThrowOnInsufficientBalanceOrAllowance, this.userAddress, + const txHash = await this._zeroEx.exchange.fillOrderAsync( + signedOrder, + fillTakerTokenAmount, + shouldThrowOnInsufficientBalanceOrAllowance, + this._userAddress, ); - const receipt = await this.showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); + const receipt = await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); const logs: Array<LogWithDecodedArgs<ExchangeContractEventArgs>> = receipt.logs as any; - this.zeroEx.exchange.throwLogErrorsAsErrors(logs); - const logFill = _.find(logs, {event: 'LogFill'}); - const args = logFill.args as any as LogFillContractEventArgs; + this._zeroEx.exchange.throwLogErrorsAsErrors(logs); + const logFill = _.find(logs, { event: 'LogFill' }); + const args = (logFill.args as any) as LogFillContractEventArgs; const filledTakerTokenAmount = args.filledTakerTokenAmount; return filledTakerTokenAmount; } - public async cancelOrderAsync(signedOrder: SignedOrder, - cancelTakerTokenAmount: BigNumber): Promise<BigNumber> { - const txHash = await this.zeroEx.exchange.cancelOrderAsync( - signedOrder, cancelTakerTokenAmount, - ); - const receipt = await this.showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); + public async cancelOrderAsync(signedOrder: SignedOrder, cancelTakerTokenAmount: BigNumber): Promise<BigNumber> { + const txHash = await this._zeroEx.exchange.cancelOrderAsync(signedOrder, cancelTakerTokenAmount); + const receipt = await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); const logs: Array<LogWithDecodedArgs<ExchangeContractEventArgs>> = receipt.logs as any; - this.zeroEx.exchange.throwLogErrorsAsErrors(logs); - const logCancel = _.find(logs, {event: ExchangeEvents.LogCancel}); - const args = logCancel.args as any as LogCancelContractEventArgs; + this._zeroEx.exchange.throwLogErrorsAsErrors(logs); + const logCancel = _.find(logs, { event: ExchangeEvents.LogCancel }); + const args = (logCancel.args as any) as LogCancelContractEventArgs; const cancelledTakerTokenAmount = args.cancelledTakerTokenAmount; return cancelledTakerTokenAmount; } public async getUnavailableTakerAmountAsync(orderHash: string): Promise<BigNumber> { utils.assert(ZeroEx.isValidOrderHash(orderHash), 'Must be valid orderHash'); - utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.'); - const unavailableTakerAmount = await this.zeroEx.exchange.getUnavailableTakerAmountAsync(orderHash); + utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.'); + const unavailableTakerAmount = await this._zeroEx.exchange.getUnavailableTakerAmountAsync(orderHash); return unavailableTakerAmount; } public getExchangeContractAddressIfExists() { - return this.exchangeAddress; - } - public async validateFillOrderThrowIfInvalidAsync(signedOrder: SignedOrder, - fillTakerTokenAmount: BigNumber, - takerAddress: string): Promise<void> { - await this.zeroEx.exchange.validateFillOrderThrowIfInvalidAsync( - signedOrder, fillTakerTokenAmount, takerAddress); + return this._exchangeAddress; + } + public async validateFillOrderThrowIfInvalidAsync( + signedOrder: SignedOrder, + fillTakerTokenAmount: BigNumber, + takerAddress: string, + ): Promise<void> { + await this._zeroEx.exchange.validateFillOrderThrowIfInvalidAsync( + signedOrder, + fillTakerTokenAmount, + takerAddress, + ); } - public async validateCancelOrderThrowIfInvalidAsync(order: Order, - cancelTakerTokenAmount: BigNumber): Promise<void> { - await this.zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(order, cancelTakerTokenAmount); + public async validateCancelOrderThrowIfInvalidAsync( + order: Order, + cancelTakerTokenAmount: BigNumber, + ): Promise<void> { + await this._zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(order, cancelTakerTokenAmount); } public isValidAddress(address: string): boolean { const lowercaseAddress = address.toLowerCase(); - return this.web3Wrapper.isAddress(lowercaseAddress); + return this._web3Wrapper.isAddress(lowercaseAddress); } public async pollTokenBalanceAsync(token: Token) { - utils.assert(this.doesUserAddressExist(), BlockchainCallErrs.USER_HAS_NO_ASSOCIATED_ADDRESSES); + utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); - const [currBalance] = await this.getTokenBalanceAndAllowanceAsync(this.userAddress, token.address); + const [currBalance] = await this.getTokenBalanceAndAllowanceAsync(this._userAddress, token.address); - this.zrxPollIntervalId = window.setInterval(async () => { - const [balance] = await this.getTokenBalanceAndAllowanceAsync(this.userAddress, token.address); - if (!balance.eq(currBalance)) { - this.dispatcher.replaceTokenBalanceByAddress(token.address, balance); - clearInterval(this.zrxPollIntervalId); - delete this.zrxPollIntervalId; - } - }, 5000); + this._zrxPollIntervalId = intervalUtils.setAsyncExcludingInterval( + async () => { + const [balance] = await this.getTokenBalanceAndAllowanceAsync(this._userAddress, token.address); + if (!balance.eq(currBalance)) { + this._dispatcher.replaceTokenBalanceByAddress(token.address, balance); + intervalUtils.clearAsyncExcludingInterval(this._zrxPollIntervalId); + delete this._zrxPollIntervalId; + } + }, + 5000, + (err: Error) => { + utils.consoleLog(`Polling tokenBalance failed: ${err}`); + intervalUtils.clearAsyncExcludingInterval(this._zrxPollIntervalId); + delete this._zrxPollIntervalId; + }, + ); } public async signOrderHashAsync(orderHash: string): Promise<SignatureData> { - utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.'); - const makerAddress = this.userAddress; + utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.'); + const makerAddress = this._userAddress; // If makerAddress is undefined, this means they have a web3 instance injected into their browser // but no account addresses associated with it. if (_.isUndefined(makerAddress)) { throw new Error('Tried to send a sign request but user has no associated addresses'); } - const ecSignature = await this.zeroEx.signOrderHashAsync(orderHash, makerAddress); + const ecSignature = await this._zeroEx.signOrderHashAsync(orderHash, makerAddress); const signatureData = _.extend({}, ecSignature, { hash: orderHash, }); - this.dispatcher.updateSignatureData(signatureData); + this._dispatcher.updateSignatureData(signatureData); return signatureData; } public async mintTestTokensAsync(token: Token) { - utils.assert(this.doesUserAddressExist(), BlockchainCallErrs.USER_HAS_NO_ASSOCIATED_ADDRESSES); + utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); - const mintableContract = await this.instantiateContractIfExistsAsync(MintableArtifacts, token.address); + const mintableContract = await this._instantiateContractIfExistsAsync(MintableArtifacts, token.address); await mintableContract.mint(constants.MINT_AMOUNT, { - from: this.userAddress, + from: this._userAddress, }); const balanceDelta = constants.MINT_AMOUNT; - this.dispatcher.updateTokenBalanceByAddress(token.address, balanceDelta); + this._dispatcher.updateTokenBalanceByAddress(token.address, balanceDelta); } public async getBalanceInEthAsync(owner: string): Promise<BigNumber> { - const balance = await this.web3Wrapper.getBalanceInEthAsync(owner); + const balance = await this._web3Wrapper.getBalanceInEthAsync(owner); return balance; } - public async convertEthToWrappedEthTokensAsync(amount: BigNumber): Promise<void> { - utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.'); - utils.assert(this.doesUserAddressExist(), BlockchainCallErrs.USER_HAS_NO_ASSOCIATED_ADDRESSES); + public async convertEthToWrappedEthTokensAsync(etherTokenAddress: string, amount: BigNumber): Promise<void> { + utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.'); + utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); - const txHash = await this.zeroEx.etherToken.depositAsync(amount, this.userAddress); - await this.showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); + const txHash = await this._zeroEx.etherToken.depositAsync(etherTokenAddress, amount, this._userAddress); + await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); } - public async convertWrappedEthTokensToEthAsync(amount: BigNumber): Promise<void> { - utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.'); - utils.assert(this.doesUserAddressExist(), BlockchainCallErrs.USER_HAS_NO_ASSOCIATED_ADDRESSES); + public async convertWrappedEthTokensToEthAsync(etherTokenAddress: string, amount: BigNumber): Promise<void> { + utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.'); + utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); - const txHash = await this.zeroEx.etherToken.withdrawAsync(amount, this.userAddress); - await this.showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); + const txHash = await this._zeroEx.etherToken.withdrawAsync(etherTokenAddress, amount, this._userAddress); + await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); } public async doesContractExistAtAddressAsync(address: string) { - const doesContractExist = await this.web3Wrapper.doesContractExistAtAddressAsync(address); + const doesContractExist = await this._web3Wrapper.doesContractExistAtAddressAsync(address); return doesContractExist; } public async getCurrentUserTokenBalanceAndAllowanceAsync(tokenAddress: string): Promise<BigNumber[]> { - const tokenBalanceAndAllowance = await this.getTokenBalanceAndAllowanceAsync(this.userAddress, tokenAddress); - return tokenBalanceAndAllowance; + const tokenBalanceAndAllowance = await this.getTokenBalanceAndAllowanceAsync(this._userAddress, tokenAddress); + return tokenBalanceAndAllowance; } - public async getTokenBalanceAndAllowanceAsync(ownerAddress: string, tokenAddress: string): - Promise<BigNumber[]> { - utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.'); + public async getTokenBalanceAndAllowanceAsync(ownerAddress: string, tokenAddress: string): Promise<BigNumber[]> { + utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.'); if (_.isEmpty(ownerAddress)) { const zero = new BigNumber(0); @@ -429,9 +445,9 @@ export class Blockchain { } let balance = new BigNumber(0); let allowance = new BigNumber(0); - if (this.doesUserAddressExist()) { - balance = await this.zeroEx.token.getBalanceAsync(tokenAddress, ownerAddress); - allowance = await this.zeroEx.token.getProxyAllowanceAsync(tokenAddress, ownerAddress); + if (this._doesUserAddressExist()) { + balance = await this._zeroEx.token.getBalanceAsync(tokenAddress, ownerAddress); + allowance = await this._zeroEx.token.getProxyAllowanceAsync(tokenAddress, ownerAddress); } return [balance, allowance]; } @@ -440,11 +456,8 @@ export class Blockchain { for (const token of tokens) { let balance = new BigNumber(0); let allowance = new BigNumber(0); - if (this.doesUserAddressExist()) { - [ - balance, - allowance, - ] = await this.getTokenBalanceAndAllowanceAsync(this.userAddress, token.address); + if (this._doesUserAddressExist()) { + [balance, allowance] = await this.getTokenBalanceAndAllowanceAsync(this._userAddress, token.address); } const tokenState = { balance, @@ -452,110 +465,113 @@ export class Blockchain { }; tokenStateByAddress[token.address] = tokenState; } - this.dispatcher.updateTokenStateByAddress(tokenStateByAddress); + this._dispatcher.updateTokenStateByAddress(tokenStateByAddress); } public async getUserAccountsAsync() { - utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.'); - const userAccountsIfExists = await this.zeroEx.getAvailableAddressesAsync(); + utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.'); + const userAccountsIfExists = await this._zeroEx.getAvailableAddressesAsync(); return userAccountsIfExists; } // HACK: When a user is using a Ledger, we simply dispatch the selected userAddress, which // by-passes the web3Wrapper logic for updating the prevUserAddress. We therefore need to // manually update it. This should only be called by the LedgerConfigDialog. public updateWeb3WrapperPrevUserAddress(newUserAddress: string) { - this.web3Wrapper.updatePrevUserAddress(newUserAddress); + this._web3Wrapper.updatePrevUserAddress(newUserAddress); } public destroy() { - clearInterval(this.zrxPollIntervalId); - this.web3Wrapper.destroy(); - // tslint:disable-next-line:no-floating-promises - this.stopWatchingExchangeLogFillEventsAsync(); // fire and forget - } - private async showEtherScanLinkAndAwaitTransactionMinedAsync( - txHash: string): Promise<TransactionReceiptWithDecodedLogs> { - const etherScanLinkIfExists = utils.getEtherScanLinkIfExists(txHash, this.networkId, EtherscanLinkSuffixes.tx); - this.dispatcher.showFlashMessage(React.createElement(TransactionSubmitted, { - etherScanLinkIfExists, - })); - const receipt = await this.zeroEx.awaitTransactionMinedAsync(txHash); + intervalUtils.clearAsyncExcludingInterval(this._zrxPollIntervalId); + this._web3Wrapper.destroy(); + this._stopWatchingExchangeLogFillEvents(); + } + private async _showEtherScanLinkAndAwaitTransactionMinedAsync( + txHash: string, + ): Promise<TransactionReceiptWithDecodedLogs> { + const etherScanLinkIfExists = utils.getEtherScanLinkIfExists(txHash, this.networkId, EtherscanLinkSuffixes.Tx); + this._dispatcher.showFlashMessage( + React.createElement(TransactionSubmitted, { + etherScanLinkIfExists, + }), + ); + const receipt = await this._zeroEx.awaitTransactionMinedAsync(txHash); return receipt; } - private doesUserAddressExist(): boolean { - return this.userAddress !== ''; + private _doesUserAddressExist(): boolean { + return this._userAddress !== ''; } - private async rehydrateStoreWithContractEvents() { + private async _rehydrateStoreWithContractEvents() { // Ensure we are only ever listening to one set of events - await this.stopWatchingExchangeLogFillEventsAsync(); + this._stopWatchingExchangeLogFillEvents(); - if (!this.doesUserAddressExist()) { + if (!this._doesUserAddressExist()) { return; // short-circuit } - if (!_.isUndefined(this.zeroEx)) { + if (!_.isUndefined(this._zeroEx)) { // Since we do not have an index on the `taker` address and want to show // transactions where an account is either the `maker` or `taker`, we loop // through all fill events, and filter/cache them client-side. const filterIndexObj = {}; - await this.startListeningForExchangeLogFillEventsAsync(filterIndexObj); + await this._startListeningForExchangeLogFillEventsAsync(filterIndexObj); } } - private async startListeningForExchangeLogFillEventsAsync(indexFilterValues: IndexedFilterValues): Promise<void> { - utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.'); - utils.assert(this.doesUserAddressExist(), BlockchainCallErrs.USER_HAS_NO_ASSOCIATED_ADDRESSES); + private async _startListeningForExchangeLogFillEventsAsync(indexFilterValues: IndexedFilterValues): Promise<void> { + utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.'); + utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); // Fetch historical logs - await this.fetchHistoricalExchangeLogFillEventsAsync(indexFilterValues); + await this._fetchHistoricalExchangeLogFillEventsAsync(indexFilterValues); // Start a subscription for new logs - const exchangeAddress = this.getExchangeContractAddressIfExists(); - const subscriptionId = this.zeroEx.exchange.subscribe( - ExchangeEvents.LogFill, indexFilterValues, + this._zeroEx.exchange.subscribe( + ExchangeEvents.LogFill, + indexFilterValues, async (err: Error, decodedLogEvent: DecodedLogEvent<LogFillContractEventArgs>) => { - if (err) { - // Note: it's not entirely clear from the documentation which - // errors will be thrown by `watch`. For now, let's log the error - // to rollbar and stop watching when one occurs - // tslint:disable-next-line:no-floating-promises - errorReporter.reportAsync(err); // fire and forget - // tslint:disable-next-line:no-floating-promises - this.stopWatchingExchangeLogFillEventsAsync(); // fire and forget - return; - } else { - const decodedLog = decodedLogEvent.log; - if (!this.doesLogEventInvolveUser(decodedLog)) { - return; // We aren't interested in the fill event - } - this.updateLatestFillsBlockIfNeeded(decodedLog.blockNumber); - const fill = await this.convertDecodedLogToFillAsync(decodedLog); - if (decodedLogEvent.isRemoved) { - tradeHistoryStorage.removeFillFromUser(this.userAddress, this.networkId, fill); + if (err) { + // Note: it's not entirely clear from the documentation which + // errors will be thrown by `watch`. For now, let's log the error + // to rollbar and stop watching when one occurs + // tslint:disable-next-line:no-floating-promises + errorReporter.reportAsync(err); // fire and forget + return; } else { - tradeHistoryStorage.addFillToUser(this.userAddress, this.networkId, fill); + const decodedLog = decodedLogEvent.log; + if (!this._doesLogEventInvolveUser(decodedLog)) { + return; // We aren't interested in the fill event + } + this._updateLatestFillsBlockIfNeeded(decodedLog.blockNumber); + const fill = await this._convertDecodedLogToFillAsync(decodedLog); + if (decodedLogEvent.isRemoved) { + tradeHistoryStorage.removeFillFromUser(this._userAddress, this.networkId, fill); + } else { + tradeHistoryStorage.addFillToUser(this._userAddress, this.networkId, fill); + } } - } - }); + }, + ); } - private async fetchHistoricalExchangeLogFillEventsAsync(indexFilterValues: IndexedFilterValues) { - const fromBlock = tradeHistoryStorage.getFillsLatestBlock(this.userAddress, this.networkId); - const subscriptionOpts: SubscriptionOpts = { + private async _fetchHistoricalExchangeLogFillEventsAsync(indexFilterValues: IndexedFilterValues) { + const fromBlock = tradeHistoryStorage.getFillsLatestBlock(this._userAddress, this.networkId); + const blockRange: BlockRange = { fromBlock, toBlock: 'latest' as BlockParam, }; - const decodedLogs = await this.zeroEx.exchange.getLogsAsync<LogFillContractEventArgs>( - ExchangeEvents.LogFill, subscriptionOpts, indexFilterValues, + const decodedLogs = await this._zeroEx.exchange.getLogsAsync<LogFillContractEventArgs>( + ExchangeEvents.LogFill, + blockRange, + indexFilterValues, ); for (const decodedLog of decodedLogs) { - if (!this.doesLogEventInvolveUser(decodedLog)) { + if (!this._doesLogEventInvolveUser(decodedLog)) { continue; // We aren't interested in the fill event } - this.updateLatestFillsBlockIfNeeded(decodedLog.blockNumber); - const fill = await this.convertDecodedLogToFillAsync(decodedLog); - tradeHistoryStorage.addFillToUser(this.userAddress, this.networkId, fill); + this._updateLatestFillsBlockIfNeeded(decodedLog.blockNumber); + const fill = await this._convertDecodedLogToFillAsync(decodedLog); + tradeHistoryStorage.addFillToUser(this._userAddress, this.networkId, fill); } } - private async convertDecodedLogToFillAsync(decodedLog: LogWithDecodedArgs<LogFillContractEventArgs>) { + private async _convertDecodedLogToFillAsync(decodedLog: LogWithDecodedArgs<LogFillContractEventArgs>) { const args = decodedLog.args; - const blockTimestamp = await this.web3Wrapper.getBlockTimestampAsync(decodedLog.blockHash); + const blockTimestamp = await this._web3Wrapper.getBlockTimestampAsync(decodedLog.blockHash); const fill = { filledTakerTokenAmount: args.filledTakerTokenAmount, filledMakerTokenAmount: args.filledMakerTokenAmount, @@ -572,13 +588,12 @@ export class Blockchain { }; return fill; } - private doesLogEventInvolveUser(decodedLog: LogWithDecodedArgs<LogFillContractEventArgs>) { + private _doesLogEventInvolveUser(decodedLog: LogWithDecodedArgs<LogFillContractEventArgs>) { const args = decodedLog.args; - const isUserMakerOrTaker = args.maker === this.userAddress || - args.taker === this.userAddress; + const isUserMakerOrTaker = args.maker === this._userAddress || args.taker === this._userAddress; return isUserMakerOrTaker; } - private updateLatestFillsBlockIfNeeded(blockNumber: number) { + private _updateLatestFillsBlockIfNeeded(blockNumber: number) { const isBlockPending = _.isNull(blockNumber); if (!isBlockPending) { // Hack: I've observed the behavior where a client won't register certain fill events @@ -587,27 +602,39 @@ export class Blockchain { // would still attempt to re-fetch events from the previous 50 blocks, but won't need to // re-fetch all events in all blocks. // TODO: Debug if this is a race condition, and apply a more precise fix - const blockNumberToSet = blockNumber - BLOCK_NUMBER_BACK_TRACK < 0 ? - 0 : - blockNumber - BLOCK_NUMBER_BACK_TRACK; - tradeHistoryStorage.setFillsLatestBlock(this.userAddress, this.networkId, blockNumberToSet); + const blockNumberToSet = + blockNumber - BLOCK_NUMBER_BACK_TRACK < 0 ? 0 : blockNumber - BLOCK_NUMBER_BACK_TRACK; + tradeHistoryStorage.setFillsLatestBlock(this._userAddress, this.networkId, blockNumberToSet); } } - private async stopWatchingExchangeLogFillEventsAsync() { - this.zeroEx.exchange.unsubscribeAll(); + private _stopWatchingExchangeLogFillEvents(): void { + this._zeroEx.exchange.unsubscribeAll(); } - private async getTokenRegistryTokensByAddressAsync(): Promise<TokenByAddress> { - utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.'); - const tokenRegistryTokens = await this.zeroEx.tokenRegistry.getTokensAsync(); + private async _getTokenRegistryTokensByAddressAsync(): Promise<TokenByAddress> { + utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.'); + const tokenRegistryTokens = await this._zeroEx.tokenRegistry.getTokensAsync(); const tokenByAddress: TokenByAddress = {}; _.each(tokenRegistryTokens, (t: ZeroExToken, i: number) => { // HACK: For now we have a hard-coded list of iconUrls for the dummyTokens // TODO: Refactor this out and pull the iconUrl directly from the TokenRegistry - const iconUrl = constants.iconUrlBySymbol[t.symbol]; + const iconUrl = configs.ICON_URL_BY_SYMBOL[t.symbol]; + // HACK: Temporarily we hijack the WETH addresses fetched from the tokenRegistry + // so that we can take our time with actually updating it. This ensures that when + // we deploy the new WETH page, everyone will re-fill their trackedTokens with the + // new canonical WETH. + // TODO: Remove this hack once we've updated the TokenRegistries + // Airtable task: https://airtable.com/tblFe0Q9JuKJPYbTn/viwsOG2Y97qdIeCIO/recv3VGmIorFzHBVz + let address = t.address; + if (configs.SHOULD_DEPRECATE_OLD_WETH_TOKEN && t.symbol === 'WETH') { + const newEtherTokenAddressIfExists = configs.NEW_WRAPPED_ETHERS[this.networkId]; + if (!_.isUndefined(newEtherTokenAddressIfExists)) { + address = newEtherTokenAddressIfExists; + } + } const token: Token = { iconUrl, - address: t.address, + address, name: t.name, symbol: t.symbol, decimals: t.decimals, @@ -618,8 +645,8 @@ export class Blockchain { }); return tokenByAddress; } - private async onPageLoadInitFireAndForgetAsync() { - await Blockchain.onPageLoadAsync(); // wait for page to load + private async _onPageLoadInitFireAndForgetAsync() { + await Blockchain._onPageLoadAsync(); // wait for page to load // Hack: We need to know the networkId the injectedWeb3 is connected to (if it is defined) in // order to properly instantiate the web3Wrapper. Since we must use the async call, we cannot @@ -637,62 +664,63 @@ export class Blockchain { } } - const provider = await Blockchain.getProviderAsync(injectedWeb3, networkIdIfExists); - const networkId = !_.isUndefined(networkIdIfExists) ? networkIdIfExists : - configs.isMainnetEnabled ? - constants.MAINNET_NETWORK_ID : - constants.TESTNET_NETWORK_ID; + const provider = await Blockchain._getProviderAsync(injectedWeb3, networkIdIfExists); + const networkId = !_.isUndefined(networkIdIfExists) + ? networkIdIfExists + : configs.IS_MAINNET_ENABLED ? constants.NETWORK_ID_MAINNET : constants.NETWORK_ID_TESTNET; const zeroExConfigs = { networkId, }; - this.zeroEx = new ZeroEx(provider, zeroExConfigs); - this.updateProviderName(injectedWeb3); + this._zeroEx = new ZeroEx(provider, zeroExConfigs); + this._updateProviderName(injectedWeb3); const shouldPollUserAddress = true; - this.web3Wrapper = new Web3Wrapper(this.dispatcher, provider, networkId, shouldPollUserAddress); - await this.postInstantiationOrUpdatingProviderZeroExAsync(); + this._web3Wrapper = new Web3Wrapper(this._dispatcher, provider, networkId, shouldPollUserAddress); + await this._postInstantiationOrUpdatingProviderZeroExAsync(); } // This method should always be run after instantiating or updating the provider // of the ZeroEx instance. - private async postInstantiationOrUpdatingProviderZeroExAsync() { - utils.assert(!_.isUndefined(this.zeroEx), 'ZeroEx must be instantiated.'); - this.exchangeAddress = this.zeroEx.exchange.getContractAddress(); + private async _postInstantiationOrUpdatingProviderZeroExAsync() { + utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.'); + this._exchangeAddress = this._zeroEx.exchange.getContractAddress(); } - private updateProviderName(injectedWeb3: Web3) { + private _updateProviderName(injectedWeb3: Web3) { const doesInjectedWeb3Exist = !_.isUndefined(injectedWeb3); - const providerName = doesInjectedWeb3Exist ? - Blockchain.getNameGivenProvider(injectedWeb3.currentProvider) : - constants.PUBLIC_PROVIDER_NAME; - this.dispatcher.updateInjectedProviderName(providerName); - } - private async fetchTokenInformationAsync() { - utils.assert(!_.isUndefined(this.networkId), - 'Cannot call fetchTokenInformationAsync if disconnected from Ethereum node'); + const providerName = doesInjectedWeb3Exist + ? Blockchain._getNameGivenProvider(injectedWeb3.currentProvider) + : constants.PROVIDER_NAME_PUBLIC; + this._dispatcher.updateInjectedProviderName(providerName); + } + private async _fetchTokenInformationAsync() { + utils.assert( + !_.isUndefined(this.networkId), + 'Cannot call fetchTokenInformationAsync if disconnected from Ethereum node', + ); - this.dispatcher.updateBlockchainIsLoaded(false); - this.dispatcher.clearTokenByAddress(); + this._dispatcher.updateBlockchainIsLoaded(false); + this._dispatcher.clearTokenByAddress(); - const tokenRegistryTokensByAddress = await this.getTokenRegistryTokensByAddressAsync(); + const tokenRegistryTokensByAddress = await this._getTokenRegistryTokensByAddressAsync(); // HACK: We need to fetch the userAddress here because otherwise we cannot save the // tracked tokens in localStorage under the users address nor fetch the token // balances and allowances and we need to do this in order not to trigger the blockchain // loading dialog to show up twice. First to load the contracts, and second to load the // balances and allowances. - this.userAddress = await this.web3Wrapper.getFirstAccountIfExistsAsync(); - if (!_.isEmpty(this.userAddress)) { - this.dispatcher.updateUserAddress(this.userAddress); + this._userAddress = await this._web3Wrapper.getFirstAccountIfExistsAsync(); + if (!_.isEmpty(this._userAddress)) { + this._dispatcher.updateUserAddress(this._userAddress); } - let trackedTokensIfExists = trackedTokenStorage.getTrackedTokensIfExists(this.userAddress, this.networkId); + let trackedTokensIfExists = trackedTokenStorage.getTrackedTokensIfExists(this._userAddress, this.networkId); const tokenRegistryTokens = _.values(tokenRegistryTokensByAddress); if (_.isUndefined(trackedTokensIfExists)) { - trackedTokensIfExists = _.map(configs.defaultTrackedTokenSymbols, symbol => { + trackedTokensIfExists = _.map(configs.DEFAULT_TRACKED_TOKEN_SYMBOLS, symbol => { const token = _.find(tokenRegistryTokens, t => t.symbol === symbol); token.isTracked = true; return token; }); _.each(trackedTokensIfExists, token => { - trackedTokenStorage.addTrackedTokenToUser(this.userAddress, this.networkId, token); + trackedTokenStorage.addTrackedTokenToUser(this._userAddress, this.networkId, token); }); } else { // Properly set all tokenRegistry tokens `isTracked` to true if they are in the existing trackedTokens array @@ -703,22 +731,22 @@ export class Blockchain { }); } const allTokens = _.uniq([...tokenRegistryTokens, ...trackedTokensIfExists]); - this.dispatcher.updateTokenByAddress(allTokens); + this._dispatcher.updateTokenByAddress(allTokens); // Get balance/allowance for tracked tokens await this.updateTokenBalancesAndAllowancesAsync(trackedTokensIfExists); const mostPopularTradingPairTokens: Token[] = [ - _.find(allTokens, {symbol: configs.defaultTrackedTokenSymbols[0]}), - _.find(allTokens, {symbol: configs.defaultTrackedTokenSymbols[1]}), + _.find(allTokens, { symbol: configs.DEFAULT_TRACKED_TOKEN_SYMBOLS[0] }), + _.find(allTokens, { symbol: configs.DEFAULT_TRACKED_TOKEN_SYMBOLS[1] }), ]; - this.dispatcher.updateChosenAssetTokenAddress(Side.deposit, mostPopularTradingPairTokens[0].address); - this.dispatcher.updateChosenAssetTokenAddress(Side.receive, mostPopularTradingPairTokens[1].address); - this.dispatcher.updateBlockchainIsLoaded(true); + this._dispatcher.updateChosenAssetTokenAddress(Side.Deposit, mostPopularTradingPairTokens[0].address); + this._dispatcher.updateChosenAssetTokenAddress(Side.Receive, mostPopularTradingPairTokens[1].address); + this._dispatcher.updateBlockchainIsLoaded(true); } - private async instantiateContractIfExistsAsync(artifact: any, address?: string): Promise<ContractInstance> { + private async _instantiateContractIfExistsAsync(artifact: any, address?: string): Promise<ContractInstance> { const c = await contract(artifact); - const providerObj = this.web3Wrapper.getProviderObj(); + const providerObj = this._web3Wrapper.getProviderObj(); c.setProvider(providerObj); const artifactNetworkConfigs = artifact.networks[this.networkId]; @@ -733,23 +761,21 @@ export class Blockchain { const doesContractExist = await this.doesContractExistAtAddressAsync(contractAddress); if (!doesContractExist) { utils.consoleLog(`Contract does not exist: ${artifact.contract_name} at ${contractAddress}`); - throw new Error(BlockchainCallErrs.CONTRACT_DOES_NOT_EXIST); + throw new Error(BlockchainCallErrs.ContractDoesNotExist); } } try { - const contractInstance = _.isUndefined(address) ? - await c.deployed() : - await c.at(address); + const contractInstance = _.isUndefined(address) ? await c.deployed() : await c.at(address); return contractInstance; } catch (err) { const errMsg = `${err}`; utils.consoleLog(`Notice: Error encountered: ${err} ${err.stack}`); if (_.includes(errMsg, 'not been deployed to detected network')) { - throw new Error(BlockchainCallErrs.CONTRACT_DOES_NOT_EXIST); + throw new Error(BlockchainCallErrs.ContractDoesNotExist); } else { await errorReporter.reportAsync(err); - throw new Error(BlockchainCallErrs.UNHANDLED_ERROR); + throw new Error(BlockchainCallErrs.UnhandledError); } } } diff --git a/packages/website/ts/components/dialogs/blockchain_err_dialog.tsx b/packages/website/ts/components/dialogs/blockchain_err_dialog.tsx index 963bd4388..f555ca6b1 100644 --- a/packages/website/ts/components/dialogs/blockchain_err_dialog.tsx +++ b/packages/website/ts/components/dialogs/blockchain_err_dialog.tsx @@ -1,12 +1,12 @@ import * as _ from 'lodash'; import Dialog from 'material-ui/Dialog'; import FlatButton from 'material-ui/FlatButton'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; -import {Blockchain} from 'ts/blockchain'; -import {BlockchainErrs} from 'ts/types'; -import {configs} from 'ts/utils/configs'; -import {constants} from 'ts/utils/constants'; +import { Blockchain } from 'ts/blockchain'; +import { BlockchainErrs } from 'ts/types'; +import { colors } from 'ts/utils/colors'; +import { configs } from 'ts/utils/configs'; +import { constants } from 'ts/utils/constants'; interface BlockchainErrDialogProps { blockchain: Blockchain; @@ -31,127 +31,126 @@ export class BlockchainErrDialog extends React.Component<BlockchainErrDialogProp const hasWalletAddress = this.props.userAddress !== ''; return ( <Dialog - title={this.getTitle(hasWalletAddress)} - titleStyle={{fontWeight: 100}} + title={this._getTitle(hasWalletAddress)} + titleStyle={{ fontWeight: 100 }} actions={dialogActions} open={this.props.isOpen} - contentStyle={{width: 400}} + contentStyle={{ width: 400 }} onRequestClose={this.props.toggleDialogFn.bind(this.props.toggleDialogFn, false)} autoScrollBodyContent={true} > - <div className="pt2" style={{color: colors.grey700}}> - {this.renderExplanation(hasWalletAddress)} + <div className="pt2" style={{ color: colors.grey700 }}> + {this._renderExplanation(hasWalletAddress)} </div> </Dialog> ); } - private getTitle(hasWalletAddress: boolean) { - if (this.props.blockchainErr === BlockchainErrs.A_CONTRACT_NOT_DEPLOYED_ON_NETWORK) { + private _getTitle(hasWalletAddress: boolean) { + if (this.props.blockchainErr === BlockchainErrs.AContractNotDeployedOnNetwork) { return '0x smart contracts not found'; } else if (!hasWalletAddress) { return 'Enable wallet communication'; - } else if (this.props.blockchainErr === BlockchainErrs.DISCONNECTED_FROM_ETHEREUM_NODE) { + } else if (this.props.blockchainErr === BlockchainErrs.DisconnectedFromEthereumNode) { return 'Disconnected from Ethereum network'; } else { return 'Unexpected error'; } } - private renderExplanation(hasWalletAddress: boolean) { - if (this.props.blockchainErr === BlockchainErrs.A_CONTRACT_NOT_DEPLOYED_ON_NETWORK) { - return this.renderContractsNotDeployedExplanation(); + private _renderExplanation(hasWalletAddress: boolean) { + if (this.props.blockchainErr === BlockchainErrs.AContractNotDeployedOnNetwork) { + return this._renderContractsNotDeployedExplanation(); } else if (!hasWalletAddress) { - return this.renderNoWalletFoundExplanation(); - } else if (this.props.blockchainErr === BlockchainErrs.DISCONNECTED_FROM_ETHEREUM_NODE) { - return this.renderDisconnectedFromNode(); + return this._renderNoWalletFoundExplanation(); + } else if (this.props.blockchainErr === BlockchainErrs.DisconnectedFromEthereumNode) { + return this._renderDisconnectedFromNode(); } else { - return this.renderUnexpectedErrorExplanation(); + return this._renderUnexpectedErrorExplanation(); } } - private renderDisconnectedFromNode() { + private _renderDisconnectedFromNode() { return ( <div> - You were disconnected from the backing Ethereum node. - {' '}If using <a href={constants.METAMASK_CHROME_STORE_URL} target="_blank"> + You were disconnected from the backing Ethereum node. If using{' '} + <a href={constants.URL_METAMASK_CHROME_STORE} target="_blank"> Metamask - </a> or <a href={constants.MIST_DOWNLOAD_URL} target="_blank">Mist</a> try refreshing - {' '}the page. If using a locally hosted Ethereum node, make sure it's still running. + </a>{' '} + or{' '} + <a href={constants.URL_MIST_DOWNLOAD} target="_blank"> + Mist + </a>{' '} + try refreshing the page. If using a locally hosted Ethereum node, make sure it's still running. </div> ); } - private renderUnexpectedErrorExplanation() { - return ( - <div> - We encountered an unexpected error. Please try refreshing the page. - </div> - ); + private _renderUnexpectedErrorExplanation() { + return <div>We encountered an unexpected error. Please try refreshing the page.</div>; } - private renderNoWalletFoundExplanation() { + private _renderNoWalletFoundExplanation() { return ( <div> <div> - We were unable to access an Ethereum wallet you control. In order to interact - {' '}with the 0x portal dApp, - we need a way to interact with one of your Ethereum wallets. - {' '}There are two easy ways you can enable us to do that: + We were unable to access an Ethereum wallet you control. In order to interact with the 0x portal + dApp, we need a way to interact with one of your Ethereum wallets. There are two easy ways you can + enable us to do that: </div> <h4>1. Metamask chrome extension</h4> <div> You can install the{' '} - <a href={constants.METAMASK_CHROME_STORE_URL} target="_blank"> + <a href={constants.URL_METAMASK_CHROME_STORE} target="_blank"> Metamask - </a> Chrome extension Ethereum wallet. Once installed and set up, refresh this page. + </a>{' '} + Chrome extension Ethereum wallet. Once installed and set up, refresh this page. <div className="pt1"> - <span className="bold">Note:</span> - {' '}If you already have Metamask installed, make sure it is unlocked. + <span className="bold">Note:</span> If you already have Metamask installed, make sure it is + unlocked. </div> </div> <h4>Parity Signer</h4> <div> - The <a href={constants.PARITY_CHROME_STORE_URL} target="_blank">Parity Signer - Chrome extension</a>{' '}lets you connect to a locally running Parity node. - Make sure you have started your local Parity node with{' '} - {configs.isMainnetEnabled && '`parity ui` or'} `parity --chain kovan ui`{' '} - in order to connect to {configs.isMainnetEnabled ? 'mainnet or Kovan respectively.' : 'Kovan.'} + The{' '} + <a href={constants.URL_PARITY_CHROME_STORE} target="_blank"> + Parity Signer Chrome extension + </a>{' '} + lets you connect to a locally running Parity node. Make sure you have started your local Parity node + with {configs.IS_MAINNET_ENABLED && '`parity ui` or'} `parity --chain kovan ui` in order to connect + to {configs.IS_MAINNET_ENABLED ? 'mainnet or Kovan respectively.' : 'Kovan.'} </div> <div className="pt2"> - <span className="bold">Note:</span> - {' '}If you have done one of the above steps and are still seeing this message, - {' '}we might still be unable to retrieve an Ethereum address by calling `web3.eth.accounts`. - {' '}Make sure you have created at least one Ethereum address. + <span className="bold">Note:</span> If you have done one of the above steps and are still seeing + this message, we might still be unable to retrieve an Ethereum address by calling + `web3.eth.accounts`. Make sure you have created at least one Ethereum address. </div> </div> ); } - private renderContractsNotDeployedExplanation() { + private _renderContractsNotDeployedExplanation() { return ( <div> <div> - The 0x smart contracts are not deployed on the Ethereum network you are - {' '}currently connected to (network Id: {this.props.networkId}). - {' '}In order to use the 0x portal dApp, - {' '}please connect to the - {' '}{constants.TESTNET_NAME} testnet (network Id: {constants.TESTNET_NETWORK_ID}) - {configs.isMainnetEnabled ? - ` or ${constants.MAINNET_NAME} (network Id: ${constants.MAINNET_NETWORK_ID}).` : - `.` - } + The 0x smart contracts are not deployed on the Ethereum network you are currently connected to + (network Id: {this.props.networkId}). In order to use the 0x portal dApp, please connect to the{' '} + {constants.TESTNET_NAME} testnet (network Id: {constants.NETWORK_ID_TESTNET}) + {configs.IS_MAINNET_ENABLED + ? ` or ${constants.MAINNET_NAME} (network Id: ${constants.NETWORK_ID_MAINNET}).` + : `.`} </div> <h4>Metamask</h4> <div> If you are using{' '} - <a href={constants.METAMASK_CHROME_STORE_URL} target="_blank"> + <a href={constants.URL_METAMASK_CHROME_STORE} target="_blank"> Metamask </a>, you can switch networks in the top left corner of the extension popover. </div> <h4>Parity Signer</h4> <div> - If using the <a href={constants.PARITY_CHROME_STORE_URL} target="_blank">Parity Signer - Chrome extension</a>, make sure to start your local Parity node with{' '} - {configs.isMainnetEnabled ? - '`parity ui` or `parity --chain Kovan ui` in order to connect to mainnet \ - or Kovan respectively.' : - '`parity --chain kovan ui` in order to connect to Kovan.' - } + If using the{' '} + <a href={constants.URL_PARITY_CHROME_STORE} target="_blank"> + Parity Signer Chrome extension + </a>, make sure to start your local Parity node with{' '} + {configs.IS_MAINNET_ENABLED + ? '`parity ui` or `parity --chain Kovan ui` in order to connect to mainnet \ + or Kovan respectively.' + : '`parity --chain kovan ui` in order to connect to Kovan.'} </div> </div> ); diff --git a/packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx b/packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx index aba5b9faf..661cc1d8c 100644 --- a/packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx +++ b/packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx @@ -1,14 +1,14 @@ -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import Dialog from 'material-ui/Dialog'; import FlatButton from 'material-ui/FlatButton'; -import RadioButton from 'material-ui/RadioButton'; -import RadioButtonGroup from 'material-ui/RadioButton/RadioButtonGroup'; import * as React from 'react'; -import {EthAmountInput} from 'ts/components/inputs/eth_amount_input'; -import {TokenAmountInput} from 'ts/components/inputs/token_amount_input'; -import {Side, Token, TokenState} from 'ts/types'; +import { EthAmountInput } from 'ts/components/inputs/eth_amount_input'; +import { TokenAmountInput } from 'ts/components/inputs/token_amount_input'; +import { Side, Token, TokenState } from 'ts/types'; +import { colors } from 'ts/utils/colors'; interface EthWethConversionDialogProps { + direction: Side; onComplete: (direction: Side, value: BigNumber) => void; onCancelled: () => void; isOpen: boolean; @@ -19,105 +19,129 @@ interface EthWethConversionDialogProps { interface EthWethConversionDialogState { value?: BigNumber; - direction: Side; shouldShowIncompleteErrs: boolean; hasErrors: boolean; } -export class EthWethConversionDialog extends - React.Component<EthWethConversionDialogProps, EthWethConversionDialogState> { +export class EthWethConversionDialog extends React.Component< + EthWethConversionDialogProps, + EthWethConversionDialogState +> { constructor() { super(); this.state = { - direction: Side.deposit, shouldShowIncompleteErrs: false, - hasErrors: true, + hasErrors: false, }; } public render() { const convertDialogActions = [ - <FlatButton - key="cancel" - label="Cancel" - onTouchTap={this.onCancel.bind(this)} - />, - <FlatButton - key="convert" - label="Convert" - primary={true} - onTouchTap={this.onConvertClick.bind(this)} - />, + <FlatButton key="cancel" label="Cancel" onTouchTap={this._onCancel.bind(this)} />, + <FlatButton key="convert" label="Convert" primary={true} onTouchTap={this._onConvertClick.bind(this)} />, ]; + const title = this.props.direction === Side.Deposit ? 'Wrap ETH' : 'Unwrap WETH'; return ( <Dialog - title="I want to convert" - titleStyle={{fontWeight: 100}} + title={title} + titleStyle={{ fontWeight: 100 }} actions={convertDialogActions} + contentStyle={{ width: 448 }} open={this.props.isOpen} > - {this.renderConversionDialogBody()} + {this._renderConversionDialogBody()} </Dialog> ); } - private renderConversionDialogBody() { + private _renderConversionDialogBody() { + const explanation = + this.props.direction === Side.Deposit + ? 'Convert your Ether into a tokenized, tradable form.' + : "Convert your Wrapped Ether back into it's native form."; + const isWrappedVersion = this.props.direction === Side.Receive; + return ( + <div> + <div className="pb2">{explanation}</div> + <div className="mx-auto" style={{ maxWidth: 312 }}> + <div className="flex"> + {this._renderCurrency(isWrappedVersion)} + <div style={{ paddingTop: 68 }}> + <i style={{ fontSize: 28, color: colors.darkBlue }} className="zmdi zmdi-arrow-right" /> + </div> + {this._renderCurrency(!isWrappedVersion)} + </div> + <div className="pt2 mx-auto" style={{ width: 245 }}> + {this.props.direction === Side.Receive ? ( + <TokenAmountInput + token={this.props.token} + tokenState={this.props.tokenState} + shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs} + shouldCheckBalance={true} + shouldCheckAllowance={false} + onChange={this._onValueChange.bind(this)} + amount={this.state.value} + onVisitBalancesPageClick={this.props.onCancelled} + /> + ) : ( + <EthAmountInput + balance={this.props.etherBalance} + amount={this.state.value} + onChange={this._onValueChange.bind(this)} + shouldCheckBalance={true} + shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs} + onVisitBalancesPageClick={this.props.onCancelled} + /> + )} + <div className="pt1" style={{ fontSize: 12 }}> + <div className="left">1 ETH = 1 WETH</div> + {this.props.direction === Side.Receive && ( + <div + className="right" + onClick={this._onMaxClick.bind(this)} + style={{ + color: colors.darkBlue, + textDecoration: 'underline', + cursor: 'pointer', + }} + > + Max + </div> + )} + </div> + </div> + </div> + </div> + ); + } + private _renderCurrency(isWrappedVersion: boolean) { + const name = isWrappedVersion ? 'Wrapped Ether' : 'Ether'; + const iconUrl = isWrappedVersion ? '/images/token_icons/ether_erc20.png' : '/images/ether.png'; + const symbol = isWrappedVersion ? 'WETH' : 'ETH'; return ( - <div className="mx-auto" style={{maxWidth: 300}}> - <RadioButtonGroup - className="pb1" - defaultSelected={this.state.direction} - name="conversionDirection" - onChange={this.onConversionDirectionChange.bind(this)} - > - <RadioButton - className="pb1" - value={Side.deposit} - label="Ether -> Ether Tokens" - /> - <RadioButton - value={Side.receive} - label="Ether Tokens -> Ether" - /> - </RadioButtonGroup> - {this.state.direction === Side.receive ? - <TokenAmountInput - label="Amount to convert" - token={this.props.token} - tokenState={this.props.tokenState} - shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs} - shouldCheckBalance={true} - shouldCheckAllowance={false} - onChange={this.onValueChange.bind(this)} - amount={this.state.value} - onVisitBalancesPageClick={this.props.onCancelled} - /> : - <EthAmountInput - label="Amount to convert" - balance={this.props.etherBalance} - amount={this.state.value} - onChange={this.onValueChange.bind(this)} - shouldCheckBalance={true} - shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs} - onVisitBalancesPageClick={this.props.onCancelled} - /> - } + <div className="mx-auto pt2"> + <div className="center" style={{ color: colors.darkBlue }}> + {name} + </div> + <div className="center py2"> + <img src={iconUrl} style={{ width: 60 }} /> + </div> + <div className="center" style={{ fontSize: 12 }}> + ({symbol}) + </div> </div> ); } - private onConversionDirectionChange(e: any, direction: Side) { + private _onMaxClick() { this.setState({ - value: undefined, - shouldShowIncompleteErrs: false, - direction, - hasErrors: true, + value: this.props.tokenState.balance, }); } - private onValueChange(isValid: boolean, amount?: BigNumber) { + private _onValueChange(isValid: boolean, amount?: BigNumber) { this.setState({ value: amount, hasErrors: !isValid, }); } - private onConvertClick() { + private _onConvertClick() { if (this.state.hasErrors) { this.setState({ shouldShowIncompleteErrs: true, @@ -127,10 +151,10 @@ export class EthWethConversionDialog extends this.setState({ value: undefined, }); - this.props.onComplete(this.state.direction, value); + this.props.onComplete(this.props.direction, value); } } - private onCancel() { + private _onCancel() { this.setState({ value: undefined, }); diff --git a/packages/website/ts/components/dialogs/ledger_config_dialog.tsx b/packages/website/ts/components/dialogs/ledger_config_dialog.tsx index d3c95a011..60db93c52 100644 --- a/packages/website/ts/components/dialogs/ledger_config_dialog.tsx +++ b/packages/website/ts/components/dialogs/ledger_config_dialog.tsx @@ -1,24 +1,18 @@ -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import Dialog from 'material-ui/Dialog'; import FlatButton from 'material-ui/FlatButton'; -import {colors} from 'material-ui/styles'; -import { - Table, - TableBody, - TableHeader, - TableHeaderColumn, - TableRow, - TableRowColumn, -} from 'material-ui/Table'; +import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table'; import TextField from 'material-ui/TextField'; import * as React from 'react'; import ReactTooltip = require('react-tooltip'); -import {Blockchain} from 'ts/blockchain'; -import {LifeCycleRaisedButton} from 'ts/components/ui/lifecycle_raised_button'; -import {Dispatcher} from 'ts/redux/dispatcher'; -import {constants} from 'ts/utils/constants'; -import {utils} from 'ts/utils/utils'; +import { Blockchain } from 'ts/blockchain'; +import { LifeCycleRaisedButton } from 'ts/components/ui/lifecycle_raised_button'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { colors } from 'ts/utils/colors'; +import { configs } from 'ts/utils/configs'; +import { constants } from 'ts/utils/constants'; +import { utils } from 'ts/utils/utils'; const VALID_ETHEREUM_DERIVATION_PATH_PREFIX = `44'/60'`; @@ -52,58 +46,45 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps, stepIndex: LedgerSteps.CONNECT, userAddresses: [], addressBalances: [], - derivationPath: constants.DEFAULT_DERIVATION_PATH, + derivationPath: configs.DEFAULT_DERIVATION_PATH, derivationErrMsg: '', }; } public render() { const dialogActions = [ - <FlatButton - key="ledgerConnectCancel" - label="Cancel" - onTouchTap={this.onClose.bind(this)} - />, + <FlatButton key="ledgerConnectCancel" label="Cancel" onTouchTap={this._onClose.bind(this)} />, ]; - const dialogTitle = this.state.stepIndex === LedgerSteps.CONNECT ? - 'Connect to your Ledger' : - 'Select desired address'; + const dialogTitle = + this.state.stepIndex === LedgerSteps.CONNECT ? 'Connect to your Ledger' : 'Select desired address'; return ( <Dialog title={dialogTitle} - titleStyle={{fontWeight: 100}} + titleStyle={{ fontWeight: 100 }} actions={dialogActions} open={this.props.isOpen} - onRequestClose={this.onClose.bind(this)} + onRequestClose={this._onClose.bind(this)} autoScrollBodyContent={true} - bodyStyle={{paddingBottom: 0}} + bodyStyle={{ paddingBottom: 0 }} > - <div style={{color: colors.grey700, paddingTop: 1}}> - {this.state.stepIndex === LedgerSteps.CONNECT && - this.renderConnectStep() - } - {this.state.stepIndex === LedgerSteps.SELECT_ADDRESS && - this.renderSelectAddressStep() - } + <div style={{ color: colors.grey700, paddingTop: 1 }}> + {this.state.stepIndex === LedgerSteps.CONNECT && this._renderConnectStep()} + {this.state.stepIndex === LedgerSteps.SELECT_ADDRESS && this._renderSelectAddressStep()} </div> </Dialog> ); } - private renderConnectStep() { + private _renderConnectStep() { return ( <div> - <div className="h4 pt3"> - Follow these instructions before proceeding: - </div> + <div className="h4 pt3">Follow these instructions before proceeding:</div> <ol> - <li className="pb1"> - Connect your Ledger Nano S & Open the Ethereum application - </li> - <li className="pb1"> - Verify that Browser Support is enabled in Settings - </li> + <li className="pb1">Connect your Ledger Nano S & Open the Ethereum application</li> + <li className="pb1">Verify that Browser Support is enabled in Settings</li> <li className="pb1"> If no Browser Support is found in settings, verify that you have{' '} - <a href="https://www.ledgerwallet.com/apps/manager" target="_blank">Firmware >1.2</a> + <a href="https://www.ledgerwallet.com/apps/manager" target="_blank"> + Firmware >1.2 + </a> </li> </ol> <div className="center pb3"> @@ -112,85 +93,74 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps, labelReady="Connect to Ledger" labelLoading="Connecting..." labelComplete="Connected!" - onClickAsyncFn={this.onConnectLedgerClickAsync.bind(this, true)} + onClickAsyncFn={this._onConnectLedgerClickAsync.bind(this, true)} /> - {this.state.didConnectFail && - <div className="pt2 left-align" style={{color: colors.red200}}> + {this.state.didConnectFail && ( + <div className="pt2 left-align" style={{ color: colors.red200 }}> Failed to connect. Follow the instructions and try again. </div> - } + )} </div> </div> ); } - private renderSelectAddressStep() { + private _renderSelectAddressStep() { return ( <div> <div> - <Table - bodyStyle={{height: 300}} - onRowSelection={this.onAddressSelected.bind(this)} - > + <Table bodyStyle={{ height: 300 }} onRowSelection={this._onAddressSelected.bind(this)}> <TableHeader displaySelectAll={false}> <TableRow> <TableHeaderColumn colSpan={2}>Address</TableHeaderColumn> <TableHeaderColumn>Balance</TableHeaderColumn> </TableRow> </TableHeader> - <TableBody> - {this.renderAddressTableRows()} - </TableBody> + <TableBody>{this._renderAddressTableRows()}</TableBody> </Table> </div> - <div className="flex pt2" style={{height: 100}}> - <div className="overflow-hidden" style={{width: 180}}> + <div className="flex pt2" style={{ height: 100 }}> + <div className="overflow-hidden" style={{ width: 180 }}> <TextField floatingLabelFixed={true} - floatingLabelStyle={{color: colors.grey500}} + floatingLabelStyle={{ color: colors.grey }} floatingLabelText="Update path derivation (advanced)" value={this.state.derivationPath} errorText={this.state.derivationErrMsg} - onChange={this.onDerivationPathChanged.bind(this)} + onChange={this._onDerivationPathChanged.bind(this)} /> </div> - <div className="pl2" style={{paddingTop: 28}}> + <div className="pl2" style={{ paddingTop: 28 }}> <LifeCycleRaisedButton labelReady="Update" labelLoading="Updating..." labelComplete="Updated!" - onClickAsyncFn={this.onFetchAddressesForDerivationPathAsync.bind(this, true)} + onClickAsyncFn={this._onFetchAddressesForDerivationPathAsync.bind(this)} /> </div> </div> </div> ); } - private renderAddressTableRows() { + private _renderAddressTableRows() { const rows = _.map(this.state.userAddresses, (userAddress: string, i: number) => { const balance = this.state.addressBalances[i]; const addressTooltipId = `address-${userAddress}`; const balanceTooltipId = `balance-${userAddress}`; - const networkName = constants.networkNameById[this.props.networkId]; + const networkName = constants.NETWORK_NAME_BY_ID[this.props.networkId]; // We specifically prefix kovan ETH. // TODO: We should probably add prefixes for all networks const isKovanNetwork = networkName === 'Kovan'; const balanceString = `${balance.toString()} ${isKovanNetwork ? 'Kovan ' : ''}ETH`; return ( - <TableRow key={userAddress} style={{height: 40}}> + <TableRow key={userAddress} style={{ height: 40 }}> <TableRowColumn colSpan={2}> - <div - data-tip={true} - data-for={addressTooltipId} - > + <div data-tip={true} data-for={addressTooltipId}> {userAddress} </div> <ReactTooltip id={addressTooltipId}>{userAddress}</ReactTooltip> </TableRowColumn> <TableRowColumn> - <div - data-tip={true} - data-for={balanceTooltipId} - > + <div data-tip={true} data-for={balanceTooltipId}> {balanceString} </div> <ReactTooltip id={balanceTooltipId}>{balanceString}</ReactTooltip> @@ -200,14 +170,14 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps, }); return rows; } - private onClose() { + private _onClose() { this.setState({ didConnectFail: false, }); const isOpen = false; this.props.toggleDialogFn(isOpen); } - private onAddressSelected(selectedRowIndexes: number[]) { + private _onAddressSelected(selectedRowIndexes: number[]) { const selectedRowIndex = selectedRowIndexes[0]; this.props.blockchain.updateLedgerDerivationIndex(selectedRowIndex); const selectedAddress = this.state.userAddresses[selectedRowIndex]; @@ -221,13 +191,15 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps, const isOpen = false; this.props.toggleDialogFn(isOpen); } - private async onFetchAddressesForDerivationPathAsync() { + private async _onFetchAddressesForDerivationPathAsync(): Promise<boolean> { const currentlySetPath = this.props.blockchain.getLedgerDerivationPathIfExists(); + let didSucceed; if (currentlySetPath === this.state.derivationPath) { - return; + didSucceed = true; + return didSucceed; } this.props.blockchain.updateLedgerDerivationPathIfExists(this.state.derivationPath); - const didSucceed = await this.fetchAddressesAndBalancesAsync(); + didSucceed = await this._fetchAddressesAndBalancesAsync(); if (!didSucceed) { this.setState({ derivationErrMsg: 'Failed to connect to Ledger.', @@ -235,11 +207,11 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps, } return didSucceed; } - private async fetchAddressesAndBalancesAsync() { + private async _fetchAddressesAndBalancesAsync() { let userAddresses: string[]; const addressBalances: BigNumber[] = []; try { - userAddresses = await this.getUserAddressesAsync(); + userAddresses = await this._getUserAddressesAsync(); for (const address of userAddresses) { const balance = await this.props.blockchain.getBalanceInEthAsync(address); addressBalances.push(balance); @@ -257,7 +229,7 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps, }); return true; } - private onDerivationPathChanged(e: any, derivationPath: string) { + private _onDerivationPathChanged(e: any, derivationPath: string) { let derivationErrMsg = ''; if (!_.startsWith(derivationPath, VALID_ETHEREUM_DERIVATION_PATH_PREFIX)) { derivationErrMsg = 'Must be valid Ethereum path.'; @@ -268,8 +240,8 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps, derivationErrMsg, }); } - private async onConnectLedgerClickAsync() { - const didSucceed = await this.fetchAddressesAndBalancesAsync(); + private async _onConnectLedgerClickAsync() { + const didSucceed = await this._fetchAddressesAndBalancesAsync(); if (didSucceed) { this.setState({ stepIndex: LedgerSteps.SELECT_ADDRESS, @@ -277,7 +249,7 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps, } return didSucceed; } - private async getUserAddressesAsync(): Promise<string[]> { + private async _getUserAddressesAsync(): Promise<string[]> { let userAddresses: string[]; userAddresses = await this.props.blockchain.getUserAccountsAsync(); diff --git a/packages/website/ts/components/dialogs/portal_disclaimer_dialog.tsx b/packages/website/ts/components/dialogs/portal_disclaimer_dialog.tsx index 1d90624ee..3ecc454a0 100644 --- a/packages/website/ts/components/dialogs/portal_disclaimer_dialog.tsx +++ b/packages/website/ts/components/dialogs/portal_disclaimer_dialog.tsx @@ -1,8 +1,7 @@ import Dialog from 'material-ui/Dialog'; import FlatButton from 'material-ui/FlatButton'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; -import {constants} from 'ts/utils/constants'; +import { colors } from 'ts/utils/colors'; interface PortalDisclaimerDialogProps { isOpen: boolean; @@ -13,31 +12,23 @@ export function PortalDisclaimerDialog(props: PortalDisclaimerDialogProps) { return ( <Dialog title="0x Portal Disclaimer" - titleStyle={{fontWeight: 100}} - actions={[ - <FlatButton - key="portalAgree" - label="I Agree" - onTouchTap={props.onToggleDialog.bind(this)} - />, - ]} + titleStyle={{ fontWeight: 100 }} + actions={[<FlatButton key="portalAgree" label="I Agree" onTouchTap={props.onToggleDialog} />]} open={props.isOpen} - onRequestClose={props.onToggleDialog.bind(this)} + onRequestClose={props.onToggleDialog} autoScrollBodyContent={true} modal={true} > - <div className="pt2" style={{color: colors.grey700}}> + <div className="pt2" style={{ color: colors.grey700 }}> <div> - 0x Portal is a free software-based tool intended to help users to - buy and sell ERC20-compatible blockchain tokens through the 0x protocol - on a purely peer-to-peer basis. 0x portal is not a regulated marketplace, - exchange or intermediary of any kind, and therefore, you should only use - 0x portal to exchange tokens that are not securities, commodity interests, - or any other form of regulated instrument. 0x has not attempted to screen - or otherwise limit the tokens that you may enter in 0x Portal. By clicking - “I Agree” below, you understand that you are solely responsible for using 0x - Portal and buying and selling tokens using 0x Portal in compliance with all - applicable laws and regulations. + 0x Portal is a free software-based tool intended to help users to buy and sell ERC20-compatible + blockchain tokens through the 0x protocol on a purely peer-to-peer basis. 0x portal is not a + regulated marketplace, exchange or intermediary of any kind, and therefore, you should only use 0x + portal to exchange tokens that are not securities, commodity interests, or any other form of + regulated instrument. 0x has not attempted to screen or otherwise limit the tokens that you may + enter in 0x Portal. By clicking “I Agree” below, you understand that you are solely responsible for + using 0x Portal and buying and selling tokens using 0x Portal in compliance with all applicable laws + and regulations. </div> </div> </Dialog> diff --git a/packages/website/ts/components/dialogs/send_dialog.tsx b/packages/website/ts/components/dialogs/send_dialog.tsx index 31afc3386..b3dbce598 100644 --- a/packages/website/ts/components/dialogs/send_dialog.tsx +++ b/packages/website/ts/components/dialogs/send_dialog.tsx @@ -1,14 +1,11 @@ -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import Dialog from 'material-ui/Dialog'; import FlatButton from 'material-ui/FlatButton'; -import RadioButton from 'material-ui/RadioButton'; -import RadioButtonGroup from 'material-ui/RadioButton/RadioButtonGroup'; import * as React from 'react'; -import {AddressInput} from 'ts/components/inputs/address_input'; -import {EthAmountInput} from 'ts/components/inputs/eth_amount_input'; -import {TokenAmountInput} from 'ts/components/inputs/token_amount_input'; -import {Side, Token, TokenState} from 'ts/types'; +import { AddressInput } from 'ts/components/inputs/address_input'; +import { TokenAmountInput } from 'ts/components/inputs/token_amount_input'; +import { Token, TokenState } from 'ts/types'; interface SendDialogProps { onComplete: (recipient: string, value: BigNumber) => void; @@ -36,37 +33,33 @@ export class SendDialog extends React.Component<SendDialogProps, SendDialogState } public render() { const transferDialogActions = [ - <FlatButton - key="cancelTransfer" - label="Cancel" - onTouchTap={this.onCancel.bind(this)} - />, + <FlatButton key="cancelTransfer" label="Cancel" onTouchTap={this._onCancel.bind(this)} />, <FlatButton key="sendTransfer" - disabled={this.hasErrors()} + disabled={this._hasErrors()} label="Send" primary={true} - onTouchTap={this.onSendClick.bind(this)} + onTouchTap={this._onSendClick.bind(this)} />, ]; return ( <Dialog title="I want to send" - titleStyle={{fontWeight: 100}} + titleStyle={{ fontWeight: 100 }} actions={transferDialogActions} open={this.props.isOpen} > - {this.renderSendDialogBody()} + {this._renderSendDialogBody()} </Dialog> ); } - private renderSendDialogBody() { + private _renderSendDialogBody() { return ( - <div className="mx-auto" style={{maxWidth: 300}}> - <div style={{height: 80}}> + <div className="mx-auto" style={{ maxWidth: 300 }}> + <div style={{ height: 80 }}> <AddressInput initialAddress={this.state.recipient} - updateAddress={this.onRecipientChange.bind(this)} + updateAddress={this._onRecipientChange.bind(this)} isRequired={true} label={'Recipient address'} hintText={'Address'} @@ -79,27 +72,27 @@ export class SendDialog extends React.Component<SendDialogProps, SendDialogState shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs} shouldCheckBalance={true} shouldCheckAllowance={false} - onChange={this.onValueChange.bind(this)} + onChange={this._onValueChange.bind(this)} amount={this.state.value} onVisitBalancesPageClick={this.props.onCancelled} /> </div> ); } - private onRecipientChange(recipient?: string) { + private _onRecipientChange(recipient?: string) { this.setState({ shouldShowIncompleteErrs: false, recipient, }); } - private onValueChange(isValid: boolean, amount?: BigNumber) { + private _onValueChange(isValid: boolean, amount?: BigNumber) { this.setState({ isAmountValid: isValid, value: amount, }); } - private onSendClick() { - if (this.hasErrors()) { + private _onSendClick() { + if (this._hasErrors()) { this.setState({ shouldShowIncompleteErrs: true, }); @@ -112,15 +105,13 @@ export class SendDialog extends React.Component<SendDialogProps, SendDialogState this.props.onComplete(this.state.recipient, value); } } - private onCancel() { + private _onCancel() { this.setState({ value: undefined, }); this.props.onCancelled(); } - private hasErrors() { - return _.isUndefined(this.state.recipient) || - _.isUndefined(this.state.value) || - !this.state.isAmountValid; + private _hasErrors() { + return _.isUndefined(this.state.recipient) || _.isUndefined(this.state.value) || !this.state.isAmountValid; } } diff --git a/packages/website/ts/components/dialogs/track_token_confirmation_dialog.tsx b/packages/website/ts/components/dialogs/track_token_confirmation_dialog.tsx index 70c7d1ab6..3f29d46f8 100644 --- a/packages/website/ts/components/dialogs/track_token_confirmation_dialog.tsx +++ b/packages/website/ts/components/dialogs/track_token_confirmation_dialog.tsx @@ -1,14 +1,12 @@ import * as _ from 'lodash'; import Dialog from 'material-ui/Dialog'; import FlatButton from 'material-ui/FlatButton'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; -import {Blockchain} from 'ts/blockchain'; -import {TrackTokenConfirmation} from 'ts/components/track_token_confirmation'; -import {trackedTokenStorage} from 'ts/local_storage/tracked_token_storage'; -import {Dispatcher} from 'ts/redux/dispatcher'; -import {Token, TokenByAddress} from 'ts/types'; -import {constants} from 'ts/utils/constants'; +import { Blockchain } from 'ts/blockchain'; +import { TrackTokenConfirmation } from 'ts/components/track_token_confirmation'; +import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { Token, TokenByAddress } from 'ts/types'; interface TrackTokenConfirmationDialogProps { tokens: Token[]; @@ -25,8 +23,10 @@ interface TrackTokenConfirmationDialogState { isAddingTokenToTracked: boolean; } -export class TrackTokenConfirmationDialog extends - React.Component<TrackTokenConfirmationDialogProps, TrackTokenConfirmationDialogState> { +export class TrackTokenConfirmationDialog extends React.Component< + TrackTokenConfirmationDialogProps, + TrackTokenConfirmationDialogState +> { constructor(props: TrackTokenConfirmationDialogProps) { super(props); this.state = { @@ -38,17 +38,17 @@ export class TrackTokenConfirmationDialog extends return ( <Dialog title="Tracking confirmation" - titleStyle={{fontWeight: 100}} + titleStyle={{ fontWeight: 100 }} actions={[ <FlatButton key="trackNo" label="No" - onTouchTap={this.onTrackConfirmationRespondedAsync.bind(this, false)} + onTouchTap={this._onTrackConfirmationRespondedAsync.bind(this, false)} />, <FlatButton key="trackYes" label="Yes" - onTouchTap={this.onTrackConfirmationRespondedAsync.bind(this, true)} + onTouchTap={this._onTrackConfirmationRespondedAsync.bind(this, true)} />, ]} open={this.props.isOpen} @@ -66,7 +66,7 @@ export class TrackTokenConfirmationDialog extends </Dialog> ); } - private async onTrackConfirmationRespondedAsync(didUserAcceptTracking: boolean) { + private async _onTrackConfirmationRespondedAsync(didUserAcceptTracking: boolean) { if (!didUserAcceptTracking) { this.props.onToggleDialog(didUserAcceptTracking); return; @@ -75,16 +75,17 @@ export class TrackTokenConfirmationDialog extends isAddingTokenToTracked: true, }); for (const token of this.props.tokens) { - const newTokenEntry = _.assign({}, token); + const newTokenEntry = { + ...token, + }; newTokenEntry.isTracked = true; trackedTokenStorage.addTrackedTokenToUser(this.props.userAddress, this.props.networkId, newTokenEntry); this.props.dispatcher.updateTokenByAddress([newTokenEntry]); - const [ - balance, - allowance, - ] = await this.props.blockchain.getCurrentUserTokenBalanceAndAllowanceAsync(token.address); + const [balance, allowance] = await this.props.blockchain.getCurrentUserTokenBalanceAndAllowanceAsync( + token.address, + ); this.props.dispatcher.updateTokenStateByAddress({ [token.address]: { balance, diff --git a/packages/website/ts/components/dialogs/u2f_not_supported_dialog.tsx b/packages/website/ts/components/dialogs/u2f_not_supported_dialog.tsx index 09c32c997..098e3e26d 100644 --- a/packages/website/ts/components/dialogs/u2f_not_supported_dialog.tsx +++ b/packages/website/ts/components/dialogs/u2f_not_supported_dialog.tsx @@ -1,8 +1,8 @@ import Dialog from 'material-ui/Dialog'; import FlatButton from 'material-ui/FlatButton'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; -import {constants} from 'ts/utils/constants'; +import { colors } from 'ts/utils/colors'; +import { constants } from 'ts/utils/constants'; interface U2fNotSupportedDialogProps { isOpen: boolean; @@ -13,24 +13,16 @@ export function U2fNotSupportedDialog(props: U2fNotSupportedDialogProps) { return ( <Dialog title="U2F Not Supported" - titleStyle={{fontWeight: 100}} - actions={[ - <FlatButton - key="u2fNo" - label="Ok" - onTouchTap={props.onToggleDialog.bind(this)} - />, - ]} + titleStyle={{ fontWeight: 100 }} + actions={[<FlatButton key="u2fNo" label="Ok" onTouchTap={props.onToggleDialog.bind(this)} />]} open={props.isOpen} onRequestClose={props.onToggleDialog.bind(this)} autoScrollBodyContent={true} > - <div className="pt2" style={{color: colors.grey700}}> + <div className="pt2" style={{ color: colors.grey700 }}> <div> - It looks like your browser does not support U2F connections - required for us to communicate with your hardware wallet. - Please use a browser that supports U2F connections and try - again. + It looks like your browser does not support U2F connections required for us to communicate with your + hardware wallet. Please use a browser that supports U2F connections and try again. </div> <div> <ul> @@ -39,9 +31,9 @@ export function U2fNotSupportedDialog(props: U2fNotSupportedDialogProps) { <li> Firefox with{' '} <a - href={constants.FIREFOX_U2F_ADDON} + href={constants.URL_FIREFOX_U2F_ADDON} target="_blank" - style={{textDecoration: 'underline'}} + style={{ textDecoration: 'underline' }} > this extension </a>. diff --git a/packages/website/ts/components/dialogs/wrapped_eth_section_notice_dialog.tsx b/packages/website/ts/components/dialogs/wrapped_eth_section_notice_dialog.tsx new file mode 100644 index 000000000..9e91ff12d --- /dev/null +++ b/packages/website/ts/components/dialogs/wrapped_eth_section_notice_dialog.tsx @@ -0,0 +1,33 @@ +import Dialog from 'material-ui/Dialog'; +import FlatButton from 'material-ui/FlatButton'; +import { colors } from 'material-ui/styles'; +import * as React from 'react'; + +interface WrappedEthSectionNoticeDialogProps { + isOpen: boolean; + onToggleDialog: () => void; +} + +export function WrappedEthSectionNoticeDialog(props: WrappedEthSectionNoticeDialogProps) { + return ( + <Dialog + title="Dedicated Wrapped Ether Section" + titleStyle={{ fontWeight: 100 }} + actions={[ + <FlatButton key="acknowledgeWrapEthSection" label="Sounds good" onTouchTap={props.onToggleDialog} />, + ]} + open={props.isOpen} + onRequestClose={props.onToggleDialog} + autoScrollBodyContent={true} + modal={true} + > + <div className="pt2" style={{ color: colors.grey700 }}> + <div> + We have recently updated the Wrapped Ether token (WETH) used by 0x Portal. Don't worry, unwrapping + Ether tied to the old Wrapped Ether token can be done at any time by clicking on the "Wrap ETH" + section in the menu to the left. + </div> + </div> + </Dialog> + ); +} diff --git a/packages/website/ts/components/eth_weth_conversion_button.tsx b/packages/website/ts/components/eth_weth_conversion_button.tsx index a83b1543f..300e71f1f 100644 --- a/packages/website/ts/components/eth_weth_conversion_button.tsx +++ b/packages/website/ts/components/eth_weth_conversion_button.tsx @@ -1,23 +1,26 @@ -import {ZeroEx} from '0x.js'; -import BigNumber from 'bignumber.js'; +import { ZeroEx } from '0x.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import RaisedButton from 'material-ui/RaisedButton'; import * as React from 'react'; -import {Blockchain} from 'ts/blockchain'; -import {EthWethConversionDialog} from 'ts/components/dialogs/eth_weth_conversion_dialog'; -import {Dispatcher} from 'ts/redux/dispatcher'; -import {BlockchainCallErrs, Side, Token, TokenState} from 'ts/types'; -import {constants} from 'ts/utils/constants'; -import {errorReporter} from 'ts/utils/error_reporter'; -import {utils} from 'ts/utils/utils'; +import { Blockchain } from 'ts/blockchain'; +import { EthWethConversionDialog } from 'ts/components/dialogs/eth_weth_conversion_dialog'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { BlockchainCallErrs, Side, Token, TokenState } from 'ts/types'; +import { constants } from 'ts/utils/constants'; +import { errorReporter } from 'ts/utils/error_reporter'; +import { utils } from 'ts/utils/utils'; interface EthWethConversionButtonProps { + direction: Side; ethToken: Token; ethTokenState: TokenState; dispatcher: Dispatcher; blockchain: Blockchain; userEtherBalance: BigNumber; - onError: () => void; + isOutdatedWrappedEther: boolean; + onConversionSuccessful?: () => void; + isDisabled?: boolean; } interface EthWethConversionButtonState { @@ -25,8 +28,14 @@ interface EthWethConversionButtonState { isEthConversionHappening: boolean; } -export class EthWethConversionButton extends - React.Component<EthWethConversionButtonProps, EthWethConversionButtonState> { +export class EthWethConversionButton extends React.Component< + EthWethConversionButtonProps, + EthWethConversionButtonState +> { + public static defaultProps: Partial<EthWethConversionButtonProps> = { + isDisabled: false, + onConversionSuccessful: _.noop, + }; public constructor(props: EthWethConversionButtonProps) { super(props); this.state = { @@ -35,20 +44,30 @@ export class EthWethConversionButton extends }; } public render() { - const labelStyle = this.state.isEthConversionHappening ? {fontSize: 10} : {}; + const labelStyle = this.state.isEthConversionHappening ? { fontSize: 10 } : {}; + let callToActionLabel; + let inProgressLabel; + if (this.props.direction === Side.Deposit) { + callToActionLabel = 'Wrap'; + inProgressLabel = 'Wrapping...'; + } else { + callToActionLabel = 'Unwrap'; + inProgressLabel = 'Unwrapping...'; + } return ( <div> <RaisedButton - style={{width: '100%'}} + style={{ width: '100%' }} labelStyle={labelStyle} - disabled={this.state.isEthConversionHappening} - label={this.state.isEthConversionHappening ? 'Converting...' : 'Convert'} - onClick={this.toggleConversionDialog.bind(this)} + disabled={this.props.isDisabled || this.state.isEthConversionHappening} + label={this.state.isEthConversionHappening ? inProgressLabel : callToActionLabel} + onClick={this._toggleConversionDialog.bind(this)} /> <EthWethConversionDialog + direction={this.props.direction} isOpen={this.state.isEthConversionDialogVisible} - onComplete={this.onConversionAmountSelectedAsync.bind(this)} - onCancelled={this.toggleConversionDialog.bind(this)} + onComplete={this._onConversionAmountSelectedAsync.bind(this)} + onCancelled={this._toggleConversionDialog.bind(this)} etherBalance={this.props.userEtherBalance} token={this.props.ethToken} tokenState={this.props.ethTokenState} @@ -56,41 +75,48 @@ export class EthWethConversionButton extends </div> ); } - private toggleConversionDialog() { + private _toggleConversionDialog() { this.setState({ isEthConversionDialogVisible: !this.state.isEthConversionDialogVisible, }); } - private async onConversionAmountSelectedAsync(direction: Side, value: BigNumber) { + private async _onConversionAmountSelectedAsync(direction: Side, value: BigNumber) { this.setState({ isEthConversionHappening: true, }); - this.toggleConversionDialog(); + this._toggleConversionDialog(); const token = this.props.ethToken; const tokenState = this.props.ethTokenState; let balance = tokenState.balance; try { - if (direction === Side.deposit) { - await this.props.blockchain.convertEthToWrappedEthTokensAsync(value); - const ethAmount = ZeroEx.toUnitAmount(value, constants.ETH_DECIMAL_PLACES); - this.props.dispatcher.showFlashMessage(`Successfully converted ${ethAmount.toString()} ETH to WETH`); + if (direction === Side.Deposit) { + await this.props.blockchain.convertEthToWrappedEthTokensAsync(token.address, value); + const ethAmount = ZeroEx.toUnitAmount(value, constants.DECIMAL_PLACES_ETH); + this.props.dispatcher.showFlashMessage(`Successfully wrapped ${ethAmount.toString()} ETH to WETH`); balance = balance.plus(value); } else { - await this.props.blockchain.convertWrappedEthTokensToEthAsync(value); + await this.props.blockchain.convertWrappedEthTokensToEthAsync(token.address, value); const tokenAmount = ZeroEx.toUnitAmount(value, token.decimals); - this.props.dispatcher.showFlashMessage(`Successfully converted ${tokenAmount.toString()} WETH to ETH`); + this.props.dispatcher.showFlashMessage(`Successfully unwrapped ${tokenAmount.toString()} WETH to ETH`); balance = balance.minus(value); } - this.props.dispatcher.replaceTokenBalanceByAddress(token.address, balance); + if (!this.props.isOutdatedWrappedEther) { + this.props.dispatcher.replaceTokenBalanceByAddress(token.address, balance); + } + this.props.onConversionSuccessful(); } catch (err) { - const errMsg = '' + err; - if (_.includes(errMsg, BlockchainCallErrs.USER_HAS_NO_ASSOCIATED_ADDRESSES)) { + const errMsg = `${err}`; + if (_.includes(errMsg, BlockchainCallErrs.UserHasNoAssociatedAddresses)) { this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); } else if (!_.includes(errMsg, 'User denied transaction')) { utils.consoleLog(`Unexpected error encountered: ${err}`); utils.consoleLog(err.stack); + const errorMsg = + direction === Side.Deposit + ? 'Failed to wrap your ETH. Please try again.' + : 'Failed to unwrap your WETH. Please try again.'; + this.props.dispatcher.showFlashMessage(errorMsg); await errorReporter.reportAsync(err); - this.props.onError(); } } this.setState({ diff --git a/packages/website/ts/components/eth_wrappers.tsx b/packages/website/ts/components/eth_wrappers.tsx new file mode 100644 index 000000000..d074ec787 --- /dev/null +++ b/packages/website/ts/components/eth_wrappers.tsx @@ -0,0 +1,374 @@ +import { ZeroEx } from '0x.js'; +import { BigNumber } from '@0xproject/utils'; +import * as _ from 'lodash'; +import Divider from 'material-ui/Divider'; +import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table'; +import * as moment from 'moment'; +import * as React from 'react'; +import ReactTooltip = require('react-tooltip'); +import { Blockchain } from 'ts/blockchain'; +import { EthWethConversionButton } from 'ts/components/eth_weth_conversion_button'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { + EtherscanLinkSuffixes, + OutdatedWrappedEtherByNetworkId, + Side, + Token, + TokenByAddress, + TokenState, + TokenStateByAddress, +} from 'ts/types'; +import { colors } from 'ts/utils/colors'; +import { configs } from 'ts/utils/configs'; +import { constants } from 'ts/utils/constants'; +import { utils } from 'ts/utils/utils'; + +const PRECISION = 5; +const DATE_FORMAT = 'D/M/YY'; +const ICON_DIMENSION = 40; +const ETHER_ICON_PATH = '/images/ether.png'; +const OUTDATED_WETH_ICON_PATH = '/images/wrapped_eth_gray.png'; + +interface OutdatedWETHAddressToIsStateLoaded { + [address: string]: boolean; +} +interface OutdatedWETHStateByAddress { + [address: string]: TokenState; +} + +interface EthWrappersProps { + networkId: number; + blockchain: Blockchain; + dispatcher: Dispatcher; + tokenByAddress: TokenByAddress; + tokenStateByAddress: TokenStateByAddress; + userAddress: string; + userEtherBalance: BigNumber; +} + +interface EthWrappersState { + outdatedWETHAddressToIsStateLoaded: OutdatedWETHAddressToIsStateLoaded; + outdatedWETHStateByAddress: OutdatedWETHStateByAddress; +} + +export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersState> { + constructor(props: EthWrappersProps) { + super(props); + const outdatedWETHAddresses = this._getOutdatedWETHAddresses(); + const outdatedWETHAddressToIsStateLoaded: OutdatedWETHAddressToIsStateLoaded = {}; + const outdatedWETHStateByAddress: OutdatedWETHStateByAddress = {}; + _.each(outdatedWETHAddresses, outdatedWETHAddress => { + outdatedWETHAddressToIsStateLoaded[outdatedWETHAddress] = false; + outdatedWETHStateByAddress[outdatedWETHAddress] = { + balance: new BigNumber(0), + allowance: new BigNumber(0), + }; + }); + this.state = { + outdatedWETHAddressToIsStateLoaded, + outdatedWETHStateByAddress, + }; + } + public componentDidMount() { + window.scrollTo(0, 0); + // tslint:disable-next-line:no-floating-promises + this._fetchOutdatedWETHStateAsync(); + } + public render() { + const tokens = _.values(this.props.tokenByAddress); + const etherToken = _.find(tokens, { symbol: 'WETH' }); + const etherTokenState = this.props.tokenStateByAddress[etherToken.address]; + const wethBalance = ZeroEx.toUnitAmount(etherTokenState.balance, constants.DECIMAL_PLACES_ETH); + const isBidirectional = true; + const etherscanUrl = utils.getEtherScanLinkIfExists( + etherToken.address, + this.props.networkId, + EtherscanLinkSuffixes.Address, + ); + const tokenLabel = this._renderToken('Wrapped Ether', etherToken.address, configs.ICON_URL_BY_SYMBOL.WETH); + return ( + <div className="clearfix lg-px4 md-px4 sm-px2" style={{ minHeight: 600 }}> + <div className="relative"> + <h3>ETH Wrapper</h3> + <div className="absolute" style={{ top: 0, right: 0 }}> + <a target="_blank" href={constants.URL_WETH_IO} style={{ color: colors.grey }}> + <div className="flex"> + <div>About Wrapped ETH</div> + <div className="pl1"> + <i className="zmdi zmdi-open-in-new" /> + </div> + </div> + </a> + </div> + </div> + <Divider /> + <div> + <div className="py2">Wrap ETH into an ERC20-compliant Ether token. 1 ETH = 1 WETH.</div> + <div> + <Table selectable={false} style={{ backgroundColor: colors.grey50 }}> + <TableHeader displaySelectAll={false} adjustForCheckbox={false}> + <TableRow> + <TableHeaderColumn>ETH Token</TableHeaderColumn> + <TableHeaderColumn>Balance</TableHeaderColumn> + <TableHeaderColumn className="center"> + {this._renderActionColumnTitle(isBidirectional)} + </TableHeaderColumn> + </TableRow> + </TableHeader> + <TableBody displayRowCheckbox={false}> + <TableRow key="ETH"> + <TableRowColumn className="py1"> + <div className="flex"> + <img + style={{ + width: ICON_DIMENSION, + height: ICON_DIMENSION, + }} + src={ETHER_ICON_PATH} + /> + <div className="ml2 sm-hide xs-hide" style={{ marginTop: 12 }}> + ETH + </div> + </div> + </TableRowColumn> + <TableRowColumn> + {this.props.userEtherBalance.toFixed(PRECISION)} ETH + </TableRowColumn> + <TableRowColumn> + <EthWethConversionButton + isOutdatedWrappedEther={false} + direction={Side.Deposit} + ethToken={etherToken} + ethTokenState={etherTokenState} + dispatcher={this.props.dispatcher} + blockchain={this.props.blockchain} + userEtherBalance={this.props.userEtherBalance} + /> + </TableRowColumn> + </TableRow> + <TableRow key="WETH"> + <TableRowColumn className="py1"> + {this._renderTokenLink(tokenLabel, etherscanUrl)} + </TableRowColumn> + <TableRowColumn>{wethBalance.toFixed(PRECISION)} WETH</TableRowColumn> + <TableRowColumn> + <EthWethConversionButton + isOutdatedWrappedEther={false} + direction={Side.Receive} + ethToken={etherToken} + ethTokenState={etherTokenState} + dispatcher={this.props.dispatcher} + blockchain={this.props.blockchain} + userEtherBalance={this.props.userEtherBalance} + /> + </TableRowColumn> + </TableRow> + </TableBody> + </Table> + </div> + </div> + <div> + <h4>Outdated WETH</h4> + <Divider /> + <div className="pt2" style={{ lineHeight: 1.5 }}> + The{' '} + <a href="https://blog.0xproject.com/canonical-weth-a9aa7d0279dd" target="_blank"> + canonical WETH + </a>{' '} + contract is updated when necessary. Unwrap outdated WETH in order to
retrieve your ETH and move + it to the updated WETH token. + </div> + <div> + <Table selectable={false} style={{ backgroundColor: colors.grey50 }}> + <TableHeader displaySelectAll={false} adjustForCheckbox={false}> + <TableRow> + <TableHeaderColumn>WETH Version</TableHeaderColumn> + <TableHeaderColumn>Balance</TableHeaderColumn> + <TableHeaderColumn className="center"> + {this._renderActionColumnTitle(!isBidirectional)} + </TableHeaderColumn> + </TableRow> + </TableHeader> + <TableBody displayRowCheckbox={false}> + {this._renderOutdatedWeths(etherToken, etherTokenState)} + </TableBody> + </Table> + </div> + </div> + </div> + ); + } + private _renderActionColumnTitle(isBidirectional: boolean) { + let iconClass = 'zmdi-long-arrow-right'; + let leftSymbol = 'WETH'; + let rightSymbol = 'ETH'; + if (isBidirectional) { + iconClass = 'zmdi-swap'; + leftSymbol = 'ETH'; + rightSymbol = 'WETH'; + } + return ( + <div className="flex mx-auto" style={{ width: 85 }}> + <div style={{ paddingTop: 3 }}>{leftSymbol}</div> + <div className="px1"> + <i style={{ fontSize: 18 }} className={`zmdi ${iconClass}`} /> + </div> + <div style={{ paddingTop: 3 }}>{rightSymbol}</div> + </div> + ); + } + private _renderOutdatedWeths(etherToken: Token, etherTokenState: TokenState) { + const rows = _.map( + configs.OUTDATED_WRAPPED_ETHERS, + (outdatedWETHByNetworkId: OutdatedWrappedEtherByNetworkId) => { + const outdatedWETHIfExists = outdatedWETHByNetworkId[this.props.networkId]; + if (_.isUndefined(outdatedWETHIfExists)) { + return null; // noop + } + const timestampMsRange = outdatedWETHIfExists.timestampMsRange; + let dateRange: string; + if (!_.isUndefined(timestampMsRange)) { + const startMoment = moment(timestampMsRange.startTimestampMs); + const endMoment = moment(timestampMsRange.endTimestampMs); + dateRange = `${startMoment.format(DATE_FORMAT)}-${endMoment.format(DATE_FORMAT)}`; + } else { + dateRange = '-'; + } + const outdatedEtherToken = { + ...etherToken, + address: outdatedWETHIfExists.address, + }; + const isStateLoaded = this.state.outdatedWETHAddressToIsStateLoaded[outdatedWETHIfExists.address]; + const outdatedEtherTokenState = this.state.outdatedWETHStateByAddress[outdatedWETHIfExists.address]; + const balanceInEthIfExists = isStateLoaded + ? ZeroEx.toUnitAmount(outdatedEtherTokenState.balance, constants.DECIMAL_PLACES_ETH).toFixed( + PRECISION, + ) + : undefined; + const onConversionSuccessful = this._onOutdatedConversionSuccessfulAsync.bind( + this, + outdatedWETHIfExists.address, + ); + const etherscanUrl = utils.getEtherScanLinkIfExists( + outdatedWETHIfExists.address, + this.props.networkId, + EtherscanLinkSuffixes.Address, + ); + const tokenLabel = this._renderToken(dateRange, outdatedEtherToken.address, OUTDATED_WETH_ICON_PATH); + return ( + <TableRow key={`weth-${outdatedWETHIfExists.address}`}> + <TableRowColumn className="py1"> + {this._renderTokenLink(tokenLabel, etherscanUrl)} + </TableRowColumn> + <TableRowColumn> + {isStateLoaded ? ( + `${balanceInEthIfExists} WETH` + ) : ( + <i className="zmdi zmdi-spinner zmdi-hc-spin" /> + )} + </TableRowColumn> + <TableRowColumn> + <EthWethConversionButton + isDisabled={!isStateLoaded} + isOutdatedWrappedEther={true} + direction={Side.Receive} + ethToken={outdatedEtherToken} + ethTokenState={outdatedEtherTokenState} + dispatcher={this.props.dispatcher} + blockchain={this.props.blockchain} + userEtherBalance={this.props.userEtherBalance} + onConversionSuccessful={onConversionSuccessful} + /> + </TableRowColumn> + </TableRow> + ); + }, + ); + return rows; + } + private _renderTokenLink(tokenLabel: React.ReactNode, etherscanUrl: string) { + return ( + <span> + {_.isUndefined(etherscanUrl) ? ( + tokenLabel + ) : ( + <a href={etherscanUrl} target="_blank" style={{ textDecoration: 'none' }}> + {tokenLabel} + </a> + )} + </span> + ); + } + private _renderToken(name: string, address: string, imgPath: string) { + const tooltipId = `tooltip-${address}`; + return ( + <div className="flex"> + <img style={{ width: ICON_DIMENSION, height: ICON_DIMENSION }} src={imgPath} /> + <div className="ml2 sm-hide xs-hide" style={{ marginTop: 12 }}> + <span data-tip={true} data-for={tooltipId}> + {name} + </span> + <ReactTooltip id={tooltipId}>{address}</ReactTooltip> + </div> + </div> + ); + } + private async _onOutdatedConversionSuccessfulAsync(outdatedWETHAddress: string) { + this.setState({ + outdatedWETHAddressToIsStateLoaded: { + ...this.state.outdatedWETHAddressToIsStateLoaded, + [outdatedWETHAddress]: false, + }, + }); + const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync( + this.props.userAddress, + outdatedWETHAddress, + ); + this.setState({ + outdatedWETHAddressToIsStateLoaded: { + ...this.state.outdatedWETHAddressToIsStateLoaded, + [outdatedWETHAddress]: true, + }, + outdatedWETHStateByAddress: { + ...this.state.outdatedWETHStateByAddress, + [outdatedWETHAddress]: { + balance, + allowance, + }, + }, + }); + } + private async _fetchOutdatedWETHStateAsync() { + const outdatedWETHAddresses = this._getOutdatedWETHAddresses(); + const outdatedWETHAddressToIsStateLoaded: OutdatedWETHAddressToIsStateLoaded = {}; + const outdatedWETHStateByAddress: OutdatedWETHStateByAddress = {}; + for (const address of outdatedWETHAddresses) { + const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync( + this.props.userAddress, + address, + ); + outdatedWETHStateByAddress[address] = { + balance, + allowance, + }; + outdatedWETHAddressToIsStateLoaded[address] = true; + } + this.setState({ + outdatedWETHStateByAddress, + outdatedWETHAddressToIsStateLoaded, + }); + } + private _getOutdatedWETHAddresses(): string[] { + const outdatedWETHAddresses = _.compact( + _.map(configs.OUTDATED_WRAPPED_ETHERS, outdatedWrappedEtherByNetwork => { + const outdatedWrappedEtherIfExists = outdatedWrappedEtherByNetwork[this.props.networkId]; + if (_.isUndefined(outdatedWrappedEtherIfExists)) { + return undefined; + } + const address = outdatedWrappedEtherIfExists.address; + return address; + }), + ); + return outdatedWETHAddresses; + } +} // tslint:disable:max-file-line-count diff --git a/packages/website/ts/components/fill_order.tsx b/packages/website/ts/components/fill_order.tsx index 388c72d8e..1a150e9ee 100644 --- a/packages/website/ts/components/fill_order.tsx +++ b/packages/website/ts/components/fill_order.tsx @@ -1,46 +1,29 @@ -import {Order as ZeroExOrder, ZeroEx} from '0x.js'; +import { Order as ZeroExOrder, ZeroEx } from '0x.js'; +import { BigNumber } from '@0xproject/utils'; import * as accounting from 'accounting'; -import BigNumber from 'bignumber.js'; import * as _ from 'lodash'; -import {Card, CardHeader, CardText} from 'material-ui/Card'; +import { Card, CardHeader, CardText } from 'material-ui/Card'; import Divider from 'material-ui/Divider'; -import Paper from 'material-ui/Paper'; import RaisedButton from 'material-ui/RaisedButton'; -import TextField from 'material-ui/TextField'; -import * as moment from 'moment'; import * as React from 'react'; -import {Link} from 'react-router-dom'; -import {Blockchain} from 'ts/blockchain'; -import {TrackTokenConfirmationDialog} from 'ts/components/dialogs/track_token_confirmation_dialog'; -import {FillOrderJSON} from 'ts/components/fill_order_json'; -import {FillWarningDialog} from 'ts/components/fill_warning_dialog'; -import {TokenAmountInput} from 'ts/components/inputs/token_amount_input'; -import {Alert} from 'ts/components/ui/alert'; -import {EthereumAddress} from 'ts/components/ui/ethereum_address'; -import {Identicon} from 'ts/components/ui/identicon'; -import {VisualOrder} from 'ts/components/visual_order'; -import {trackedTokenStorage} from 'ts/local_storage/tracked_token_storage'; -import {Dispatcher} from 'ts/redux/dispatcher'; -import {orderSchema} from 'ts/schemas/order_schema'; -import {SchemaValidator} from 'ts/schemas/validator'; -import { - AlertTypes, - BlockchainErrs, - ContractResponse, - ExchangeContractErrs, - Order, - OrderToken, - Side, - Token, - TokenByAddress, - TokenStateByAddress, - WebsitePaths, -} from 'ts/types'; -import {constants} from 'ts/utils/constants'; -import {errorReporter} from 'ts/utils/error_reporter'; -import {utils} from 'ts/utils/utils'; - -const CUSTOM_LIGHT_GRAY = '#BBBBBB'; +import { Link } from 'react-router-dom'; +import { Blockchain } from 'ts/blockchain'; +import { TrackTokenConfirmationDialog } from 'ts/components/dialogs/track_token_confirmation_dialog'; +import { FillOrderJSON } from 'ts/components/fill_order_json'; +import { FillWarningDialog } from 'ts/components/fill_warning_dialog'; +import { TokenAmountInput } from 'ts/components/inputs/token_amount_input'; +import { Alert } from 'ts/components/ui/alert'; +import { EthereumAddress } from 'ts/components/ui/ethereum_address'; +import { Identicon } from 'ts/components/ui/identicon'; +import { VisualOrder } from 'ts/components/visual_order'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { orderSchema } from 'ts/schemas/order_schema'; +import { SchemaValidator } from 'ts/schemas/validator'; +import { AlertTypes, BlockchainErrs, Order, Token, TokenByAddress, TokenStateByAddress, WebsitePaths } from 'ts/types'; +import { colors } from 'ts/utils/colors'; +import { constants } from 'ts/utils/constants'; +import { errorReporter } from 'ts/utils/error_reporter'; +import { utils } from 'ts/utils/utils'; interface FillOrderProps { blockchain: Blockchain; @@ -75,7 +58,7 @@ interface FillOrderState { } export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { - private validator: SchemaValidator; + private _validator: SchemaValidator; constructor(props: FillOrderProps) { super(props); this.state = { @@ -96,12 +79,12 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { isConfirmingTokenTracking: false, tokensToTrack: [], }; - this.validator = new SchemaValidator(); + this._validator = new SchemaValidator(); } public componentWillMount() { if (!_.isEmpty(this.state.orderJSON)) { // tslint:disable-next-line:no-floating-promises - this.validateFillOrderFireAndForgetAsync(this.state.orderJSON); + this._validateFillOrderFireAndForgetAsync(this.state.orderJSON); } } public componentDidMount() { @@ -109,57 +92,57 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { } public render() { return ( - <div className="clearfix lg-px4 md-px4 sm-px2" style={{minHeight: 600}}> + <div className="clearfix lg-px4 md-px4 sm-px2" style={{ minHeight: 600 }}> <h3>Fill an order</h3> <Divider /> <div> - {!this.props.isOrderInUrl && + {!this.props.isOrderInUrl && ( <div> - <div className="pt2 pb2"> - Paste an order JSON snippet below to begin - </div> + <div className="pt2 pb2">Paste an order JSON snippet below to begin</div> <div className="pb2">Order JSON</div> <FillOrderJSON blockchain={this.props.blockchain} tokenByAddress={this.props.tokenByAddress} networkId={this.props.networkId} orderJSON={this.state.orderJSON} - onFillOrderJSONChanged={this.onFillOrderJSONChanged.bind(this)} + onFillOrderJSONChanged={this._onFillOrderJSONChanged.bind(this)} /> - {this.renderOrderJsonNotices()} + {this._renderOrderJsonNotices()} </div> - } + )} <div> - {!_.isUndefined(this.state.parsedOrder) && this.state.didOrderValidationRun - && this.state.areAllInvolvedTokensTracked && - this.renderVisualOrder() - } + {!_.isUndefined(this.state.parsedOrder) && + this.state.didOrderValidationRun && + this.state.areAllInvolvedTokensTracked && + this._renderVisualOrder()} </div> - {this.props.isOrderInUrl && + {this.props.isOrderInUrl && ( <div className="pt2"> - <Card style={{boxShadow: 'none', backgroundColor: 'none', border: '1px solid #eceaea'}}> - <CardHeader - title="Order JSON" - actAsExpander={true} - showExpandableButton={true} - /> + <Card + style={{ + boxShadow: 'none', + backgroundColor: 'none', + border: '1px solid #eceaea', + }} + > + <CardHeader title="Order JSON" actAsExpander={true} showExpandableButton={true} /> <CardText expandable={true}> <FillOrderJSON blockchain={this.props.blockchain} tokenByAddress={this.props.tokenByAddress} networkId={this.props.networkId} orderJSON={this.state.orderJSON} - onFillOrderJSONChanged={this.onFillOrderJSONChanged.bind(this)} + onFillOrderJSONChanged={this._onFillOrderJSONChanged.bind(this)} /> </CardText> </Card> - {this.renderOrderJsonNotices()} + {this._renderOrderJsonNotices()} </div> - } + )} </div> <FillWarningDialog isOpen={this.state.isFillWarningDialogOpen} - onToggleDialog={this.onFillWarningClosed.bind(this)} + onToggleDialog={this._onFillWarningClosed.bind(this)} /> <TrackTokenConfirmationDialog userAddress={this.props.userAddress} @@ -169,29 +152,30 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { dispatcher={this.props.dispatcher} tokens={this.state.tokensToTrack} isOpen={this.state.isConfirmingTokenTracking} - onToggleDialog={this.onToggleTrackConfirmDialog.bind(this)} + onToggleDialog={this._onToggleTrackConfirmDialog.bind(this)} /> </div> ); } - private renderOrderJsonNotices() { + private _renderOrderJsonNotices() { return ( <div> - {!_.isUndefined(this.props.initialOrder) && !this.state.didOrderValidationRun && - <div className="pt2"> - <span className="pr1"> - <i className="zmdi zmdi-spinner zmdi-hc-spin" /> - </span> - <span>Validating order...</span> - </div> - } - {!_.isEmpty(this.state.orderJSONErrMsg) && + {!_.isUndefined(this.props.initialOrder) && + !this.state.didOrderValidationRun && ( + <div className="pt2"> + <span className="pr1"> + <i className="zmdi zmdi-spinner zmdi-hc-spin" /> + </span> + <span>Validating order...</span> + </div> + )} + {!_.isEmpty(this.state.orderJSONErrMsg) && ( <Alert type={AlertTypes.ERROR} message={this.state.orderJSONErrMsg} /> - } + )} </div> ); } - private renderVisualOrder() { + private _renderVisualOrder() { const takerTokenAddress = this.state.parsedOrder.taker.token.address; const takerToken = this.props.tokenByAddress[takerTokenAddress]; const orderTakerAmount = new BigNumber(this.state.parsedOrder.taker.amount); @@ -212,32 +196,30 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { amount: this.props.orderFillAmount, symbol: takerToken.symbol, }; - const orderTaker = !_.isEmpty(this.state.parsedOrder.taker.address) ? this.state.parsedOrder.taker.address : - this.props.userAddress; + const orderTaker = !_.isEmpty(this.state.parsedOrder.taker.address) + ? this.state.parsedOrder.taker.address + : this.props.userAddress; const parsedOrderExpiration = new BigNumber(this.state.parsedOrder.expiration); const exchangeRate = orderMakerAmount.div(orderTakerAmount); let orderReceiveAmount = 0; if (!_.isUndefined(this.props.orderFillAmount)) { const orderReceiveAmountBigNumber = exchangeRate.mul(this.props.orderFillAmount); - orderReceiveAmount = this.formatCurrencyAmount(orderReceiveAmountBigNumber, makerToken.decimals); + orderReceiveAmount = this._formatCurrencyAmount(orderReceiveAmountBigNumber, makerToken.decimals); } - const isUserMaker = !_.isUndefined(this.state.parsedOrder) && - this.state.parsedOrder.maker.address === this.props.userAddress; + const isUserMaker = + !_.isUndefined(this.state.parsedOrder) && this.state.parsedOrder.maker.address === this.props.userAddress; const expiryDate = utils.convertToReadableDateTimeFromUnixTimestamp(parsedOrderExpiration); return ( <div className="pt3 pb1"> - <div className="clearfix pb2" style={{width: '100%'}}> + <div className="clearfix pb2" style={{ width: '100%' }}> <div className="inline left">Order details</div> - <div className="inline right" style={{minWidth: 208}}> - <div className="col col-4 pl2" style={{color: '#BEBEBE'}}> + <div className="inline right" style={{ minWidth: 208 }}> + <div className="col col-4 pl2" style={{ color: colors.grey }}> Maker: </div> <div className="col col-2 pr1"> - <Identicon - address={this.state.parsedOrder.maker.address} - diameter={23} - /> + <Identicon address={this.state.parsedOrder.maker.address} diameter={23} /> </div> <div className="col col-6"> <EthereumAddress @@ -261,123 +243,112 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { isMakerTokenAddressInRegistry={this.state.isMakerTokenAddressInRegistry} isTakerTokenAddressInRegistry={this.state.isTakerTokenAddressInRegistry} /> - <div className="center pt3 pb2"> - Expires: {expiryDate} UTC - </div> + <div className="center pt3 pb2">Expires: {expiryDate} UTC</div> </div> </div> - {!isUserMaker && - <div className="clearfix mx-auto" style={{width: 315, height: 108}}> - <div className="col col-7" style={{maxWidth: 235}}> - <TokenAmountInput - label="Fill amount" - onChange={this.onFillAmountChange.bind(this)} - shouldShowIncompleteErrs={false} - token={fillToken} - tokenState={fillTokenState} - amount={fillAssetToken.amount} - shouldCheckBalance={true} - shouldCheckAllowance={true} - /> - </div> - <div - className="col col-5 pl1" - style={{color: CUSTOM_LIGHT_GRAY, paddingTop: 39}} - > - = {accounting.formatNumber(orderReceiveAmount, 6)} {makerToken.symbol} - </div> + {!isUserMaker && ( + <div className="clearfix mx-auto relative" style={{ width: 235, height: 108 }}> + <TokenAmountInput + label="Fill amount" + onChange={this._onFillAmountChange.bind(this)} + shouldShowIncompleteErrs={false} + token={fillToken} + tokenState={fillTokenState} + amount={fillAssetToken.amount} + shouldCheckBalance={true} + shouldCheckAllowance={true} + /> + <div + className="absolute sm-hide xs-hide" + style={{ + color: colors.grey400, + right: -247, + top: 39, + width: 242, + }} + > + = {accounting.formatNumber(orderReceiveAmount, 6)} {makerToken.symbol} + </div> </div> - } + )} <div> - {isUserMaker ? + {isUserMaker ? ( <div> <RaisedButton - style={{width: '100%'}} + style={{ width: '100%' }} disabled={this.state.isCancelling} label={this.state.isCancelling ? 'Cancelling order...' : 'Cancel order'} - onClick={this.onCancelOrderClickFireAndForgetAsync.bind(this)} + onClick={this._onCancelOrderClickFireAndForgetAsync.bind(this)} /> - {this.state.didCancelOrderSucceed && - <Alert - type={AlertTypes.SUCCESS} - message={this.renderCancelSuccessMsg()} - /> - } - </div> : + {this.state.didCancelOrderSucceed && ( + <Alert type={AlertTypes.SUCCESS} message={this._renderCancelSuccessMsg()} /> + )} + </div> + ) : ( <div> <RaisedButton - style={{width: '100%'}} + style={{ width: '100%' }} disabled={this.state.isFilling} label={this.state.isFilling ? 'Filling order...' : 'Fill order'} - onClick={this.onFillOrderClick.bind(this)} + onClick={this._onFillOrderClick.bind(this)} /> - {!_.isEmpty(this.state.globalErrMsg) && + {!_.isEmpty(this.state.globalErrMsg) && ( <Alert type={AlertTypes.ERROR} message={this.state.globalErrMsg} /> - } - {this.state.didFillOrderSucceed && - <Alert - type={AlertTypes.SUCCESS} - message={this.renderFillSuccessMsg()} - /> - } + )} + {this.state.didFillOrderSucceed && ( + <Alert type={AlertTypes.SUCCESS} message={this._renderFillSuccessMsg()} /> + )} </div> - } + )} </div> </div> ); } - private renderFillSuccessMsg() { + private _renderFillSuccessMsg() { return ( <div> Order successfully filled. See the trade details in your{' '} - <Link - to={`${WebsitePaths.Portal}/trades`} - style={{color: 'white'}} - > + <Link to={`${WebsitePaths.Portal}/trades`} style={{ color: colors.white }}> trade history </Link> </div> ); } - private renderCancelSuccessMsg() { - return ( - <div> - Order successfully cancelled. - </div> - ); + private _renderCancelSuccessMsg() { + return <div>Order successfully cancelled.</div>; } - private onFillOrderClick() { + private _onFillOrderClick() { if (!this.state.isMakerTokenAddressInRegistry || !this.state.isTakerTokenAddressInRegistry) { this.setState({ isFillWarningDialogOpen: true, }); } else { // tslint:disable-next-line:no-floating-promises - this.onFillOrderClickFireAndForgetAsync(); + this._onFillOrderClickFireAndForgetAsync(); } } - private onFillWarningClosed(didUserCancel: boolean) { + private _onFillWarningClosed(didUserCancel: boolean) { this.setState({ isFillWarningDialogOpen: false, }); if (!didUserCancel) { // tslint:disable-next-line:no-floating-promises - this.onFillOrderClickFireAndForgetAsync(); + this._onFillOrderClickFireAndForgetAsync(); } } - private onFillAmountChange(isValid: boolean, amount?: BigNumber) { + private _onFillAmountChange(isValid: boolean, amount?: BigNumber) { this.props.dispatcher.updateOrderFillAmount(amount); } - private onFillOrderJSONChanged(event: any) { + private _onFillOrderJSONChanged(event: any) { const orderJSON = event.target.value; this.setState({ didOrderValidationRun: _.isEmpty(orderJSON) && _.isEmpty(this.state.orderJSONErrMsg), didFillOrderSucceed: false, }); // tslint:disable-next-line:no-floating-promises - this.validateFillOrderFireAndForgetAsync(orderJSON); + this._validateFillOrderFireAndForgetAsync(orderJSON); } - private async checkForUntrackedTokensAndAskToAdd() { + private async _checkForUntrackedTokensAndAskToAdd() { if (!_.isEmpty(this.state.orderJSONErrMsg)) { return; } @@ -389,22 +360,24 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { const isUnseenMakerToken = _.isUndefined(makerTokenIfExists); const isMakerTokenTracked = !_.isUndefined(makerTokenIfExists) && makerTokenIfExists.isTracked; if (isUnseenMakerToken) { - tokensToTrack.push(_.assign({}, this.state.parsedOrder.maker.token, { + tokensToTrack.push({ + ...this.state.parsedOrder.maker.token, iconUrl: undefined, isTracked: false, isRegistered: false, - })); + }); } else if (!isMakerTokenTracked) { tokensToTrack.push(makerTokenIfExists); } const isUnseenTakerToken = _.isUndefined(takerTokenIfExists); const isTakerTokenTracked = !_.isUndefined(takerTokenIfExists) && takerTokenIfExists.isTracked; if (isUnseenTakerToken) { - tokensToTrack.push(_.assign({}, this.state.parsedOrder.taker.token, { + tokensToTrack.push({ + ...this.state.parsedOrder.taker.token, iconUrl: undefined, isTracked: false, isRegistered: false, - })); + }); } else if (!isTakerTokenTracked) { tokensToTrack.push(takerTokenIfExists); } @@ -419,12 +392,12 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { }); } } - private async validateFillOrderFireAndForgetAsync(orderJSON: string) { + private async _validateFillOrderFireAndForgetAsync(orderJSON: string) { let orderJSONErrMsg = ''; let parsedOrder: Order; try { const order = JSON.parse(orderJSON); - const validationResult = this.validator.validate(order, orderSchema); + const validationResult = this._validator.validate(order, orderSchema); if (validationResult.errors.length > 0) { orderJSONErrMsg = 'Submitted order JSON is not a valid order'; utils.consoleLog(`Unexpected order JSON validation error: ${validationResult.errors.join(', ')}`); @@ -517,10 +490,10 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { unavailableTakerAmount, }); - await this.checkForUntrackedTokensAndAskToAdd(); + await this._checkForUntrackedTokensAndAskToAdd(); } - private async onFillOrderClickFireAndForgetAsync(): Promise<void> { - if (!_.isEmpty(this.props.blockchainErr) || _.isEmpty(this.props.userAddress)) { + private async _onFillOrderClickFireAndForgetAsync(): Promise<void> { + if (this.props.blockchainErr !== BlockchainErrs.NoError || _.isEmpty(this.props.userAddress)) { this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); return; } @@ -531,8 +504,6 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { }); const parsedOrder = this.state.parsedOrder; - const orderHash = parsedOrder.signature.hash; - const unavailableTakerAmount = await this.props.blockchain.getUnavailableTakerAmountAsync(orderHash); const takerFillAmount = this.props.orderFillAmount; if (_.isUndefined(this.props.userAddress)) { @@ -565,11 +536,12 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { if (_.isEmpty(globalErrMsg)) { try { await this.props.blockchain.validateFillOrderThrowIfInvalidAsync( - signedOrder, takerFillAmount, this.props.userAddress); - } catch (err) { - globalErrMsg = utils.zeroExErrToHumanReadableErrMsg( - err.message, parsedOrder.taker.address, + signedOrder, + takerFillAmount, + this.props.userAddress, ); + } catch (err) { + globalErrMsg = utils.zeroExErrToHumanReadableErrMsg(err.message, parsedOrder.taker.address); } } if (!_.isEmpty(globalErrMsg)) { @@ -581,7 +553,8 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { } try { const orderFilledAmount: BigNumber = await this.props.blockchain.fillOrderAsync( - signedOrder, this.props.orderFillAmount, + signedOrder, + this.props.orderFillAmount, ); // After fill completes, let's update the token balances const makerToken = this.props.tokenByAddress[parsedOrder.maker.token.address]; @@ -605,15 +578,15 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { } globalErrMsg = 'Failed to fill order, please refresh and try again'; utils.consoleLog(`${err}`); - await errorReporter.reportAsync(err); this.setState({ globalErrMsg, }); + await errorReporter.reportAsync(err); return; } } - private async onCancelOrderClickFireAndForgetAsync(): Promise<void> { - if (!_.isEmpty(this.props.blockchainErr) || _.isEmpty(this.props.userAddress)) { + private async _onCancelOrderClickFireAndForgetAsync(): Promise<void> { + if (this.props.blockchainErr !== BlockchainErrs.NoError || _.isEmpty(this.props.userAddress)) { this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); return; } @@ -655,8 +628,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { const unavailableTakerAmount = await this.props.blockchain.getUnavailableTakerAmountAsync(orderHash); const availableTakerTokenAmount = takerTokenAmount.minus(unavailableTakerAmount); try { - await this.props.blockchain.validateCancelOrderThrowIfInvalidAsync( - signedOrder, availableTakerTokenAmount); + await this.props.blockchain.validateCancelOrderThrowIfInvalidAsync(signedOrder, availableTakerTokenAmount); } catch (err) { globalErrMsg = utils.zeroExErrToHumanReadableErrMsg(err.message, parsedOrder.taker.address); } @@ -668,9 +640,7 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { return; } try { - await this.props.blockchain.cancelOrderAsync( - signedOrder, availableTakerTokenAmount, - ); + await this.props.blockchain.cancelOrderAsync(signedOrder, availableTakerTokenAmount); this.setState({ isCancelling: false, didCancelOrderSucceed: true, @@ -688,19 +658,19 @@ export class FillOrder extends React.Component<FillOrderProps, FillOrderState> { } globalErrMsg = 'Failed to cancel order, please refresh and try again'; utils.consoleLog(`${err}`); - await errorReporter.reportAsync(err); this.setState({ globalErrMsg, }); + await errorReporter.reportAsync(err); return; } } - private formatCurrencyAmount(amount: BigNumber, decimals: number): number { + private _formatCurrencyAmount(amount: BigNumber, decimals: number): number { const unitAmount = ZeroEx.toUnitAmount(amount, decimals); const roundedUnitAmount = Math.round(unitAmount.toNumber() * 100000) / 100000; return roundedUnitAmount; } - private onToggleTrackConfirmDialog(didConfirmTokenTracking: boolean) { + private _onToggleTrackConfirmDialog(didConfirmTokenTracking: boolean) { if (!didConfirmTokenTracking) { this.setState({ orderJSON: '', diff --git a/packages/website/ts/components/fill_order_json.tsx b/packages/website/ts/components/fill_order_json.tsx index f4db1f74e..f8e43481a 100644 --- a/packages/website/ts/components/fill_order_json.tsx +++ b/packages/website/ts/components/fill_order_json.tsx @@ -1,13 +1,13 @@ -import {ZeroEx} from '0x.js'; -import BigNumber from 'bignumber.js'; +import { ZeroEx } from '0x.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import Paper from 'material-ui/Paper'; import TextField from 'material-ui/TextField'; import * as React from 'react'; -import {Blockchain} from 'ts/blockchain'; -import {Side, TokenByAddress} from 'ts/types'; -import {constants} from 'ts/utils/constants'; -import {utils} from 'ts/utils/utils'; +import { Blockchain } from 'ts/blockchain'; +import { Side, TokenByAddress } from 'ts/types'; +import { constants } from 'ts/utils/constants'; +import { utils } from 'ts/utils/utils'; interface FillOrderJSONProps { blockchain: Blockchain; @@ -24,11 +24,11 @@ export class FillOrderJSON extends React.Component<FillOrderJSONProps, FillOrder const tokenAddresses = _.keys(this.props.tokenByAddress); const exchangeContract = this.props.blockchain.getExchangeContractAddressIfExists(); const hintSideToAssetToken = { - [Side.deposit]: { + [Side.Deposit]: { amount: new BigNumber(35), address: tokenAddresses[0], }, - [Side.receive]: { + [Side.Receive]: { amount: new BigNumber(89), address: tokenAddresses[1], }, @@ -41,17 +41,28 @@ export class FillOrderJSON extends React.Component<FillOrderJSONProps, FillOrder v: 27, }; const hintSalt = ZeroEx.generatePseudoRandomSalt(); - const hintOrder = utils.generateOrder(this.props.networkId, exchangeContract, hintSideToAssetToken, - hintOrderExpiryTimestamp, '', '', constants.MAKER_FEE, - constants.TAKER_FEE, constants.FEE_RECIPIENT_ADDRESS, - hintSignatureData, this.props.tokenByAddress, hintSalt); + const feeRecipient = constants.NULL_ADDRESS; + const hintOrder = utils.generateOrder( + this.props.networkId, + exchangeContract, + hintSideToAssetToken, + hintOrderExpiryTimestamp, + '', + '', + constants.MAKER_FEE, + constants.TAKER_FEE, + feeRecipient, + hintSignatureData, + this.props.tokenByAddress, + hintSalt, + ); const hintOrderJSON = `${JSON.stringify(hintOrder, null, '\t').substring(0, 500)}...`; return ( <div> - <Paper className="p1 overflow-hidden" style={{height: 164}}> + <Paper className="p1 overflow-hidden" style={{ height: 164 }}> <TextField id="orderJSON" - hintStyle={{bottom: 0, top: 0}} + hintStyle={{ bottom: 0, top: 0 }} fullWidth={true} value={this.props.orderJSON} onChange={this.props.onFillOrderJSONChanged.bind(this)} @@ -59,8 +70,8 @@ export class FillOrderJSON extends React.Component<FillOrderJSONProps, FillOrder multiLine={true} rows={6} rowsMax={6} - underlineStyle={{display: 'none'}} - textareaStyle={{marginTop: 0}} + underlineStyle={{ display: 'none' }} + textareaStyle={{ marginTop: 0 }} /> </Paper> </div> diff --git a/packages/website/ts/components/fill_warning_dialog.tsx b/packages/website/ts/components/fill_warning_dialog.tsx index 83e46cc8f..165d21b34 100644 --- a/packages/website/ts/components/fill_warning_dialog.tsx +++ b/packages/website/ts/components/fill_warning_dialog.tsx @@ -1,11 +1,11 @@ import Dialog from 'material-ui/Dialog'; import FlatButton from 'material-ui/FlatButton'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; +import { colors } from 'ts/utils/colors'; interface FillWarningDialogProps { isOpen: boolean; - onToggleDialog: () => void; + onToggleDialog: (didUserCancel: boolean) => void; } export function FillWarningDialog(props: FillWarningDialogProps) { @@ -13,7 +13,7 @@ export function FillWarningDialog(props: FillWarningDialogProps) { return ( <Dialog title="Warning" - titleStyle={{fontWeight: 100, color: colors.red500}} + titleStyle={{ fontWeight: 100, color: colors.red500 }} actions={[ <FlatButton key="fillWarningCancel" @@ -31,15 +31,11 @@ export function FillWarningDialog(props: FillWarningDialogProps) { autoScrollBodyContent={true} modal={true} > - <div className="pt2" style={{color: colors.grey700}}> + <div className="pt2" style={{ color: colors.grey700 }}> <div> - At least one of the tokens in this order was not found in the - token registry smart contract and may be counterfeit. It is your - responsibility to verify the token addresses on Etherscan ( - <a - href="https://0xproject.com/wiki#Verifying-Custom-Tokens" - target="_blank" - > + At least one of the tokens in this order was not found in the token registry smart contract and may + be counterfeit. It is your responsibility to verify the token addresses on Etherscan ( + <a href="https://0xproject.com/wiki#Verifying-Custom-Tokens" target="_blank"> See this how-to guide </a>) before filling an order. <b>This action may result in the loss of funds</b>. </div> diff --git a/packages/website/ts/components/flash_messages/token_send_completed.tsx b/packages/website/ts/components/flash_messages/token_send_completed.tsx index fef7520f6..18f371624 100644 --- a/packages/website/ts/components/flash_messages/token_send_completed.tsx +++ b/packages/website/ts/components/flash_messages/token_send_completed.tsx @@ -1,9 +1,10 @@ -import {ZeroEx} from '0x.js'; -import BigNumber from 'bignumber.js'; +import { ZeroEx } from '0x.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import * as React from 'react'; -import {Token} from 'ts/types'; -import {utils} from 'ts/utils/utils'; +import { Token } from 'ts/types'; +import { colors } from 'ts/utils/colors'; +import { utils } from 'ts/utils/utils'; interface TokenSendCompletedProps { etherScanLinkIfExists?: string; @@ -16,16 +17,11 @@ interface TokenSendCompletedState {} export class TokenSendCompleted extends React.Component<TokenSendCompletedProps, TokenSendCompletedState> { public render() { - const etherScanLink = !_.isUndefined(this.props.etherScanLinkIfExists) && - ( - <a - style={{color: 'white'}} - href={`${this.props.etherScanLinkIfExists}`} - target="_blank" - > - Verify on Etherscan - </a> - ); + const etherScanLink = !_.isUndefined(this.props.etherScanLinkIfExists) && ( + <a style={{ color: colors.white }} href={`${this.props.etherScanLinkIfExists}`} target="_blank"> + Verify on Etherscan + </a> + ); const amountInUnits = ZeroEx.toUnitAmount(this.props.amountInBaseUnits, this.props.token.decimals); const truncatedAddress = utils.getAddressBeginAndEnd(this.props.toAddress); return ( diff --git a/packages/website/ts/components/flash_messages/transaction_submitted.tsx b/packages/website/ts/components/flash_messages/transaction_submitted.tsx index cef3e2b1e..862e382dd 100644 --- a/packages/website/ts/components/flash_messages/transaction_submitted.tsx +++ b/packages/website/ts/components/flash_messages/transaction_submitted.tsx @@ -1,5 +1,6 @@ import * as _ from 'lodash'; import * as React from 'react'; +import { colors } from 'ts/utils/colors'; interface TransactionSubmittedProps { etherScanLinkIfExists?: string; @@ -15,11 +16,7 @@ export class TransactionSubmitted extends React.Component<TransactionSubmittedPr return ( <div> Transaction submitted to the network:{' '} - <a - style={{color: 'white'}} - href={`${this.props.etherScanLinkIfExists}`} - target="_blank" - > + <a style={{ color: colors.white }} href={`${this.props.etherScanLinkIfExists}`} target="_blank"> Verify on Etherscan </a> </div> diff --git a/packages/website/ts/components/footer.tsx b/packages/website/ts/components/footer.tsx index 5e3c0479a..a0f1a0c96 100644 --- a/packages/website/ts/components/footer.tsx +++ b/packages/website/ts/components/footer.tsx @@ -1,14 +1,9 @@ import * as _ from 'lodash'; import * as React from 'react'; -import { - Link, -} from 'react-router-dom'; -import {HashLink} from 'react-router-hash-link'; -import { - Link as ScrollLink, -} from 'react-scroll'; -import {Styles, WebsitePaths} from 'ts/types'; -import {constants} from 'ts/utils/constants'; +import { Link } from 'react-router-dom'; +import { WebsitePaths } from 'ts/types'; +import { colors } from 'ts/utils/colors'; +import { constants } from 'ts/utils/constants'; interface MenuItemsBySection { [sectionName: string]: FooterMenuItem[]; @@ -18,7 +13,6 @@ interface FooterMenuItem { title: string; path?: string; isExternal?: boolean; - fileName?: string; } enum Sections { @@ -28,9 +22,6 @@ enum Sections { } const ICON_DIMENSION = 16; -const CUSTOM_DARK_GRAY = '#393939'; -const CUSTOM_LIGHT_GRAY = '#CACACA'; -const CUSTOM_LIGHTEST_GRAY = '#9E9E9E'; const menuItemsBySection: MenuItemsBySection = { Documentation: [ { @@ -63,26 +54,27 @@ const menuItemsBySection: MenuItemsBySection = { { title: 'Rocket.chat', isExternal: true, - path: constants.ZEROEX_CHAT_URL, - fileName: 'rocketchat.png', + path: constants.URL_ZEROEX_CHAT, }, { title: 'Blog', isExternal: true, - path: constants.BLOG_URL, - fileName: 'medium.png', + path: constants.URL_BLOG, }, { title: 'Twitter', isExternal: true, - path: constants.TWITTER_URL, - fileName: 'twitter.png', + path: constants.URL_TWITTER, }, { title: 'Reddit', isExternal: true, - path: constants.REDDIT_URL, - fileName: 'reddit.png', + path: constants.URL_REDDIT, + }, + { + title: 'Forum', + isExternal: true, + path: constants.URL_DISCOURSE_FORUM, }, ], Organization: [ @@ -94,7 +86,7 @@ const menuItemsBySection: MenuItemsBySection = { { title: 'Careers', isExternal: true, - path: constants.ANGELLIST_URL, + path: constants.URL_ANGELLIST, }, { title: 'Contact', @@ -104,34 +96,40 @@ const menuItemsBySection: MenuItemsBySection = { ], }; const linkStyle = { - color: 'white', + color: colors.white, cursor: 'pointer', }; -const titleToIcon: {[title: string]: string} = { +const titleToIcon: { [title: string]: string } = { 'Rocket.chat': 'rocketchat.png', - 'Blog': 'medium.png', - 'Twitter': 'twitter.png', - 'Reddit': 'reddit.png', + Blog: 'medium.png', + Twitter: 'twitter.png', + Reddit: 'reddit.png', + Forum: 'discourse.png', }; -export interface FooterProps { - location: Location; -} +export interface FooterProps {} interface FooterState {} export class Footer extends React.Component<FooterProps, FooterState> { public render() { return ( - <div className="relative pb4 pt2" style={{backgroundColor: CUSTOM_DARK_GRAY}}> - <div className="mx-auto max-width-4 md-px2 lg-px0 py4 clearfix" style={{color: 'white'}}> + <div className="relative pb4 pt2" style={{ backgroundColor: colors.darkerGrey }}> + <div className="mx-auto max-width-4 md-px2 lg-px0 py4 clearfix" style={{ color: colors.white }}> <div className="col lg-col-4 md-col-4 col-12 left"> - <div className="sm-mx-auto" style={{width: 148}}> + <div className="sm-mx-auto" style={{ width: 148 }}> <div> <img src="/images/protocol_logo_white.png" height="30" /> </div> - <div style={{fontSize: 11, color: CUSTOM_LIGHTEST_GRAY, paddingLeft: 37, paddingTop: 2}}> + <div + style={{ + fontSize: 11, + color: colors.grey, + paddingLeft: 37, + paddingTop: 2, + }} + > © ZeroEx, Intl. </div> </div> @@ -139,20 +137,20 @@ export class Footer extends React.Component<FooterProps, FooterState> { <div className="col lg-col-8 md-col-8 col-12 lg-pl4 md-pl4"> <div className="col lg-col-4 md-col-4 col-12"> <div className="lg-right md-right sm-center"> - {this.renderHeader(Sections.Documentation)} - {_.map(menuItemsBySection[Sections.Documentation], this.renderMenuItem.bind(this))} + {this._renderHeader(Sections.Documentation)} + {_.map(menuItemsBySection[Sections.Documentation], this._renderMenuItem.bind(this))} </div> </div> <div className="col lg-col-4 md-col-4 col-12 lg-pr2 md-pr2"> <div className="lg-right md-right sm-center"> - {this.renderHeader(Sections.Community)} - {_.map(menuItemsBySection[Sections.Community], this.renderMenuItem.bind(this))} + {this._renderHeader(Sections.Community)} + {_.map(menuItemsBySection[Sections.Community], this._renderMenuItem.bind(this))} </div> </div> <div className="col lg-col-4 md-col-4 col-12"> <div className="lg-right md-right sm-center"> - {this.renderHeader(Sections.Organization)} - {_.map(menuItemsBySection[Sections.Organization], this.renderMenuItem.bind(this))} + {this._renderHeader(Sections.Organization)} + {_.map(menuItemsBySection[Sections.Organization], this._renderMenuItem.bind(this))} </div> </div> </div> @@ -160,100 +158,55 @@ export class Footer extends React.Component<FooterProps, FooterState> { </div> ); } - private renderIcon(fileName: string) { + private _renderIcon(fileName: string) { return ( - <div style={{height: ICON_DIMENSION, width: ICON_DIMENSION}}> - <img src={`/images/social/${fileName}`} style={{width: ICON_DIMENSION}} /> + <div style={{ height: ICON_DIMENSION, width: ICON_DIMENSION }}> + <img src={`/images/social/${fileName}`} style={{ width: ICON_DIMENSION }} /> </div> ); } - private renderMenuItem(item: FooterMenuItem) { + private _renderMenuItem(item: FooterMenuItem) { const iconIfExists = titleToIcon[item.title]; return ( - <div - key={item.title} - className="sm-center" - style={{fontSize: 13, paddingTop: 25}} - > - {item.isExternal ? - <a - className="text-decoration-none" - style={linkStyle} - target="_blank" - href={item.path} - > - {!_.isUndefined(iconIfExists) ? - <div className="sm-mx-auto" style={{width: 65}}> + <div key={item.title} className="sm-center" style={{ fontSize: 13, paddingTop: 25 }}> + {item.isExternal ? ( + <a className="text-decoration-none" style={linkStyle} target="_blank" href={item.path}> + {!_.isUndefined(iconIfExists) ? ( + <div className="sm-mx-auto" style={{ width: 65 }}> <div className="flex"> - <div className="pr1"> - {this.renderIcon(iconIfExists)} - </div> + <div className="pr1">{this._renderIcon(iconIfExists)}</div> <div>{item.title}</div> </div> - </div> : + </div> + ) : ( item.title - } - </a> : - <Link - to={item.path} - style={linkStyle} - className="text-decoration-none" - > + )} + </a> + ) : ( + <Link to={item.path} style={linkStyle} className="text-decoration-none"> <div> - {!_.isUndefined(iconIfExists) && - <div className="pr1"> - {this.renderIcon(iconIfExists)} - </div> - } + {!_.isUndefined(iconIfExists) && ( + <div className="pr1">{this._renderIcon(iconIfExists)}</div> + )} {item.title} </div> </Link> - } + )} </div> ); } - private renderHeader(title: string) { + private _renderHeader(title: string) { const headerStyle = { textTransform: 'uppercase', - color: CUSTOM_LIGHT_GRAY, + color: colors.grey400, letterSpacing: 2, fontFamily: 'Roboto Mono', fontSize: 13, }; return ( - <div - className="lg-pb2 md-pb2 sm-pt4" - style={headerStyle} - > + <div className="lg-pb2 md-pb2 sm-pt4" style={headerStyle}> {title} </div> ); } - private renderHomepageLink(title: string) { - const hash = title.toLowerCase(); - if (this.props.location.pathname === WebsitePaths.Home) { - return ( - <ScrollLink - style={linkStyle} - to={hash} - smooth={true} - offset={0} - duration={constants.HOME_SCROLL_DURATION_MS} - containerId="home" - > - {title} - </ScrollLink> - ); - } else { - return ( - <HashLink - to={`/#${hash}`} - className="text-decoration-none" - style={linkStyle} - > - {title} - </HashLink> - ); - } - } } diff --git a/packages/website/ts/components/generate_order/asset_picker.tsx b/packages/website/ts/components/generate_order/asset_picker.tsx index 633d6a017..df7d87cfd 100644 --- a/packages/website/ts/components/generate_order/asset_picker.tsx +++ b/packages/website/ts/components/generate_order/asset_picker.tsx @@ -1,26 +1,14 @@ import * as _ from 'lodash'; import Dialog from 'material-ui/Dialog'; import FlatButton from 'material-ui/FlatButton'; -import GridList from 'material-ui/GridList/GridList'; -import GridTile from 'material-ui/GridList/GridTile'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; -import {Blockchain} from 'ts/blockchain'; -import {NewTokenForm} from 'ts/components/generate_order/new_token_form'; -import {TrackTokenConfirmation} from 'ts/components/track_token_confirmation'; -import {TokenIcon} from 'ts/components/ui/token_icon'; -import {trackedTokenStorage} from 'ts/local_storage/tracked_token_storage'; -import {Dispatcher} from 'ts/redux/dispatcher'; -import { - AssetToken, - DialogConfigs, - Styles, - Token, - TokenByAddress, - TokenState, - TokenVisibility, -} from 'ts/types'; -import {utils} from 'ts/utils/utils'; +import { Blockchain } from 'ts/blockchain'; +import { NewTokenForm } from 'ts/components/generate_order/new_token_form'; +import { TrackTokenConfirmation } from 'ts/components/track_token_confirmation'; +import { TokenIcon } from 'ts/components/ui/token_icon'; +import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { DialogConfigs, Token, TokenByAddress, TokenState, TokenVisibility } from 'ts/types'; const TOKEN_ICON_DIMENSION = 100; const TILE_DIMENSION = 146; @@ -53,7 +41,7 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt public static defaultProps: Partial<AssetPickerProps> = { tokenVisibility: TokenVisibility.ALL, }; - private dialogConfigsByAssetView: {[assetView: string]: DialogConfigs}; + private _dialogConfigsByAssetView: { [assetView: string]: DialogConfigs }; constructor(props: AssetPickerProps) { super(props); this.state = { @@ -62,7 +50,7 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt chosenTrackTokenAddress: undefined, isAddingTokenToTracked: false, }; - this.dialogConfigsByAssetView = { + this._dialogConfigsByAssetView = { [AssetViews.ASSET_PICKER]: { title: 'Select token', isModal: false, @@ -80,45 +68,41 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt <FlatButton key="noTracking" label="No" - onTouchTap={this.onTrackConfirmationRespondedAsync.bind(this, false)} + onTouchTap={this._onTrackConfirmationRespondedAsync.bind(this, false)} />, <FlatButton key="yesTrack" label="Yes" - onTouchTap={this.onTrackConfirmationRespondedAsync.bind(this, true)} + onTouchTap={this._onTrackConfirmationRespondedAsync.bind(this, true)} />, ], }, }; } public render() { - const dialogConfigs: DialogConfigs = this.dialogConfigsByAssetView[this.state.assetView]; + const dialogConfigs: DialogConfigs = this._dialogConfigsByAssetView[this.state.assetView]; return ( <Dialog title={dialogConfigs.title} - titleStyle={{fontWeight: 100}} + titleStyle={{ fontWeight: 100 }} modal={dialogConfigs.isModal} open={this.props.isOpen} actions={dialogConfigs.actions} - onRequestClose={this.onCloseDialog.bind(this)} + onRequestClose={this._onCloseDialog.bind(this)} > - {this.state.assetView === AssetViews.ASSET_PICKER && - this.renderAssetPicker() - } - {this.state.assetView === AssetViews.NEW_TOKEN_FORM && + {this.state.assetView === AssetViews.ASSET_PICKER && this._renderAssetPicker()} + {this.state.assetView === AssetViews.NEW_TOKEN_FORM && ( <NewTokenForm blockchain={this.props.blockchain} - onNewTokenSubmitted={this.onNewTokenSubmitted.bind(this)} + onNewTokenSubmitted={this._onNewTokenSubmitted.bind(this)} tokenByAddress={this.props.tokenByAddress} /> - } - {this.state.assetView === AssetViews.CONFIRM_TRACK_TOKEN && - this.renderConfirmTrackToken() - } + )} + {this.state.assetView === AssetViews.CONFIRM_TRACK_TOKEN && this._renderConfirmTrackToken()} </Dialog> ); } - private renderConfirmTrackToken() { + private _renderConfirmTrackToken() { const token = this.props.tokenByAddress[this.state.chosenTrackTokenAddress]; return ( <TrackTokenConfirmation @@ -129,22 +113,29 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt /> ); } - private renderAssetPicker() { + private _renderAssetPicker() { return ( <div className="clearfix flex flex-wrap" - style={{overflowY: 'auto', maxWidth: 720, maxHeight: 356, marginBottom: 10}} + style={{ + overflowY: 'auto', + maxWidth: 720, + maxHeight: 356, + marginBottom: 10, + }} > - {this.renderGridTiles()} + {this._renderGridTiles()} </div> ); } - private renderGridTiles() { + private _renderGridTiles() { let isHovered; let tileStyles; const gridTiles = _.map(this.props.tokenByAddress, (token: Token, address: string) => { - if ((this.props.tokenVisibility === TokenVisibility.TRACKED && !token.isTracked) || - (this.props.tokenVisibility === TokenVisibility.UNTRACKED && token.isTracked)) { + if ( + (this.props.tokenVisibility === TokenVisibility.TRACKED && !token.isTracked) || + (this.props.tokenVisibility === TokenVisibility.UNTRACKED && token.isTracked) + ) { return null; // Skip } isHovered = this.state.hoveredAddress === address; @@ -155,11 +146,15 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt return ( <div key={address} - style={{width: TILE_DIMENSION, height: TILE_DIMENSION, ...tileStyles}} + style={{ + width: TILE_DIMENSION, + height: TILE_DIMENSION, + ...tileStyles, + }} className="p2 mx-auto" - onClick={this.onChooseToken.bind(this, address)} - onMouseEnter={this.onToggleHover.bind(this, address, true)} - onMouseLeave={this.onToggleHover.bind(this, address, false)} + onClick={this._onChooseToken.bind(this, address)} + onMouseEnter={this._onToggleHover.bind(this, address, true)} + onMouseLeave={this._onToggleHover.bind(this, address, false)} > <div className="p1 center"> <TokenIcon token={token} diameter={TOKEN_ICON_DIMENSION} /> @@ -175,40 +170,44 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt opacity: isHovered ? 0.6 : 1, }; if (this.props.tokenVisibility !== TokenVisibility.TRACKED) { - gridTiles.push(( + gridTiles.push( <div key={otherTokenKey} - style={{width: TILE_DIMENSION, height: TILE_DIMENSION, ...tileStyles}} + style={{ + width: TILE_DIMENSION, + height: TILE_DIMENSION, + ...tileStyles, + }} className="p2 mx-auto" - onClick={this.onCustomAssetChosen.bind(this)} - onMouseEnter={this.onToggleHover.bind(this, otherTokenKey, true)} - onMouseLeave={this.onToggleHover.bind(this, otherTokenKey, false)} + onClick={this._onCustomAssetChosen.bind(this)} + onMouseEnter={this._onToggleHover.bind(this, otherTokenKey, true)} + onMouseLeave={this._onToggleHover.bind(this, otherTokenKey, false)} > <div className="p1 center"> <i - style={{fontSize: 105, paddingLeft: 1, paddingRight: 1}} + style={{ fontSize: 105, paddingLeft: 1, paddingRight: 1 }} className="zmdi zmdi-plus-circle" /> </div> <div className="center">Other ERC20 Token</div> - </div> - )); + </div>, + ); } return gridTiles; } - private onToggleHover(address: string, isHovered: boolean) { + private _onToggleHover(address: string, isHovered: boolean) { const hoveredAddress = isHovered ? address : undefined; this.setState({ hoveredAddress, }); } - private onCloseDialog() { + private _onCloseDialog() { this.setState({ assetView: AssetViews.ASSET_PICKER, }); this.props.onTokenChosen(this.props.currentTokenAddress); } - private onChooseToken(tokenAddress: string) { + private _onChooseToken(tokenAddress: string) { const token = this.props.tokenByAddress[tokenAddress]; if (token.isTracked) { this.props.onTokenChosen(tokenAddress); @@ -219,27 +218,12 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt }); } } - private getTitle() { - switch (this.state.assetView) { - case AssetViews.ASSET_PICKER: - return 'Select token'; - - case AssetViews.NEW_TOKEN_FORM: - return 'Add an ERC20 token'; - - case AssetViews.CONFIRM_TRACK_TOKEN: - return 'Tracking confirmation'; - - default: - throw utils.spawnSwitchErr('assetView', this.state.assetView); - } - } - private onCustomAssetChosen() { + private _onCustomAssetChosen() { this.setState({ assetView: AssetViews.NEW_TOKEN_FORM, }); } - private onNewTokenSubmitted(newToken: Token, newTokenState: TokenState) { + private _onNewTokenSubmitted(newToken: Token, newTokenState: TokenState) { this.props.dispatcher.updateTokenStateByAddress({ [newToken.address]: newTokenState, }); @@ -250,14 +234,14 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt }); this.props.onTokenChosen(newToken.address); } - private async onTrackConfirmationRespondedAsync(didUserAcceptTracking: boolean) { + private async _onTrackConfirmationRespondedAsync(didUserAcceptTracking: boolean) { if (!didUserAcceptTracking) { this.setState({ isAddingTokenToTracked: false, assetView: AssetViews.ASSET_PICKER, chosenTrackTokenAddress: undefined, }); - this.onCloseDialog(); + this._onCloseDialog(); return; } this.setState({ @@ -265,15 +249,16 @@ export class AssetPicker extends React.Component<AssetPickerProps, AssetPickerSt }); const tokenAddress = this.state.chosenTrackTokenAddress; const token = this.props.tokenByAddress[tokenAddress]; - const newTokenEntry = _.assign({}, token); + const newTokenEntry = { + ...token, + }; newTokenEntry.isTracked = true; trackedTokenStorage.addTrackedTokenToUser(this.props.userAddress, this.props.networkId, newTokenEntry); - const [ - balance, - allowance, - ] = await this.props.blockchain.getCurrentUserTokenBalanceAndAllowanceAsync(token.address); + const [balance, allowance] = await this.props.blockchain.getCurrentUserTokenBalanceAndAllowanceAsync( + token.address, + ); this.props.dispatcher.updateTokenStateByAddress({ [token.address]: { balance, diff --git a/packages/website/ts/components/generate_order/generate_order_form.tsx b/packages/website/ts/components/generate_order/generate_order_form.tsx index 72edf08cf..3ae0d48a7 100644 --- a/packages/website/ts/components/generate_order/generate_order_form.tsx +++ b/packages/website/ts/components/generate_order/generate_order_form.tsx @@ -1,24 +1,23 @@ -import {Order, ZeroEx} from '0x.js'; -import BigNumber from 'bignumber.js'; +import { Order, ZeroEx } from '0x.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import Dialog from 'material-ui/Dialog'; import Divider from 'material-ui/Divider'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; -import {Blockchain} from 'ts/blockchain'; -import {ExpirationInput} from 'ts/components/inputs/expiration_input'; -import {HashInput} from 'ts/components/inputs/hash_input'; -import {IdenticonAddressInput} from 'ts/components/inputs/identicon_address_input'; -import {TokenAmountInput} from 'ts/components/inputs/token_amount_input'; -import {TokenInput} from 'ts/components/inputs/token_input'; -import {OrderJSON} from 'ts/components/order_json'; -import {Alert} from 'ts/components/ui/alert'; -import {HelpTooltip} from 'ts/components/ui/help_tooltip'; -import {LifeCycleRaisedButton} from 'ts/components/ui/lifecycle_raised_button'; -import {SwapIcon} from 'ts/components/ui/swap_icon'; -import {Dispatcher} from 'ts/redux/dispatcher'; -import {orderSchema} from 'ts/schemas/order_schema'; -import {SchemaValidator} from 'ts/schemas/validator'; +import { Blockchain } from 'ts/blockchain'; +import { ExpirationInput } from 'ts/components/inputs/expiration_input'; +import { HashInput } from 'ts/components/inputs/hash_input'; +import { IdenticonAddressInput } from 'ts/components/inputs/identicon_address_input'; +import { TokenAmountInput } from 'ts/components/inputs/token_amount_input'; +import { TokenInput } from 'ts/components/inputs/token_input'; +import { OrderJSON } from 'ts/components/order_json'; +import { Alert } from 'ts/components/ui/alert'; +import { HelpTooltip } from 'ts/components/ui/help_tooltip'; +import { LifeCycleRaisedButton } from 'ts/components/ui/lifecycle_raised_button'; +import { SwapIcon } from 'ts/components/ui/swap_icon'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { orderSchema } from 'ts/schemas/order_schema'; +import { SchemaValidator } from 'ts/schemas/validator'; import { AlertTypes, BlockchainErrs, @@ -30,8 +29,9 @@ import { TokenByAddress, TokenStateByAddress, } from 'ts/types'; -import {errorReporter} from 'ts/utils/error_reporter'; -import {utils} from 'ts/utils/utils'; +import { colors } from 'ts/utils/colors'; +import { errorReporter } from 'ts/utils/error_reporter'; +import { utils } from 'ts/utils/utils'; enum SigningState { UNSIGNED, @@ -62,17 +62,8 @@ interface GenerateOrderFormState { signingState: SigningState; } -const style = { - paper: { - display: 'inline-block', - position: 'relative', - textAlign: 'center', - width: '100%', - }, -}; - -export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, any> { - private validator: SchemaValidator; +export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, GenerateOrderFormState> { + private _validator: SchemaValidator; constructor(props: GenerateOrderFormProps) { super(props); this.state = { @@ -80,20 +71,21 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, a shouldShowIncompleteErrs: false, signingState: SigningState.UNSIGNED, }; - this.validator = new SchemaValidator(); + this._validator = new SchemaValidator(); } public componentDidMount() { window.scrollTo(0, 0); } public render() { const dispatcher = this.props.dispatcher; - const depositTokenAddress = this.props.sideToAssetToken[Side.deposit].address; + const depositTokenAddress = this.props.sideToAssetToken[Side.Deposit].address; const depositToken = this.props.tokenByAddress[depositTokenAddress]; const depositTokenState = this.props.tokenStateByAddress[depositTokenAddress]; - const receiveTokenAddress = this.props.sideToAssetToken[Side.receive].address; + const receiveTokenAddress = this.props.sideToAssetToken[Side.Receive].address; const receiveToken = this.props.tokenByAddress[receiveTokenAddress]; const receiveTokenState = this.props.tokenStateByAddress[receiveTokenAddress]; - const takerExplanation = 'If a taker is specified, only they are<br> \ + const takerExplanation = + 'If a taker is specified, only they are<br> \ allowed to fill this order. If no taker is<br> \ specified, anyone is able to fill it.'; const exchangeContractIfExists = this.props.blockchain.getExchangeContractAddressIfExists(); @@ -101,7 +93,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, a <div className="clearfix mb2 lg-px4 md-px4 sm-px2"> <h3>Generate an order</h3> <Divider /> - <div className="mx-auto" style={{maxWidth: 580}}> + <div className="mx-auto" style={{ maxWidth: 580 }}> <div className="pt3"> <div className="mx-auto clearfix"> <div className="lg-col md-col lg-col-5 md-col-5 sm-col sm-col-5 sm-pb2"> @@ -111,9 +103,9 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, a blockchainErr={this.props.blockchainErr} dispatcher={this.props.dispatcher} label="Selling" - side={Side.deposit} + side={Side.Deposit} networkId={this.props.networkId} - assetToken={this.props.sideToAssetToken[Side.deposit]} + assetToken={this.props.sideToAssetToken[Side.Deposit]} updateChosenAssetToken={dispatcher.updateChosenAssetToken.bind(dispatcher)} tokenByAddress={this.props.tokenByAddress} /> @@ -121,8 +113,8 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, a label="Sell amount" token={depositToken} tokenState={depositTokenState} - amount={this.props.sideToAssetToken[Side.deposit].amount} - onChange={this.onTokenAmountChange.bind(this, depositToken, Side.deposit)} + amount={this.props.sideToAssetToken[Side.Deposit].amount} + onChange={this._onTokenAmountChange.bind(this, depositToken, Side.Deposit)} shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs} shouldCheckBalance={true} shouldCheckAllowance={true} @@ -130,9 +122,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, a </div> <div className="lg-col md-col lg-col-2 md-col-2 sm-col sm-col-2 xs-hide"> <div className="p1"> - <SwapIcon - swapTokensFn={dispatcher.swapAssetTokenSymbols.bind(dispatcher)} - /> + <SwapIcon swapTokensFn={dispatcher.swapAssetTokenSymbols.bind(dispatcher)} /> </div> </div> <div className="lg-col md-col lg-col-5 md-col-5 sm-col sm-col-5 sm-pb2"> @@ -142,9 +132,9 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, a blockchainErr={this.props.blockchainErr} dispatcher={this.props.dispatcher} label="Buying" - side={Side.receive} + side={Side.Receive} networkId={this.props.networkId} - assetToken={this.props.sideToAssetToken[Side.receive]} + assetToken={this.props.sideToAssetToken[Side.Receive]} updateChosenAssetToken={dispatcher.updateChosenAssetToken.bind(dispatcher)} tokenByAddress={this.props.tokenByAddress} /> @@ -152,8 +142,8 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, a label="Receive amount" token={receiveToken} tokenState={receiveTokenState} - amount={this.props.sideToAssetToken[Side.receive].amount} - onChange={this.onTokenAmountChange.bind(this, receiveToken, Side.receive)} + amount={this.props.sideToAssetToken[Side.Receive].amount} + onChange={this._onTokenAmountChange.bind(this, receiveToken, Side.Receive)} shouldShowIncompleteErrs={this.state.shouldShowIncompleteErrs} shouldCheckBalance={false} shouldCheckAllowance={false} @@ -163,7 +153,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, a </div> <div className="pt1 sm-pb2 lg-px4 md-px4"> <div className="lg-px3 md-px3"> - <div style={{fontSize: 12, color: colors.grey500}}>Expiration</div> + <div style={{ fontSize: 12, color: colors.grey }}>Expiration</div> <ExpirationInput orderExpiryTimestamp={this.props.orderExpiryTimestamp} updateOrderExpiry={dispatcher.updateOrderExpiry.bind(dispatcher)} @@ -174,13 +164,11 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, a <IdenticonAddressInput label="Taker" initialAddress={this.props.orderTakerAddress} - updateOrderAddress={this.updateOrderAddress.bind(this)} + updateOrderAddress={this._updateOrderAddress.bind(this)} /> <div className="pt3"> <div className="pl1"> - <HelpTooltip - explanation={takerExplanation} - /> + <HelpTooltip explanation={takerExplanation} /> </div> </div> </div> @@ -198,20 +186,20 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, a labelReady="Sign hash" labelLoading="Signing..." labelComplete="Hash signed!" - onClickAsyncFn={this.onSignClickedAsync.bind(this)} + onClickAsyncFn={this._onSignClickedAsync.bind(this)} /> </div> - {this.state.globalErrMsg !== '' && + {this.state.globalErrMsg !== '' && ( <Alert type={AlertTypes.ERROR} message={this.state.globalErrMsg} /> - } + )} </div> </div> <Dialog title="Order JSON" - titleStyle={{fontWeight: 100}} + titleStyle={{ fontWeight: 100 }} modal={false} open={this.state.signingState === SigningState.SIGNED} - onRequestClose={this.onCloseOrderJSONDialog.bind(this)} + onRequestClose={this._onCloseOrderJSONDialog.bind(this)} > <OrderJSON exchangeContractIfExists={exchangeContractIfExists} @@ -231,10 +219,13 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, a </div> ); } - private onTokenAmountChange(token: Token, side: Side, isValid: boolean, amount?: BigNumber) { - this.props.dispatcher.updateChosenAssetToken(side, {address: token.address, amount}); + private _onTokenAmountChange(token: Token, side: Side, isValid: boolean, amount?: BigNumber) { + this.props.dispatcher.updateChosenAssetToken(side, { + address: token.address, + amount, + }); } - private onCloseOrderJSONDialog() { + private _onCloseOrderJSONDialog() { // Upon closing the order JSON dialog, we update the orderSalt stored in the Redux store // with a new value so that if a user signs the identical order again, the newly signed // orderHash will not collide with the previously generated orderHash. @@ -243,22 +234,27 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, a signingState: SigningState.UNSIGNED, }); } - private async onSignClickedAsync(): Promise<boolean> { - if (this.props.blockchainErr !== '') { + private async _onSignClickedAsync(): Promise<boolean> { + if (this.props.blockchainErr !== BlockchainErrs.NoError) { this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); return false; } // Check if all required inputs were supplied - const debitToken = this.props.sideToAssetToken[Side.deposit]; + const debitToken = this.props.sideToAssetToken[Side.Deposit]; const debitBalance = this.props.tokenStateByAddress[debitToken.address].balance; const debitAllowance = this.props.tokenStateByAddress[debitToken.address].allowance; - const receiveAmount = this.props.sideToAssetToken[Side.receive].amount; - if (!_.isUndefined(debitToken.amount) && !_.isUndefined(receiveAmount) && - debitToken.amount.gt(0) && receiveAmount.gt(0) && + const receiveAmount = this.props.sideToAssetToken[Side.Receive].amount; + if ( + !_.isUndefined(debitToken.amount) && + !_.isUndefined(receiveAmount) && + debitToken.amount.gt(0) && + receiveAmount.gt(0) && this.props.userAddress !== '' && - debitBalance.gte(debitToken.amount) && debitAllowance.gte(debitToken.amount)) { - const didSignSuccessfully = await this.signTransactionAsync(); + debitBalance.gte(debitToken.amount) && + debitAllowance.gte(debitToken.amount) + ) { + const didSignSuccessfully = await this._signTransactionAsync(); if (didSignSuccessfully) { this.setState({ globalErrMsg: '', @@ -279,7 +275,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, a return false; } } - private async signTransactionAsync(): Promise<boolean> { + private async _signTransactionAsync(): Promise<boolean> { this.setState({ signingState: SigningState.SIGNING, }); @@ -287,7 +283,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, a if (_.isUndefined(exchangeContractAddr)) { this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); this.setState({ - isSigning: false, + signingState: SigningState.UNSIGNED, }); return false; } @@ -312,19 +308,28 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, a let globalErrMsg = ''; try { const signatureData = await this.props.blockchain.signOrderHashAsync(orderHash); - const order = utils.generateOrder(this.props.networkId, exchangeContractAddr, this.props.sideToAssetToken, - hashData.orderExpiryTimestamp, this.props.orderTakerAddress, - this.props.userAddress, hashData.makerFee, hashData.takerFee, - hashData.feeRecipientAddress, signatureData, this.props.tokenByAddress, - hashData.orderSalt); - const validationResult = this.validator.validate(order, orderSchema); + const order = utils.generateOrder( + this.props.networkId, + exchangeContractAddr, + this.props.sideToAssetToken, + hashData.orderExpiryTimestamp, + this.props.orderTakerAddress, + this.props.userAddress, + hashData.makerFee, + hashData.takerFee, + hashData.feeRecipientAddress, + signatureData, + this.props.tokenByAddress, + hashData.orderSalt, + ); + const validationResult = this._validator.validate(order, orderSchema); if (validationResult.errors.length > 0) { globalErrMsg = 'Order signing failed. Please refresh and try again'; utils.consoleLog(`Unexpected error occured: Order validation failed: ${validationResult.errors}`); } } catch (err) { - const errMsg = '' + err; + const errMsg = `${err}`; if (utils.didUserDenyWeb3Request(errMsg)) { globalErrMsg = 'User denied sign request'; } else { @@ -340,7 +345,7 @@ export class GenerateOrderForm extends React.Component<GenerateOrderFormProps, a }); return globalErrMsg === ''; } - private updateOrderAddress(address?: string): void { + private _updateOrderAddress(address?: string): void { if (!_.isUndefined(address)) { this.props.dispatcher.updateOrderTakerAddress(address); } diff --git a/packages/website/ts/components/generate_order/new_token_form.tsx b/packages/website/ts/components/generate_order/new_token_form.tsx index 7e2c61ae8..63645be9a 100644 --- a/packages/website/ts/components/generate_order/new_token_form.tsx +++ b/packages/website/ts/components/generate_order/new_token_form.tsx @@ -1,15 +1,14 @@ -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; -import {colors} from 'material-ui/styles'; import TextField from 'material-ui/TextField'; import * as React from 'react'; -import {Blockchain} from 'ts/blockchain'; -import {AddressInput} from 'ts/components/inputs/address_input'; -import {Alert} from 'ts/components/ui/alert'; -import {LifeCycleRaisedButton} from 'ts/components/ui/lifecycle_raised_button'; -import {RequiredLabel} from 'ts/components/ui/required_label'; -import {AlertTypes, Token, TokenByAddress, TokenState} from 'ts/types'; -import {constants} from 'ts/utils/constants'; +import { Blockchain } from 'ts/blockchain'; +import { AddressInput } from 'ts/components/inputs/address_input'; +import { Alert } from 'ts/components/ui/alert'; +import { LifeCycleRaisedButton } from 'ts/components/ui/lifecycle_raised_button'; +import { RequiredLabel } from 'ts/components/ui/required_label'; +import { AlertTypes, Token, TokenByAddress, TokenState } from 'ts/types'; +import { colors } from 'ts/utils/colors'; interface NewTokenFormProps { blockchain: Blockchain; @@ -46,25 +45,25 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor } public render() { return ( - <div className="mx-auto pb2" style={{width: 256}}> + <div className="mx-auto pb2" style={{ width: 256 }}> <div> <TextField floatingLabelFixed={true} - floatingLabelStyle={{color: colors.grey500}} + floatingLabelStyle={{ color: colors.grey }} floatingLabelText={<RequiredLabel label="Name" />} value={this.state.name} errorText={this.state.nameErrText} - onChange={this.onTokenNameChanged.bind(this)} + onChange={this._onTokenNameChanged.bind(this)} /> </div> <div> <TextField floatingLabelFixed={true} - floatingLabelStyle={{color: colors.grey500}} + floatingLabelStyle={{ color: colors.grey }} floatingLabelText={<RequiredLabel label="Symbol" />} value={this.state.symbol} errorText={this.state.symbolErrText} - onChange={this.onTokenSymbolChanged.bind(this)} + onChange={this._onTokenSymbolChanged.bind(this)} /> </div> <div> @@ -73,38 +72,36 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor label="Contract address" initialAddress="" shouldShowIncompleteErrs={this.state.shouldShowAddressIncompleteErr} - updateAddress={this.onTokenAddressChanged.bind(this)} + updateAddress={this._onTokenAddressChanged.bind(this)} /> </div> <div> <TextField floatingLabelFixed={true} - floatingLabelStyle={{color: colors.grey500}} + floatingLabelStyle={{ color: colors.grey }} floatingLabelText={<RequiredLabel label="Decimals" />} value={this.state.decimals} errorText={this.state.decimalsErrText} - onChange={this.onTokenDecimalsChanged.bind(this)} + onChange={this._onTokenDecimalsChanged.bind(this)} /> </div> - <div className="pt2 mx-auto" style={{width: 120}}> + <div className="pt2 mx-auto" style={{ width: 120 }}> <LifeCycleRaisedButton labelReady="Add" labelLoading="Adding..." labelComplete="Added!" - onClickAsyncFn={this.onAddNewTokenClickAsync.bind(this)} + onClickAsyncFn={this._onAddNewTokenClickAsync.bind(this)} /> </div> - {this.state.globalErrMsg !== '' && - <Alert type={AlertTypes.ERROR} message={this.state.globalErrMsg} /> - } + {this.state.globalErrMsg !== '' && <Alert type={AlertTypes.ERROR} message={this.state.globalErrMsg} />} </div> ); } - private async onAddNewTokenClickAsync() { + private async _onAddNewTokenClickAsync() { // Trigger validation of name and symbol - this.onTokenNameChanged(undefined, this.state.name); - this.onTokenSymbolChanged(undefined, this.state.symbol); - this.onTokenDecimalsChanged(undefined, this.state.decimals); + this._onTokenNameChanged(undefined, this.state.name); + this._onTokenSymbolChanged(undefined, this.state.symbol); + this._onTokenDecimalsChanged(undefined, this.state.decimals); const isAddressIncomplete = this.state.address === ''; let doesContractExist = false; @@ -117,18 +114,21 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor let allowance = new BigNumber(0); if (doesContractExist) { try { - [ - balance, - allowance, - ] = await this.props.blockchain.getCurrentUserTokenBalanceAndAllowanceAsync(this.state.address); + [balance, allowance] = await this.props.blockchain.getCurrentUserTokenBalanceAndAllowanceAsync( + this.state.address, + ); } catch (err) { hasBalanceAllowanceErr = true; } } let globalErrMsg = ''; - if (this.state.nameErrText !== '' || this.state.symbolErrText !== '' || - this.state.decimalsErrText !== '' || isAddressIncomplete) { + if ( + this.state.nameErrText !== '' || + this.state.symbolErrText !== '' || + this.state.decimalsErrText !== '' || + isAddressIncomplete + ) { globalErrMsg = 'Please fix the above issues'; } else if (!doesContractExist) { globalErrMsg = 'No contract found at supplied address'; @@ -161,15 +161,15 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor }; this.props.onNewTokenSubmitted(newToken, newTokenState); } - private onTokenNameChanged(e: any, name: string) { + private _onTokenNameChanged(e: any, name: string) { let nameErrText = ''; const maxLength = 30; const tokens = _.values(this.props.tokenByAddress); - const tokenWithNameIfExists = _.find(tokens, {name}); + const tokenWithNameIfExists = _.find(tokens, { name }); const tokenWithNameExists = !_.isUndefined(tokenWithNameIfExists); if (name === '') { nameErrText = 'Name is required'; - } else if (!this.isValidName(name)) { + } else if (!this._isValidName(name)) { nameErrText = 'Name should only contain letters, digits and spaces'; } else if (name.length > maxLength) { nameErrText = `Max length is ${maxLength}`; @@ -182,15 +182,15 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor nameErrText, }); } - private onTokenSymbolChanged(e: any, symbol: string) { + private _onTokenSymbolChanged(e: any, symbol: string) { let symbolErrText = ''; const maxLength = 5; const tokens = _.values(this.props.tokenByAddress); - const tokenWithSymbolExists = !_.isUndefined(_.find(tokens, {symbol})); + const tokenWithSymbolExists = !_.isUndefined(_.find(tokens, { symbol })); if (symbol === '') { symbolErrText = 'Symbol is required'; - } else if (!this.isLetters(symbol)) { - symbolErrText = 'Can only include letters'; + } else if (!this._isAlphanumeric(symbol)) { + symbolErrText = 'Can only include alphanumeric characters'; } else if (symbol.length > maxLength) { symbolErrText = `Max length is ${maxLength}`; } else if (tokenWithSymbolExists) { @@ -202,12 +202,12 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor symbolErrText, }); } - private onTokenDecimalsChanged(e: any, decimals: string) { + private _onTokenDecimalsChanged(e: any, decimals: string) { let decimalsErrText = ''; const maxLength = 2; if (decimals === '') { decimalsErrText = 'Decimals is required'; - } else if (!this.isInteger(decimals)) { + } else if (!this._isInteger(decimals)) { decimalsErrText = 'Must be an integer'; } else if (decimals.length > maxLength) { decimalsErrText = `Max length is ${maxLength}`; @@ -218,20 +218,20 @@ export class NewTokenForm extends React.Component<NewTokenFormProps, NewTokenFor decimalsErrText, }); } - private onTokenAddressChanged(address?: string) { + private _onTokenAddressChanged(address?: string) { if (!_.isUndefined(address)) { this.setState({ address, }); } } - private isValidName(input: string) { + private _isValidName(input: string) { return /^[a-z0-9 ]+$/i.test(input); } - private isInteger(input: string) { + private _isInteger(input: string) { return /^[0-9]+$/i.test(input); } - private isLetters(input: string) { - return /^[a-zA-Z]+$/i.test(input); + private _isAlphanumeric(input: string) { + return /^[a-zA-Z0-9]+$/i.test(input); } } diff --git a/packages/website/ts/components/inputs/address_input.tsx b/packages/website/ts/components/inputs/address_input.tsx index 8b03b8d12..dd4131140 100644 --- a/packages/website/ts/components/inputs/address_input.tsx +++ b/packages/website/ts/components/inputs/address_input.tsx @@ -1,10 +1,9 @@ -import {isAddress} from 'ethereum-address'; +import { addressUtils } from '@0xproject/utils'; import * as _ from 'lodash'; -import {colors} from 'material-ui/styles'; import TextField from 'material-ui/TextField'; import * as React from 'react'; -import {Blockchain} from 'ts/blockchain'; -import {RequiredLabel} from 'ts/components/ui/required_label'; +import { RequiredLabel } from 'ts/components/ui/required_label'; +import { colors } from 'ts/utils/colors'; interface AddressInputProps { disabled?: boolean; @@ -31,16 +30,14 @@ export class AddressInput extends React.Component<AddressInputProps, AddressInpu }; } public componentWillReceiveProps(nextProps: AddressInputProps) { - if (nextProps.shouldShowIncompleteErrs && this.props.isRequired && - this.state.address === '') { - this.setState({ - errMsg: 'Address is required', - }); + if (nextProps.shouldShowIncompleteErrs && this.props.isRequired && this.state.address === '') { + this.setState({ + errMsg: 'Address is required', + }); } } public render() { - const label = this.props.isRequired ? <RequiredLabel label={this.props.label} /> : - this.props.label; + const label = this.props.isRequired ? <RequiredLabel label={this.props.label} /> : this.props.label; const labelDisplay = this.props.shouldHideLabel ? 'hidden' : 'block'; const hintText = this.props.hintText ? this.props.hintText : ''; return ( @@ -51,18 +48,18 @@ export class AddressInput extends React.Component<AddressInputProps, AddressInpu fullWidth={true} hintText={hintText} floatingLabelFixed={true} - floatingLabelStyle={{color: colors.grey500, display: labelDisplay}} + floatingLabelStyle={{ color: colors.grey, display: labelDisplay }} floatingLabelText={label} errorText={this.state.errMsg} value={this.state.address} - onChange={this.onOrderTakerAddressUpdated.bind(this)} + onChange={this._onOrderTakerAddressUpdated.bind(this)} /> </div> ); } - private onOrderTakerAddressUpdated(e: any) { + private _onOrderTakerAddressUpdated(e: any) { const address = e.target.value.toLowerCase(); - const isValidAddress = isAddress(address) || address === ''; + const isValidAddress = addressUtils.isAddress(address) || address === ''; const errMsg = isValidAddress ? '' : 'Invalid ethereum address'; this.setState({ address, diff --git a/packages/website/ts/components/inputs/allowance_toggle.tsx b/packages/website/ts/components/inputs/allowance_toggle.tsx index 4c15ed4a0..da46db4f4 100644 --- a/packages/website/ts/components/inputs/allowance_toggle.tsx +++ b/packages/website/ts/components/inputs/allowance_toggle.tsx @@ -1,12 +1,12 @@ -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import Toggle from 'material-ui/Toggle'; import * as React from 'react'; -import {Blockchain} from 'ts/blockchain'; -import {Dispatcher} from 'ts/redux/dispatcher'; -import {BalanceErrs, Token, TokenState} from 'ts/types'; -import {errorReporter} from 'ts/utils/error_reporter'; -import {utils} from 'ts/utils/utils'; +import { Blockchain } from 'ts/blockchain'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { BalanceErrs, Token, TokenState } from 'ts/types'; +import { errorReporter } from 'ts/utils/error_reporter'; +import { utils } from 'ts/utils/utils'; const DEFAULT_ALLOWANCE_AMOUNT_IN_BASE_UNITS = new BigNumber(2).pow(256).minus(1); @@ -46,22 +46,21 @@ export class AllowanceToggle extends React.Component<AllowanceToggleProps, Allow <div> <Toggle disabled={this.state.isSpinnerVisible} - toggled={this.isAllowanceSet()} - onToggle={this.onToggleAllowanceAsync.bind(this, this.props.token)} + toggled={this._isAllowanceSet()} + onToggle={this._onToggleAllowanceAsync.bind(this)} /> </div> - {this.state.isSpinnerVisible && - <div className="pl1" style={{paddingTop: 3}}> + {this.state.isSpinnerVisible && ( + <div className="pl1" style={{ paddingTop: 3 }}> <i className="zmdi zmdi-spinner zmdi-hc-spin" /> </div> - } + )} </div> ); } - private async onToggleAllowanceAsync() { + private async _onToggleAllowanceAsync(): Promise<void> { if (this.props.userAddress === '') { this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); - return false; } this.setState({ @@ -69,7 +68,7 @@ export class AllowanceToggle extends React.Component<AllowanceToggleProps, Allow }); let newAllowanceAmountInBaseUnits = new BigNumber(0); - if (!this.isAllowanceSet()) { + if (!this._isAllowanceSet()) { newAllowanceAmountInBaseUnits = DEFAULT_ALLOWANCE_AMOUNT_IN_BASE_UNITS; } try { @@ -78,17 +77,17 @@ export class AllowanceToggle extends React.Component<AllowanceToggleProps, Allow this.setState({ isSpinnerVisible: false, }); - const errMsg = '' + err; + const errMsg = `${err}`; if (_.includes(errMsg, 'User denied transaction')) { - return false; + return; } utils.consoleLog(`Unexpected error encountered: ${err}`); utils.consoleLog(err.stack); - await errorReporter.reportAsync(err); this.props.onErrorOccurred(BalanceErrs.allowanceSettingFailed); + await errorReporter.reportAsync(err); } } - private isAllowanceSet() { + private _isAllowanceSet() { return !this.props.tokenState.allowance.eq(0); } } diff --git a/packages/website/ts/components/inputs/balance_bounded_input.tsx b/packages/website/ts/components/inputs/balance_bounded_input.tsx index 7ddefc3b9..ddc434b51 100644 --- a/packages/website/ts/components/inputs/balance_bounded_input.tsx +++ b/packages/website/ts/components/inputs/balance_bounded_input.tsx @@ -1,12 +1,12 @@ -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; -import {colors} from 'material-ui/styles'; import TextField from 'material-ui/TextField'; import * as React from 'react'; -import {Link} from 'react-router-dom'; -import {RequiredLabel} from 'ts/components/ui/required_label'; -import {InputErrMsg, ValidatedBigNumberCallback, WebsitePaths} from 'ts/types'; -import {utils} from 'ts/utils/utils'; +import { Link } from 'react-router-dom'; +import { RequiredLabel } from 'ts/components/ui/required_label'; +import { InputErrMsg, ValidatedBigNumberCallback, WebsitePaths } from 'ts/types'; +import { colors } from 'ts/utils/colors'; +import { utils } from 'ts/utils/utils'; interface BalanceBoundedInputProps { label?: string; @@ -25,8 +25,7 @@ interface BalanceBoundedInputState { amountString: string; } -export class BalanceBoundedInput extends - React.Component<BalanceBoundedInputProps, BalanceBoundedInputState> { +export class BalanceBoundedInput extends React.Component<BalanceBoundedInputProps, BalanceBoundedInputState> { public static defaultProps: Partial<BalanceBoundedInputProps> = { shouldShowIncompleteErrs: false, shouldHideVisitBalancesLink: false, @@ -35,7 +34,7 @@ export class BalanceBoundedInput extends super(props); const amountString = this.props.amount ? this.props.amount.toString() : ''; this.state = { - errMsg: this.validate(amountString, props.balance), + errMsg: this._validate(amountString, props.balance), amountString, }; } @@ -57,14 +56,14 @@ export class BalanceBoundedInput extends if (shouldResetState) { const amountString = nextProps.amount.toString(); this.setState({ - errMsg: this.validate(amountString, nextProps.balance), + errMsg: this._validate(amountString, nextProps.balance), amountString, }); } } else if (isCurrentAmountNumeric) { const amountString = ''; this.setState({ - errMsg: this.validate(amountString, nextProps.balance), + errMsg: this._validate(amountString, nextProps.balance), amountString, }); } @@ -74,39 +73,42 @@ export class BalanceBoundedInput extends if (this.props.shouldShowIncompleteErrs && this.state.amountString === '') { errorText = 'This field is required'; } - let label: React.ReactNode|string = ''; + let label: React.ReactNode | string = ''; if (!_.isUndefined(this.props.label)) { - label = <RequiredLabel label={this.props.label}/>; + label = <RequiredLabel label={this.props.label} />; } return ( <TextField fullWidth={true} floatingLabelText={label} floatingLabelFixed={true} - floatingLabelStyle={{color: colors.grey500, width: 206}} + floatingLabelStyle={{ color: colors.grey, width: 206 }} errorText={errorText} value={this.state.amountString} - hintText={<span style={{textTransform: 'capitalize'}}>amount</span>} - onChange={this.onValueChange.bind(this)} - underlineStyle={{width: 'calc(100% + 50px)'}} + hintText={<span style={{ textTransform: 'capitalize' }}>amount</span>} + onChange={this._onValueChange.bind(this)} + underlineStyle={{ width: 'calc(100% + 50px)' }} /> ); } - private onValueChange(e: any, amountString: string) { - const errMsg = this.validate(amountString, this.props.balance); - this.setState({ - amountString, - errMsg, - }, () => { - const isValid = _.isUndefined(errMsg); - if (utils.isNumeric(amountString)) { - this.props.onChange(isValid, new BigNumber(amountString)); - } else { - this.props.onChange(isValid); - } - }); + private _onValueChange(e: any, amountString: string) { + const errMsg = this._validate(amountString, this.props.balance); + this.setState( + { + amountString, + errMsg, + }, + () => { + const isValid = _.isUndefined(errMsg); + if (utils.isNumeric(amountString)) { + this.props.onChange(isValid, new BigNumber(amountString)); + } else { + this.props.onChange(isValid); + } + }, + ); } - private validate(amountString: string, balance: BigNumber): InputErrMsg { + private _validate(amountString: string, balance: BigNumber): InputErrMsg { if (!utils.isNumeric(amountString)) { return amountString !== '' ? 'Must be a number' : ''; } @@ -115,17 +117,12 @@ export class BalanceBoundedInput extends return 'Cannot be zero'; } if (this.props.shouldCheckBalance && amount.gt(balance)) { - return ( - <span> - Insufficient balance.{' '} - {this.renderIncreaseBalanceLink()} - </span> - ); + return <span>Insufficient balance. {this._renderIncreaseBalanceLink()}</span>; } const errMsg = _.isUndefined(this.props.validate) ? undefined : this.props.validate(amount); return errMsg; } - private renderIncreaseBalanceLink() { + private _renderIncreaseBalanceLink() { if (this.props.shouldHideVisitBalancesLink) { return null; } @@ -133,25 +130,19 @@ export class BalanceBoundedInput extends const increaseBalanceText = 'Increase balance'; const linkStyle = { cursor: 'pointer', - color: colors.grey900, + color: colors.darkestGrey, textDecoration: 'underline', display: 'inline', }; if (_.isUndefined(this.props.onVisitBalancesPageClick)) { return ( - <Link - to={`${WebsitePaths.Portal}/balances`} - style={linkStyle} - > + <Link to={`${WebsitePaths.Portal}/balances`} style={linkStyle}> {increaseBalanceText} </Link> ); } else { return ( - <div - onClick={this.props.onVisitBalancesPageClick} - style={linkStyle} - > + <div onClick={this.props.onVisitBalancesPageClick} style={linkStyle}> {increaseBalanceText} </div> ); diff --git a/packages/website/ts/components/inputs/eth_amount_input.tsx b/packages/website/ts/components/inputs/eth_amount_input.tsx index 5c5e23eef..a66f92c8c 100644 --- a/packages/website/ts/components/inputs/eth_amount_input.tsx +++ b/packages/website/ts/components/inputs/eth_amount_input.tsx @@ -1,10 +1,10 @@ -import {ZeroEx} from '0x.js'; -import BigNumber from 'bignumber.js'; +import { ZeroEx } from '0x.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import * as React from 'react'; -import {BalanceBoundedInput} from 'ts/components/inputs/balance_bounded_input'; -import {ValidatedBigNumberCallback} from 'ts/types'; -import {constants} from 'ts/utils/constants'; +import { BalanceBoundedInput } from 'ts/components/inputs/balance_bounded_input'; +import { ValidatedBigNumberCallback } from 'ts/types'; +import { constants } from 'ts/utils/constants'; interface EthAmountInputProps { label?: string; @@ -21,31 +21,29 @@ interface EthAmountInputState {} export class EthAmountInput extends React.Component<EthAmountInputProps, EthAmountInputState> { public render() { - const amount = this.props.amount ? - ZeroEx.toUnitAmount(this.props.amount, constants.ETH_DECIMAL_PLACES) : - undefined; + const amount = this.props.amount + ? ZeroEx.toUnitAmount(this.props.amount, constants.DECIMAL_PLACES_ETH) + : undefined; return ( - <div className="flex overflow-hidden" style={{height: 63}}> + <div className="flex overflow-hidden" style={{ height: 63 }}> <BalanceBoundedInput label={this.props.label} balance={this.props.balance} amount={amount} - onChange={this.onChange.bind(this)} + onChange={this._onChange.bind(this)} shouldCheckBalance={this.props.shouldCheckBalance} shouldShowIncompleteErrs={this.props.shouldShowIncompleteErrs} onVisitBalancesPageClick={this.props.onVisitBalancesPageClick} shouldHideVisitBalancesLink={this.props.shouldHideVisitBalancesLink} /> - <div style={{paddingTop: _.isUndefined(this.props.label) ? 15 : 40}}> - ETH - </div> + <div style={{ paddingTop: _.isUndefined(this.props.label) ? 15 : 40 }}>ETH</div> </div> ); } - private onChange(isValid: boolean, amount?: BigNumber) { - const baseUnitAmountIfExists = _.isUndefined(amount) ? - undefined : - ZeroEx.toBaseUnitAmount(amount, constants.ETH_DECIMAL_PLACES); + private _onChange(isValid: boolean, amount?: BigNumber) { + const baseUnitAmountIfExists = _.isUndefined(amount) + ? undefined + : ZeroEx.toBaseUnitAmount(amount, constants.DECIMAL_PLACES_ETH); this.props.onChange(isValid, baseUnitAmountIfExists); } } diff --git a/packages/website/ts/components/inputs/expiration_input.tsx b/packages/website/ts/components/inputs/expiration_input.tsx index d3d3d258d..e473648d2 100644 --- a/packages/website/ts/components/inputs/expiration_input.tsx +++ b/packages/website/ts/components/inputs/expiration_input.tsx @@ -1,10 +1,10 @@ -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import DatePicker from 'material-ui/DatePicker'; import TimePicker from 'material-ui/TimePicker'; import * as moment from 'moment'; import * as React from 'react'; -import {utils} from 'ts/utils/utils'; +import { utils } from 'ts/utils/utils'; interface ExpirationInputProps { orderExpiryTimestamp: BigNumber; @@ -17,11 +17,11 @@ interface ExpirationInputState { } export class ExpirationInput extends React.Component<ExpirationInputProps, ExpirationInputState> { - private earliestPickableMoment: moment.Moment; + private _earliestPickableMoment: moment.Moment; constructor(props: ExpirationInputProps) { super(props); // Set the earliest pickable date to today at 00:00, so users can only pick the current or later dates - this.earliestPickableMoment = moment().startOf('day'); + this._earliestPickableMoment = moment().startOf('day'); const expirationMoment = utils.convertToMomentFromUnixTimestamp(props.orderExpiryTimestamp); const initialOrderExpiryTimestamp = utils.initialOrderExpiryUnixTimestampSec(); const didUserSetExpiry = !initialOrderExpiryTimestamp.eq(props.orderExpiryTimestamp); @@ -42,13 +42,10 @@ export class ExpirationInput extends React.Component<ExpirationInputProps, Expir mode="landscape" autoOk={true} value={date} - onChange={this.onDateChanged.bind(this)} - shouldDisableDate={this.shouldDisableDate.bind(this)} + onChange={this._onDateChanged.bind(this)} + shouldDisableDate={this._shouldDisableDate.bind(this)} /> - <div - className="absolute" - style={{fontSize: 20, right: 40, top: 13, pointerEvents: 'none'}} - > + <div className="absolute" style={{ fontSize: 20, right: 40, top: 13, pointerEvents: 'none' }}> <i className="zmdi zmdi-calendar" /> </div> </div> @@ -58,29 +55,24 @@ export class ExpirationInput extends React.Component<ExpirationInputProps, Expir hintText="Time" autoOk={true} value={time} - onChange={this.onTimeChanged.bind(this)} + onChange={this._onTimeChanged.bind(this)} /> - <div - className="absolute" - style={{fontSize: 20, right: 9, top: 13, pointerEvents: 'none'}} - > + <div className="absolute" style={{ fontSize: 20, right: 9, top: 13, pointerEvents: 'none' }}> <i className="zmdi zmdi-time" /> </div> </div> - <div - onClick={this.clearDates.bind(this)} - className="col col-1 pt2" - style={{textAlign: 'right'}} - > - <i style={{fontSize: 16, cursor: 'pointer'}} className="zmdi zmdi-close" /> + <div onClick={this._clearDates.bind(this)} className="col col-1 pt2" style={{ textAlign: 'right' }}> + <i style={{ fontSize: 16, cursor: 'pointer' }} className="zmdi zmdi-close" /> </div> </div> ); } - private shouldDisableDate(date: Date): boolean { - return moment(date).startOf('day').isBefore(this.earliestPickableMoment); + private _shouldDisableDate(date: Date): boolean { + return moment(date) + .startOf('day') + .isBefore(this._earliestPickableMoment); } - private clearDates() { + private _clearDates() { this.setState({ dateMoment: undefined, timeMoment: undefined, @@ -88,7 +80,7 @@ export class ExpirationInput extends React.Component<ExpirationInputProps, Expir const defaultDateTime = utils.initialOrderExpiryUnixTimestampSec(); this.props.updateOrderExpiry(defaultDateTime); } - private onDateChanged(e: any, date: Date) { + private _onDateChanged(e: any, date: Date) { const dateMoment = moment(date); this.setState({ dateMoment, @@ -96,12 +88,12 @@ export class ExpirationInput extends React.Component<ExpirationInputProps, Expir const timestamp = utils.convertToUnixTimestampSeconds(dateMoment, this.state.timeMoment); this.props.updateOrderExpiry(timestamp); } - private onTimeChanged(e: any, time: Date) { + private _onTimeChanged(e: any, time: Date) { const timeMoment = moment(time); this.setState({ timeMoment, }); - const dateMoment = _.isUndefined(this.state.dateMoment) ? moment() : this.state.dateMoment; + const dateMoment = _.isUndefined(this.state.dateMoment) ? moment() : this.state.dateMoment; const timestamp = utils.convertToUnixTimestampSeconds(dateMoment, timeMoment); this.props.updateOrderExpiry(timestamp); } diff --git a/packages/website/ts/components/inputs/hash_input.tsx b/packages/website/ts/components/inputs/hash_input.tsx index 25e7b5009..5a3d34fe6 100644 --- a/packages/website/ts/components/inputs/hash_input.tsx +++ b/packages/website/ts/components/inputs/hash_input.tsx @@ -1,11 +1,11 @@ -import {Order, ZeroEx} from '0x.js'; +import { Order, ZeroEx } from '0x.js'; import * as _ from 'lodash'; import * as React from 'react'; import ReactTooltip = require('react-tooltip'); -import {Blockchain} from 'ts/blockchain'; -import {FakeTextField} from 'ts/components/ui/fake_text_field'; -import {HashData, Styles} from 'ts/types'; -import {constants} from 'ts/utils/constants'; +import { Blockchain } from 'ts/blockchain'; +import { FakeTextField } from 'ts/components/ui/fake_text_field'; +import { HashData, Styles } from 'ts/types'; +import { constants } from 'ts/utils/constants'; const styles: Styles = { textField: { @@ -27,15 +27,11 @@ interface HashInputState {} export class HashInput extends React.Component<HashInputProps, HashInputState> { public render() { - const msgHashHex = this.props.blockchainIsLoaded ? this.generateMessageHashHex() : ''; + const msgHashHex = this.props.blockchainIsLoaded ? this._generateMessageHashHex() : ''; return ( <div> <FakeTextField label={this.props.label}> - <div - style={styles.textField} - data-tip={true} - data-for="hashTooltip" - > + <div style={styles.textField} data-tip={true} data-for="hashTooltip"> {msgHashHex} </div> </FakeTextField> @@ -43,7 +39,7 @@ export class HashInput extends React.Component<HashInputProps, HashInputState> { </div> ); } - private generateMessageHashHex() { + private _generateMessageHashHex() { const exchangeContractAddress = this.props.blockchain.getExchangeContractAddressIfExists(); const hashData = this.props.hashData; const order: Order = { diff --git a/packages/website/ts/components/inputs/identicon_address_input.tsx b/packages/website/ts/components/inputs/identicon_address_input.tsx index 692a092d9..4cf9af64d 100644 --- a/packages/website/ts/components/inputs/identicon_address_input.tsx +++ b/packages/website/ts/components/inputs/identicon_address_input.tsx @@ -1,11 +1,9 @@ import * as _ from 'lodash'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; -import {Blockchain} from 'ts/blockchain'; -import {AddressInput} from 'ts/components/inputs/address_input'; -import {Identicon} from 'ts/components/ui/identicon'; -import {InputLabel} from 'ts/components/ui/input_label'; -import {RequiredLabel} from 'ts/components/ui/required_label'; +import { AddressInput } from 'ts/components/inputs/address_input'; +import { Identicon } from 'ts/components/ui/identicon'; +import { InputLabel } from 'ts/components/ui/input_label'; +import { RequiredLabel } from 'ts/components/ui/required_label'; interface IdenticonAddressInputProps { initialAddress: string; @@ -26,28 +24,27 @@ export class IdenticonAddressInput extends React.Component<IdenticonAddressInput }; } public render() { - const label = this.props.isRequired ? <RequiredLabel label={this.props.label} /> : - this.props.label; + const label = this.props.isRequired ? <RequiredLabel label={this.props.label} /> : this.props.label; return ( - <div className="relative" style={{width: '100%'}}> + <div className="relative" style={{ width: '100%' }}> <InputLabel text={label} /> <div className="flex"> - <div className="col col-1 pb1 pr1" style={{paddingTop: 13}}> + <div className="col col-1 pb1 pr1" style={{ paddingTop: 13 }}> <Identicon address={this.state.address} diameter={26} /> </div> - <div className="col col-11 pb1 pl1" style={{height: 65}}> + <div className="col col-11 pb1 pl1" style={{ height: 65 }}> <AddressInput hintText="e.g 0x75bE4F78AA3699B3A348c84bDB2a96c3Db..." shouldHideLabel={true} initialAddress={this.props.initialAddress} - updateAddress={this.updateAddress.bind(this)} + updateAddress={this._updateAddress.bind(this)} /> </div> </div> </div> ); } - private updateAddress(address?: string): void { + private _updateAddress(address?: string): void { this.setState({ address, }); diff --git a/packages/website/ts/components/inputs/token_amount_input.tsx b/packages/website/ts/components/inputs/token_amount_input.tsx index f39341a4f..63966d759 100644 --- a/packages/website/ts/components/inputs/token_amount_input.tsx +++ b/packages/website/ts/components/inputs/token_amount_input.tsx @@ -1,16 +1,16 @@ -import {ZeroEx} from '0x.js'; -import BigNumber from 'bignumber.js'; +import { ZeroEx } from '0x.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; -import {Link} from 'react-router-dom'; -import {BalanceBoundedInput} from 'ts/components/inputs/balance_bounded_input'; -import {InputErrMsg, Token, TokenState, ValidatedBigNumberCallback, WebsitePaths} from 'ts/types'; +import { Link } from 'react-router-dom'; +import { BalanceBoundedInput } from 'ts/components/inputs/balance_bounded_input'; +import { InputErrMsg, Token, TokenState, ValidatedBigNumberCallback, WebsitePaths } from 'ts/types'; +import { colors } from 'ts/utils/colors'; interface TokenAmountInputProps { - label: string; token: Token; tokenState: TokenState; + label?: string; amount?: BigNumber; shouldShowIncompleteErrs: boolean; shouldCheckBalance: boolean; @@ -19,51 +19,52 @@ interface TokenAmountInputProps { onVisitBalancesPageClick?: () => void; } -interface TokenAmountInputState {} +interface TokenAmountInputState {} export class TokenAmountInput extends React.Component<TokenAmountInputProps, TokenAmountInputState> { public render() { - const amount = this.props.amount ? - ZeroEx.toUnitAmount(this.props.amount, this.props.token.decimals) : - undefined; + const amount = this.props.amount + ? ZeroEx.toUnitAmount(this.props.amount, this.props.token.decimals) + : undefined; + const hasLabel = !_.isUndefined(this.props.label); return ( - <div className="flex overflow-hidden" style={{height: 84}}> + <div className="flex overflow-hidden" style={{ height: hasLabel ? 84 : 62 }}> <BalanceBoundedInput label={this.props.label} amount={amount} balance={ZeroEx.toUnitAmount(this.props.tokenState.balance, this.props.token.decimals)} - onChange={this.onChange.bind(this)} - validate={this.validate.bind(this)} + onChange={this._onChange.bind(this)} + validate={this._validate.bind(this)} shouldCheckBalance={this.props.shouldCheckBalance} shouldShowIncompleteErrs={this.props.shouldShowIncompleteErrs} onVisitBalancesPageClick={this.props.onVisitBalancesPageClick} /> - <div style={{paddingTop: 39}}> - {this.props.token.symbol} - </div> + <div style={{ paddingTop: hasLabel ? 39 : 14 }}>{this.props.token.symbol}</div> </div> ); } - private onChange(isValid: boolean, amount?: BigNumber) { + private _onChange(isValid: boolean, amount?: BigNumber) { let baseUnitAmount; if (!_.isUndefined(amount)) { baseUnitAmount = ZeroEx.toBaseUnitAmount(amount, this.props.token.decimals); } this.props.onChange(isValid, baseUnitAmount); } - private validate(amount: BigNumber): InputErrMsg { + private _validate(amount: BigNumber): InputErrMsg { if (this.props.shouldCheckAllowance && amount.gt(this.props.tokenState.allowance)) { return ( <span> Insufficient allowance.{' '} <Link to={`${WebsitePaths.Portal}/balances`} - style={{cursor: 'pointer', color: colors.grey900}} + style={{ cursor: 'pointer', color: colors.darkestGrey }} > - Set allowance + Set allowance </Link> </span> ); + } else { + return undefined; } } } diff --git a/packages/website/ts/components/inputs/token_input.tsx b/packages/website/ts/components/inputs/token_input.tsx index 8daa84650..5df19b28c 100644 --- a/packages/website/ts/components/inputs/token_input.tsx +++ b/packages/website/ts/components/inputs/token_input.tsx @@ -1,13 +1,13 @@ import * as _ from 'lodash'; import Paper from 'material-ui/Paper'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; -import {Blockchain} from 'ts/blockchain'; -import {AssetPicker} from 'ts/components/generate_order/asset_picker'; -import {InputLabel} from 'ts/components/ui/input_label'; -import {TokenIcon} from 'ts/components/ui/token_icon'; -import {Dispatcher} from 'ts/redux/dispatcher'; -import {AssetToken, BlockchainErrs, Side, Token, TokenByAddress, TokenState} from 'ts/types'; +import { Blockchain } from 'ts/blockchain'; +import { AssetPicker } from 'ts/components/generate_order/asset_picker'; +import { InputLabel } from 'ts/components/ui/input_label'; +import { TokenIcon } from 'ts/components/ui/token_icon'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { AssetToken, BlockchainErrs, Side, Token, TokenByAddress } from 'ts/types'; +import { colors } from 'ts/utils/colors'; const TOKEN_ICON_DIMENSION = 80; @@ -51,18 +51,15 @@ export class TokenInput extends React.Component<TokenInputProps, TokenInputState </div> <Paper zDepth={1} - style={{cursor: 'pointer'}} - onMouseEnter={this.onToggleHover.bind(this, true)} - onMouseLeave={this.onToggleHover.bind(this, false)} - onClick={this.onAssetClicked.bind(this)} + style={{ cursor: 'pointer' }} + onMouseEnter={this._onToggleHover.bind(this, true)} + onMouseLeave={this._onToggleHover.bind(this, false)} + onClick={this._onAssetClicked.bind(this)} > - <div - className="mx-auto pt2" - style={{width: TOKEN_ICON_DIMENSION, ...iconStyles}} - > + <div className="mx-auto pt2" style={{ width: TOKEN_ICON_DIMENSION, ...iconStyles }}> <TokenIcon token={token} diameter={TOKEN_ICON_DIMENSION} /> </div> - <div className="py1 center" style={{color: colors.grey500}}> + <div className="py1 center" style={{ color: colors.grey }}> {token.name} </div> </Paper> @@ -73,13 +70,13 @@ export class TokenInput extends React.Component<TokenInputProps, TokenInputState dispatcher={this.props.dispatcher} isOpen={this.state.isPickerOpen} currentTokenAddress={this.props.assetToken.address} - onTokenChosen={this.onTokenChosen.bind(this)} + onTokenChosen={this._onTokenChosen.bind(this)} tokenByAddress={this.props.tokenByAddress} /> </div> ); } - private onTokenChosen(tokenAddress: string) { + private _onTokenChosen(tokenAddress: string) { const assetToken: AssetToken = { address: tokenAddress, amount: this.props.assetToken.amount, @@ -89,13 +86,13 @@ export class TokenInput extends React.Component<TokenInputProps, TokenInputState isPickerOpen: false, }); } - private onToggleHover(isHoveringIcon: boolean) { + private _onToggleHover(isHoveringIcon: boolean) { this.setState({ isHoveringIcon, }); } - private onAssetClicked() { - if (this.props.blockchainErr !== '') { + private _onAssetClicked() { + if (this.props.blockchainErr !== BlockchainErrs.NoError) { this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); return; } diff --git a/packages/website/ts/components/order_json.tsx b/packages/website/ts/components/order_json.tsx index 073abe419..1b6b32a04 100644 --- a/packages/website/ts/components/order_json.tsx +++ b/packages/website/ts/components/order_json.tsx @@ -1,15 +1,14 @@ -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import Paper from 'material-ui/Paper'; -import {colors} from 'material-ui/styles'; import TextField from 'material-ui/TextField'; import * as React from 'react'; -import {CopyIcon} from 'ts/components/ui/copy_icon'; -import {Order, SideToAssetToken, SignatureData, TokenByAddress, WebsitePaths} from 'ts/types'; -import {configs} from 'ts/utils/configs'; -import {constants} from 'ts/utils/constants'; -import {errorReporter} from 'ts/utils/error_reporter'; -import {utils} from 'ts/utils/utils'; +import { CopyIcon } from 'ts/components/ui/copy_icon'; +import { SideToAssetToken, SignatureData, TokenByAddress, WebsitePaths } from 'ts/types'; +import { configs } from 'ts/utils/configs'; +import { constants } from 'ts/utils/constants'; +import { errorReporter } from 'ts/utils/error_reporter'; +import { utils } from 'ts/utils/utils'; interface OrderJSONProps { exchangeContractIfExists: string; @@ -37,73 +36,79 @@ export class OrderJSON extends React.Component<OrderJSONProps, OrderJSONState> { shareLink: '', }; // tslint:disable-next-line:no-floating-promises - this.setShareLinkAsync(); + this._setShareLinkAsync(); } public render() { - const order = utils.generateOrder(this.props.networkId, this.props.exchangeContractIfExists, - this.props.sideToAssetToken, this.props.orderExpiryTimestamp, - this.props.orderTakerAddress, this.props.orderMakerAddress, - this.props.orderMakerFee, this.props.orderTakerFee, - this.props.orderFeeRecipient, this.props.orderSignatureData, - this.props.tokenByAddress, this.props.orderSalt); + const order = utils.generateOrder( + this.props.networkId, + this.props.exchangeContractIfExists, + this.props.sideToAssetToken, + this.props.orderExpiryTimestamp, + this.props.orderTakerAddress, + this.props.orderMakerAddress, + this.props.orderMakerFee, + this.props.orderTakerFee, + this.props.orderFeeRecipient, + this.props.orderSignatureData, + this.props.tokenByAddress, + this.props.orderSalt, + ); const orderJSON = JSON.stringify(order); return ( <div> <div className="pb2"> - You have successfully generated and cryptographically signed an order! The{' '} - following JSON contains the order parameters and cryptographic signature that{' '} - your counterparty will need to execute a trade with you. + You have successfully generated and cryptographically signed an order! The following JSON contains + the order parameters and cryptographic signature that your counterparty will need to execute a trade + with you. </div> <div className="pb2 flex"> - <div - className="inline-block pl1" - style={{top: 1}} - > + <div className="inline-block pl1" style={{ top: 1 }}> <CopyIcon data={orderJSON} callToAction="Copy" /> </div> </div> <Paper className="center overflow-hidden"> <TextField id="orderJSON" - style={{width: 710}} + style={{ width: 710 }} value={JSON.stringify(order, null, '\t')} multiLine={true} rows={2} rowsMax={8} - underlineStyle={{display: 'none'}} + underlineStyle={{ display: 'none' }} /> </Paper> <div className="pt3 pb2 center"> + <div>Share your signed order!</div> <div> - Share your signed order! - </div> - <div> - <div className="mx-auto overflow-hidden" style={{width: 152}}> - <TextField - id={`${this.state.shareLink}-bitly`} - value={this.state.shareLink} - /> + <div className="mx-auto overflow-hidden" style={{ width: 152 }}> + <TextField id={`${this.state.shareLink}-bitly`} value={this.state.shareLink} /> </div> </div> - <div className="mx-auto pt1 flex" style={{width: 91}}> + <div className="mx-auto pt1 flex" style={{ width: 91 }}> <div> <i - style={{cursor: 'pointer', fontSize: 29}} - onClick={this.shareViaFacebook.bind(this)} + style={{ cursor: 'pointer', fontSize: 29 }} + onClick={this._shareViaFacebook.bind(this)} className="zmdi zmdi-facebook-box" /> </div> - <div className="pl1" style={{position: 'relative', width: 28}}> + <div className="pl1" style={{ position: 'relative', width: 28 }}> <i - style={{cursor: 'pointer', fontSize: 32, position: 'absolute', top: -2, left: 8}} - onClick={this.shareViaEmailAsync.bind(this)} + style={{ + cursor: 'pointer', + fontSize: 32, + position: 'absolute', + top: -2, + left: 8, + }} + onClick={this._shareViaEmailAsync.bind(this)} className="zmdi zmdi-email" /> </div> <div className="pl1"> <i - style={{cursor: 'pointer', fontSize: 29}} - onClick={this.shareViaTwitterAsync.bind(this)} + style={{ cursor: 'pointer', fontSize: 29 }} + onClick={this._shareViaTwitterAsync.bind(this)} className="zmdi zmdi-twitter-box" /> </div> @@ -112,35 +117,38 @@ export class OrderJSON extends React.Component<OrderJSONProps, OrderJSONState> { </div> ); } - private async shareViaTwitterAsync() { + private async _shareViaTwitterAsync() { const tweetText = encodeURIComponent(`Fill my order using the 0x protocol: ${this.state.shareLink}`); window.open(`https://twitter.com/intent/tweet?text=${tweetText}`, 'Share your order', 'width=500,height=400'); } - private async shareViaFacebook() { - (window as any).FB.ui({ - display: 'popup', - href: this.state.shareLink, - method: 'share', - }, _.noop); + private async _shareViaFacebook() { + (window as any).FB.ui( + { + display: 'popup', + href: this.state.shareLink, + method: 'share', + }, + _.noop, + ); } - private async shareViaEmailAsync() { - const encodedSubject = encodeURIComponent('Let\'s trade using the 0x protocol'); + private async _shareViaEmailAsync() { + const encodedSubject = encodeURIComponent("Let's trade using the 0x protocol"); const encodedBody = encodeURIComponent(`I generated an order with the 0x protocol. You can see and fill it here: ${this.state.shareLink}`); const mailToLink = `mailto:mail@example.org?subject=${encodedSubject}&body=${encodedBody}`; window.open(mailToLink, '_blank'); } - private async setShareLinkAsync() { - const shareLink = await this.generateShareLinkAsync(); + private async _setShareLinkAsync() { + const shareLink = await this._generateShareLinkAsync(); this.setState({ shareLink, }); } - private async generateShareLinkAsync(): Promise<string> { - const longUrl = encodeURIComponent(this.getOrderUrl()); - const bitlyRequestUrl = constants.BITLY_ENDPOINT + '/v3/shorten?' + - 'access_token=' + constants.BITLY_ACCESS_TOKEN + - '&longUrl=' + longUrl; + private async _generateShareLinkAsync(): Promise<string> { + const longUrl = encodeURIComponent(this._getOrderUrl()); + const bitlyRequestUrl = `${constants.URL_BITLY_API}/v3/shorten?access_token=${ + configs.BITLY_ACCESS_TOKEN + }&longUrl=${longUrl}`; const response = await fetch(bitlyRequestUrl); const responseBody = await response.text(); const bodyObj = JSON.parse(responseBody); @@ -150,14 +158,23 @@ You can see and fill it here: ${this.state.shareLink}`); await errorReporter.reportAsync(new Error(`Bitly returned non-200: ${JSON.stringify(response)}`)); return ''; } - return (bodyObj).data.url; + return bodyObj.data.url; } - private getOrderUrl() { - const order = utils.generateOrder(this.props.networkId, this.props.exchangeContractIfExists, - this.props.sideToAssetToken, this.props.orderExpiryTimestamp, this.props.orderTakerAddress, - this.props.orderMakerAddress, this.props.orderMakerFee, this.props.orderTakerFee, - this.props.orderFeeRecipient, this.props.orderSignatureData, this.props.tokenByAddress, - this.props.orderSalt); + private _getOrderUrl() { + const order = utils.generateOrder( + this.props.networkId, + this.props.exchangeContractIfExists, + this.props.sideToAssetToken, + this.props.orderExpiryTimestamp, + this.props.orderTakerAddress, + this.props.orderMakerAddress, + this.props.orderMakerFee, + this.props.orderTakerFee, + this.props.orderFeeRecipient, + this.props.orderSignatureData, + this.props.tokenByAddress, + this.props.orderSalt, + ); const orderJSONString = JSON.stringify(order); const orderUrl = `${configs.BASE_URL}${WebsitePaths.Portal}/fill?order=${orderJSONString}`; return orderUrl; diff --git a/packages/website/ts/components/portal.tsx b/packages/website/ts/components/portal.tsx index 62a5d2eac..e2e28e8b6 100644 --- a/packages/website/ts/components/portal.tsx +++ b/packages/website/ts/components/portal.tsx @@ -1,44 +1,41 @@ -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import Paper from 'material-ui/Paper'; -import RaisedButton from 'material-ui/RaisedButton'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; import * as DocumentTitle from 'react-document-title'; -import {Route, Switch} from 'react-router-dom'; -import {Blockchain} from 'ts/blockchain'; -import {BlockchainErrDialog} from 'ts/components/dialogs/blockchain_err_dialog'; -import {PortalDisclaimerDialog} from 'ts/components/dialogs/portal_disclaimer_dialog'; -import {FillOrder} from 'ts/components/fill_order'; -import {Footer} from 'ts/components/footer'; -import {PortalMenu} from 'ts/components/portal_menu'; -import {TokenBalances} from 'ts/components/token_balances'; -import {TopBar} from 'ts/components/top_bar'; -import {TradeHistory} from 'ts/components/trade_history/trade_history'; -import {FlashMessage} from 'ts/components/ui/flash_message'; -import {Loading} from 'ts/components/ui/loading'; -import {GenerateOrderForm} from 'ts/containers/generate_order_form'; -import {localStorage} from 'ts/local_storage/local_storage'; -import {Dispatcher} from 'ts/redux/dispatcher'; -import {State} from 'ts/redux/reducer'; -import {orderSchema} from 'ts/schemas/order_schema'; -import {SchemaValidator} from 'ts/schemas/validator'; +import { Route, Switch } from 'react-router-dom'; +import { Blockchain } from 'ts/blockchain'; +import { BlockchainErrDialog } from 'ts/components/dialogs/blockchain_err_dialog'; +import { PortalDisclaimerDialog } from 'ts/components/dialogs/portal_disclaimer_dialog'; +import { WrappedEthSectionNoticeDialog } from 'ts/components/dialogs/wrapped_eth_section_notice_dialog'; +import { EthWrappers } from 'ts/components/eth_wrappers'; +import { FillOrder } from 'ts/components/fill_order'; +import { Footer } from 'ts/components/footer'; +import { PortalMenu } from 'ts/components/portal_menu'; +import { TokenBalances } from 'ts/components/token_balances'; +import { TopBar } from 'ts/components/top_bar'; +import { TradeHistory } from 'ts/components/trade_history/trade_history'; +import { FlashMessage } from 'ts/components/ui/flash_message'; +import { Loading } from 'ts/components/ui/loading'; +import { GenerateOrderForm } from 'ts/containers/generate_order_form'; +import { localStorage } from 'ts/local_storage/local_storage'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { orderSchema } from 'ts/schemas/order_schema'; +import { SchemaValidator } from 'ts/schemas/validator'; import { BlockchainErrs, - Fill, HashData, Order, ScreenWidths, - Side, - Styles, Token, TokenByAddress, TokenStateByAddress, WebsitePaths, } from 'ts/types'; -import {configs} from 'ts/utils/configs'; -import {constants} from 'ts/utils/constants'; -import {utils} from 'ts/utils/utils'; +import { colors } from 'ts/utils/colors'; +import { configs } from 'ts/utils/configs'; +import { constants } from 'ts/utils/constants'; +import { utils } from 'ts/utils/utils'; const THROTTLE_TIMEOUT = 100; @@ -60,69 +57,57 @@ export interface PortalAllProps { shouldBlockchainErrDialogBeOpen: boolean; userSuppliedOrderCache: Order; location: Location; - flashMessage?: string|React.ReactNode; + flashMessage?: string | React.ReactNode; } interface PortalAllState { prevNetworkId: number; prevNodeVersion: string; prevUserAddress: string; - hasAcceptedDisclaimer: boolean; + prevPathname: string; + isDisclaimerDialogOpen: boolean; + isWethNoticeDialogOpen: boolean; } -const styles: Styles = { - button: { - color: 'white', - }, - headline: { - fontSize: 20, - fontWeight: 400, - marginBottom: 12, - paddingTop: 16, - }, - inkBar: { - background: colors.amber600, - }, - menuItem: { - padding: '0px 16px 0px 48px', - }, - tabItemContainer: { - background: colors.blueGrey500, - borderRadius: '4px 4px 0 0', - }, -}; - export class Portal extends React.Component<PortalAllProps, PortalAllState> { - private blockchain: Blockchain; - private sharedOrderIfExists: Order; - private throttledScreenWidthUpdate: () => void; + private _blockchain: Blockchain; + private _sharedOrderIfExists: Order; + private _throttledScreenWidthUpdate: () => void; + public static hasAlreadyDismissedWethNotice() { + const didDismissWethNotice = localStorage.getItemIfExists(constants.LOCAL_STORAGE_KEY_DISMISS_WETH_NOTICE); + const hasAlreadyDismissedWethNotice = !_.isUndefined(didDismissWethNotice) && !_.isEmpty(didDismissWethNotice); + return hasAlreadyDismissedWethNotice; + } constructor(props: PortalAllProps) { super(props); - this.sharedOrderIfExists = this.getSharedOrderIfExists(); - this.throttledScreenWidthUpdate = _.throttle(this.updateScreenWidth.bind(this), THROTTLE_TIMEOUT); + this._sharedOrderIfExists = this._getSharedOrderIfExists(); + this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT); + + const isViewingBalances = _.includes(props.location.pathname, `${WebsitePaths.Portal}/balances`); + const hasAlreadyDismissedWethNotice = Portal.hasAlreadyDismissedWethNotice(); + + const didAcceptPortalDisclaimer = localStorage.getItemIfExists(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER); + const hasAcceptedDisclaimer = + !_.isUndefined(didAcceptPortalDisclaimer) && !_.isEmpty(didAcceptPortalDisclaimer); this.state = { prevNetworkId: this.props.networkId, prevNodeVersion: this.props.nodeVersion, prevUserAddress: this.props.userAddress, - hasAcceptedDisclaimer: false, + prevPathname: this.props.location.pathname, + isDisclaimerDialogOpen: !hasAcceptedDisclaimer, + isWethNoticeDialogOpen: !hasAlreadyDismissedWethNotice && isViewingBalances, }; } public componentDidMount() { - window.addEventListener('resize', this.throttledScreenWidthUpdate); + window.addEventListener('resize', this._throttledScreenWidthUpdate); window.scrollTo(0, 0); } public componentWillMount() { - this.blockchain = new Blockchain(this.props.dispatcher); - const didAcceptPortalDisclaimer = localStorage.getItemIfExists(constants.ACCEPT_DISCLAIMER_LOCAL_STORAGE_KEY); - const hasAcceptedDisclaimer = !_.isUndefined(didAcceptPortalDisclaimer) && - !_.isEmpty(didAcceptPortalDisclaimer); - this.setState({ - hasAcceptedDisclaimer, - }); + this._blockchain = new Blockchain(this.props.dispatcher); } public componentWillUnmount() { - this.blockchain.destroy(); - window.removeEventListener('resize', this.throttledScreenWidthUpdate); + this._blockchain.destroy(); + window.removeEventListener('resize', this._throttledScreenWidthUpdate); // We re-set the entire redux state when the portal is unmounted so that when it is re-rendered // the initialization process always occurs from the same base state. This helps avoid // initialization inconsistencies (i.e While the portal was unrendered, the user might have @@ -132,19 +117,18 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> { public componentWillReceiveProps(nextProps: PortalAllProps) { if (nextProps.networkId !== this.state.prevNetworkId) { // tslint:disable-next-line:no-floating-promises - this.blockchain.networkIdUpdatedFireAndForgetAsync(nextProps.networkId); + this._blockchain.networkIdUpdatedFireAndForgetAsync(nextProps.networkId); this.setState({ prevNetworkId: nextProps.networkId, }); } if (nextProps.userAddress !== this.state.prevUserAddress) { // tslint:disable-next-line:no-floating-promises - this.blockchain.userAddressUpdatedFireAndForgetAsync(nextProps.userAddress); - if (!_.isEmpty(nextProps.userAddress) && - nextProps.blockchainIsLoaded) { + this._blockchain.userAddressUpdatedFireAndForgetAsync(nextProps.userAddress); + if (!_.isEmpty(nextProps.userAddress) && nextProps.blockchainIsLoaded) { const tokens = _.values(nextProps.tokenByAddress); // tslint:disable-next-line:no-floating-promises - this.updateBalanceAndAllowanceWithLoadingScreenAsync(tokens); + this._updateBalanceAndAllowanceWithLoadingScreenAsync(tokens); } this.setState({ prevUserAddress: nextProps.userAddress, @@ -152,105 +136,128 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> { } if (nextProps.nodeVersion !== this.state.prevNodeVersion) { // tslint:disable-next-line:no-floating-promises - this.blockchain.nodeVersionUpdatedFireAndForgetAsync(nextProps.nodeVersion); + this._blockchain.nodeVersionUpdatedFireAndForgetAsync(nextProps.nodeVersion); + } + if (nextProps.location.pathname !== this.state.prevPathname) { + const isViewingBalances = _.includes(nextProps.location.pathname, `${WebsitePaths.Portal}/balances`); + const hasAlreadyDismissedWethNotice = Portal.hasAlreadyDismissedWethNotice(); + this.setState({ + prevPathname: nextProps.location.pathname, + isWethNoticeDialogOpen: !hasAlreadyDismissedWethNotice && isViewingBalances, + }); } } public render() { - const updateShouldBlockchainErrDialogBeOpen = this.props.dispatcher - .updateShouldBlockchainErrDialogBeOpen.bind(this.props.dispatcher); + const updateShouldBlockchainErrDialogBeOpen = this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen.bind( + this.props.dispatcher, + ); const portalStyle: React.CSSProperties = { minHeight: '100vh', display: 'flex', flexDirection: 'column', justifyContent: 'space-between', }; + const portalMenuContainerStyle: React.CSSProperties = { + overflow: 'hidden', + backgroundColor: colors.darkestGrey, + color: colors.white, + }; return ( <div style={portalStyle}> - <DocumentTitle title="0x Portal DApp"/> + <DocumentTitle title="0x Portal DApp" /> <TopBar userAddress={this.props.userAddress} blockchainIsLoaded={this.props.blockchainIsLoaded} location={this.props.location} /> - <div id="portal" className="mx-auto max-width-4 pt4" style={{width: '100%'}}> + <div id="portal" className="mx-auto max-width-4" style={{ width: '100%' }}> <Paper className="mb3 mt2"> - {!configs.isMainnetEnabled && this.props.networkId === constants.MAINNET_NETWORK_ID ? + {!configs.IS_MAINNET_ENABLED && this.props.networkId === constants.NETWORK_ID_MAINNET ? ( <div className="p3 center"> <div className="h2 py2">Mainnet unavailable</div> <div className="mx-auto pb2 pt2"> - <img - src="/images/zrx_token.png" - style={{width: 150}} - /> + <img src="/images/zrx_token.png" style={{ width: 150 }} /> </div> <div> 0x portal is currently unavailable on the Ethereum mainnet. - <div> - To try it out, switch to the Kovan test network - (networkId: 42). - </div> - <div className="py2"> - Check back soon! - </div> + <div>To try it out, switch to the Kovan test network (networkId: 42).</div> + <div className="py2">Check back soon!</div> </div> - </div> : + </div> + ) : ( <div className="mx-auto flex"> - <div - className="col col-2 pr2 pt1 sm-hide xs-hide" - style={{overflow: 'hidden', backgroundColor: 'rgb(39, 39, 39)', color: 'white'}} - > - <PortalMenu menuItemStyle={{color: 'white'}} /> + <div className="col col-2 pr2 pt1 sm-hide xs-hide" style={portalMenuContainerStyle}> + <PortalMenu menuItemStyle={{ color: colors.white }} /> </div> <div className="col col-12 lg-col-10 md-col-10 sm-col sm-col-12"> - <div className="py2" style={{backgroundColor: colors.grey50}}> - {this.props.blockchainIsLoaded ? + <div className="py2" style={{ backgroundColor: colors.grey50 }}> + {this.props.blockchainIsLoaded ? ( <Switch> <Route + path={`${WebsitePaths.Portal}/weth`} + render={this._renderEthWrapper.bind(this)} + /> + <Route path={`${WebsitePaths.Portal}/fill`} - render={this.renderFillOrder.bind(this)} + render={this._renderFillOrder.bind(this)} /> <Route path={`${WebsitePaths.Portal}/balances`} - render={this.renderTokenBalances.bind(this)} + render={this._renderTokenBalances.bind(this)} /> <Route path={`${WebsitePaths.Portal}/trades`} - component={this.renderTradeHistory.bind(this)} + component={this._renderTradeHistory.bind(this)} /> <Route path={`${WebsitePaths.Home}`} - render={this.renderGenerateOrderForm.bind(this)} + render={this._renderGenerateOrderForm.bind(this)} /> - </Switch> : + </Switch> + ) : ( <Loading /> - } + )} </div> </div> </div> - } + )} </Paper> <BlockchainErrDialog - blockchain={this.blockchain} + blockchain={this._blockchain} blockchainErr={this.props.blockchainErr} isOpen={this.props.shouldBlockchainErrDialogBeOpen} userAddress={this.props.userAddress} toggleDialogFn={updateShouldBlockchainErrDialogBeOpen} networkId={this.props.networkId} /> - <PortalDisclaimerDialog - isOpen={!this.state.hasAcceptedDisclaimer} - onToggleDialog={this.onPortalDisclaimerAccepted.bind(this)} + <WrappedEthSectionNoticeDialog + isOpen={this.state.isWethNoticeDialogOpen} + onToggleDialog={this._onWethNoticeAccepted.bind(this)} /> - <FlashMessage - dispatcher={this.props.dispatcher} - flashMessage={this.props.flashMessage} + <PortalDisclaimerDialog + isOpen={this.state.isDisclaimerDialogOpen} + onToggleDialog={this._onPortalDisclaimerAccepted.bind(this)} /> + <FlashMessage dispatcher={this.props.dispatcher} flashMessage={this.props.flashMessage} /> </div> - <Footer location={this.props.location} /> + <Footer /> </div> ); } - private renderTradeHistory() { + private _renderEthWrapper() { + return ( + <EthWrappers + networkId={this.props.networkId} + blockchain={this._blockchain} + dispatcher={this.props.dispatcher} + tokenByAddress={this.props.tokenByAddress} + tokenStateByAddress={this.props.tokenStateByAddress} + userAddress={this.props.userAddress} + userEtherBalance={this.props.userEtherBalance} + /> + ); + } + private _renderTradeHistory() { return ( <TradeHistory tokenByAddress={this.props.tokenByAddress} @@ -259,10 +266,10 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> { /> ); } - private renderTokenBalances() { + private _renderTokenBalances() { return ( <TokenBalances - blockchain={this.blockchain} + blockchain={this._blockchain} blockchainErr={this.props.blockchainErr} blockchainIsLoaded={this.props.blockchainIsLoaded} dispatcher={this.props.dispatcher} @@ -275,16 +282,16 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> { /> ); } - private renderFillOrder(match: any, location: Location, history: History) { - const initialFillOrder = !_.isUndefined(this.props.userSuppliedOrderCache) ? - this.props.userSuppliedOrderCache : - this.sharedOrderIfExists; + private _renderFillOrder(match: any, location: Location, history: History) { + const initialFillOrder = !_.isUndefined(this.props.userSuppliedOrderCache) + ? this.props.userSuppliedOrderCache + : this._sharedOrderIfExists; return ( <FillOrder - blockchain={this.blockchain} + blockchain={this._blockchain} blockchainErr={this.props.blockchainErr} initialOrder={initialFillOrder} - isOrderInUrl={!_.isUndefined(this.sharedOrderIfExists)} + isOrderInUrl={!_.isUndefined(this._sharedOrderIfExists)} orderFillAmount={this.props.orderFillAmount} networkId={this.props.networkId} userAddress={this.props.userAddress} @@ -294,25 +301,31 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> { /> ); } - private renderGenerateOrderForm(match: any, location: Location, history: History) { + private _renderGenerateOrderForm(match: any, location: Location, history: History) { return ( <GenerateOrderForm - blockchain={this.blockchain} + blockchain={this._blockchain} hashData={this.props.hashData} dispatcher={this.props.dispatcher} /> ); } - private onPortalDisclaimerAccepted() { - localStorage.setItem(constants.ACCEPT_DISCLAIMER_LOCAL_STORAGE_KEY, 'set'); + private _onPortalDisclaimerAccepted() { + localStorage.setItem(constants.LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER, 'set'); + this.setState({ + isDisclaimerDialogOpen: false, + }); + } + private _onWethNoticeAccepted() { + localStorage.setItem(constants.LOCAL_STORAGE_KEY_DISMISS_WETH_NOTICE, 'set'); this.setState({ - hasAcceptedDisclaimer: true, + isWethNoticeDialogOpen: false, }); } - private getSharedOrderIfExists(): Order { + private _getSharedOrderIfExists(): Order | undefined { const queryString = window.location.search; if (queryString.length === 0) { - return; + return undefined; } const queryParams = queryString.substring(1).split('&'); const orderQueryParam = _.find(queryParams, queryParam => { @@ -320,11 +333,11 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> { return queryPair[0] === 'order'; }); if (_.isUndefined(orderQueryParam)) { - return; + return undefined; } const orderPair = orderQueryParam.split('='); if (orderPair.length !== 2) { - return; + return undefined; } const validator = new SchemaValidator(); @@ -332,17 +345,17 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> { const validationResult = validator.validate(order, orderSchema); if (validationResult.errors.length > 0) { utils.consoleLog(`Invalid shared order: ${validationResult.errors}`); - return; + return undefined; } return order; } - private updateScreenWidth() { + private _updateScreenWidth() { const newScreenWidth = utils.getScreenWidth(); this.props.dispatcher.updateScreenWidth(newScreenWidth); } - private async updateBalanceAndAllowanceWithLoadingScreenAsync(tokens: Token[]) { + private async _updateBalanceAndAllowanceWithLoadingScreenAsync(tokens: Token[]) { this.props.dispatcher.updateBlockchainIsLoaded(false); - await this.blockchain.updateTokenBalancesAndAllowancesAsync(tokens); + await this._blockchain.updateTokenBalancesAndAllowancesAsync(tokens); this.props.dispatcher.updateBlockchainIsLoaded(true); } } diff --git a/packages/website/ts/components/portal_menu.tsx b/packages/website/ts/components/portal_menu.tsx index 869df3e71..a2f9340c8 100644 --- a/packages/website/ts/components/portal_menu.tsx +++ b/packages/website/ts/components/portal_menu.tsx @@ -1,8 +1,7 @@ import * as _ from 'lodash'; import * as React from 'react'; -import {Link} from 'react-router-dom'; -import {MenuItem} from 'ts/components/ui/menu_item'; -import {WebsitePaths} from 'ts/types'; +import { MenuItem } from 'ts/components/ui/menu_item'; +import { WebsitePaths } from 'ts/types'; export interface PortalMenuProps { menuItemStyle: React.CSSProperties; @@ -24,7 +23,7 @@ export class PortalMenu extends React.Component<PortalMenuProps, PortalMenuState to={`${WebsitePaths.Portal}`} onClick={this.props.onClick.bind(this)} > - {this.renderMenuItemWithIcon('Generate order', 'zmdi-arrow-right-top')} + {this._renderMenuItemWithIcon('Generate order', 'zmdi-arrow-right-top')} </MenuItem> <MenuItem style={this.props.menuItemStyle} @@ -32,7 +31,7 @@ export class PortalMenu extends React.Component<PortalMenuProps, PortalMenuState to={`${WebsitePaths.Portal}/fill`} onClick={this.props.onClick.bind(this)} > - {this.renderMenuItemWithIcon('Fill order', 'zmdi-arrow-left-bottom')} + {this._renderMenuItemWithIcon('Fill order', 'zmdi-arrow-left-bottom')} </MenuItem> <MenuItem style={this.props.menuItemStyle} @@ -40,7 +39,7 @@ export class PortalMenu extends React.Component<PortalMenuProps, PortalMenuState to={`${WebsitePaths.Portal}/balances`} onClick={this.props.onClick.bind(this)} > - {this.renderMenuItemWithIcon('Balances', 'zmdi-balance-wallet')} + {this._renderMenuItemWithIcon('Balances', 'zmdi-balance-wallet')} </MenuItem> <MenuItem style={this.props.menuItemStyle} @@ -48,20 +47,26 @@ export class PortalMenu extends React.Component<PortalMenuProps, PortalMenuState to={`${WebsitePaths.Portal}/trades`} onClick={this.props.onClick.bind(this)} > - {this.renderMenuItemWithIcon('Trade history', 'zmdi-format-list-bulleted')} + {this._renderMenuItemWithIcon('Trade history', 'zmdi-format-list-bulleted')} + </MenuItem> + <MenuItem + style={this.props.menuItemStyle} + className="py2" + to={`${WebsitePaths.Portal}/weth`} + onClick={this.props.onClick.bind(this)} + > + {this._renderMenuItemWithIcon('Wrap ETH', 'zmdi-circle-o')} </MenuItem> </div> ); } - private renderMenuItemWithIcon(title: string, iconName: string) { + private _renderMenuItemWithIcon(title: string, iconName: string) { return ( - <div className="flex" style={{fontWeight: 100}}> + <div className="flex" style={{ fontWeight: 100 }}> <div className="pr1 pl2"> - <i style={{fontSize: 20}} className={`zmdi ${iconName}`} /> - </div> - <div className="pl1"> - {title} + <i style={{ fontSize: 20 }} className={`zmdi ${iconName}`} /> </div> + <div className="pl1">{title}</div> </div> ); } diff --git a/packages/website/ts/components/send_button.tsx b/packages/website/ts/components/send_button.tsx index da8dd2a9b..f94ec346a 100644 --- a/packages/website/ts/components/send_button.tsx +++ b/packages/website/ts/components/send_button.tsx @@ -1,15 +1,13 @@ -import {ZeroEx} from '0x.js'; -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import RaisedButton from 'material-ui/RaisedButton'; import * as React from 'react'; -import {Blockchain} from 'ts/blockchain'; -import {SendDialog} from 'ts/components/dialogs/send_dialog'; -import {Dispatcher} from 'ts/redux/dispatcher'; -import {BlockchainCallErrs, Token, TokenState} from 'ts/types'; -import {constants} from 'ts/utils/constants'; -import {errorReporter} from 'ts/utils/error_reporter'; -import {utils} from 'ts/utils/utils'; +import { Blockchain } from 'ts/blockchain'; +import { SendDialog } from 'ts/components/dialogs/send_dialog'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { BlockchainCallErrs, Token, TokenState } from 'ts/types'; +import { errorReporter } from 'ts/utils/error_reporter'; +import { utils } from 'ts/utils/utils'; interface SendButtonProps { token: Token; @@ -33,36 +31,36 @@ export class SendButton extends React.Component<SendButtonProps, SendButtonState }; } public render() { - const labelStyle = this.state.isSending ? {fontSize: 10} : {}; + const labelStyle = this.state.isSending ? { fontSize: 10 } : {}; return ( <div> <RaisedButton - style={{width: '100%'}} + style={{ width: '100%' }} labelStyle={labelStyle} disabled={this.state.isSending} label={this.state.isSending ? 'Sending...' : 'Send'} - onClick={this.toggleSendDialog.bind(this)} + onClick={this._toggleSendDialog.bind(this)} /> <SendDialog isOpen={this.state.isSendDialogVisible} - onComplete={this.onSendAmountSelectedAsync.bind(this)} - onCancelled={this.toggleSendDialog.bind(this)} + onComplete={this._onSendAmountSelectedAsync.bind(this)} + onCancelled={this._toggleSendDialog.bind(this)} token={this.props.token} tokenState={this.props.tokenState} /> </div> ); } - private toggleSendDialog() { + private _toggleSendDialog() { this.setState({ isSendDialogVisible: !this.state.isSendDialogVisible, }); } - private async onSendAmountSelectedAsync(recipient: string, value: BigNumber) { + private async _onSendAmountSelectedAsync(recipient: string, value: BigNumber) { this.setState({ isSending: true, }); - this.toggleSendDialog(); + this._toggleSendDialog(); const token = this.props.token; const tokenState = this.props.tokenState; let balance = tokenState.balance; @@ -72,14 +70,14 @@ export class SendButton extends React.Component<SendButtonProps, SendButtonState this.props.dispatcher.replaceTokenBalanceByAddress(token.address, balance); } catch (err) { const errMsg = `${err}`; - if (_.includes(errMsg, BlockchainCallErrs.USER_HAS_NO_ASSOCIATED_ADDRESSES)) { + if (_.includes(errMsg, BlockchainCallErrs.UserHasNoAssociatedAddresses)) { this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); return; } else if (!_.includes(errMsg, 'User denied transaction')) { utils.consoleLog(`Unexpected error encountered: ${err}`); utils.consoleLog(err.stack); - await errorReporter.reportAsync(err); this.props.onError(); + await errorReporter.reportAsync(err); } } this.setState({ diff --git a/packages/website/ts/components/token_balances.tsx b/packages/website/ts/components/token_balances.tsx index ae5ef9222..2cef413c7 100644 --- a/packages/website/ts/components/token_balances.tsx +++ b/packages/website/ts/components/token_balances.tsx @@ -1,5 +1,5 @@ -import {ZeroEx} from '0x.js'; -import BigNumber from 'bignumber.js'; +import { ZeroEx } from '0x.js'; +import { BigNumber } from '@0xproject/utils'; import DharmaLoanFrame from 'dharma-loan-frame'; import * as _ from 'lodash'; import Dialog from 'material-ui/Dialog'; @@ -7,31 +7,21 @@ import Divider from 'material-ui/Divider'; import FlatButton from 'material-ui/FlatButton'; import FloatingActionButton from 'material-ui/FloatingActionButton'; import RaisedButton from 'material-ui/RaisedButton'; -import {colors} from 'material-ui/styles'; import ContentAdd from 'material-ui/svg-icons/content/add'; import ContentRemove from 'material-ui/svg-icons/content/remove'; -import { - Table, - TableBody, - TableHeader, - TableHeaderColumn, - TableRow, - TableRowColumn, -} from 'material-ui/Table'; -import QueryString = require('query-string'); +import { Table, TableBody, TableHeader, TableHeaderColumn, TableRow, TableRowColumn } from 'material-ui/Table'; import * as React from 'react'; import ReactTooltip = require('react-tooltip'); import firstBy = require('thenby'); -import {Blockchain} from 'ts/blockchain'; -import {EthWethConversionButton} from 'ts/components/eth_weth_conversion_button'; -import {AssetPicker} from 'ts/components/generate_order/asset_picker'; -import {AllowanceToggle} from 'ts/components/inputs/allowance_toggle'; -import {SendButton} from 'ts/components/send_button'; -import {HelpTooltip} from 'ts/components/ui/help_tooltip'; -import {LifeCycleRaisedButton} from 'ts/components/ui/lifecycle_raised_button'; -import {TokenIcon} from 'ts/components/ui/token_icon'; -import {trackedTokenStorage} from 'ts/local_storage/tracked_token_storage'; -import {Dispatcher} from 'ts/redux/dispatcher'; +import { Blockchain } from 'ts/blockchain'; +import { AssetPicker } from 'ts/components/generate_order/asset_picker'; +import { AllowanceToggle } from 'ts/components/inputs/allowance_toggle'; +import { SendButton } from 'ts/components/send_button'; +import { HelpTooltip } from 'ts/components/ui/help_tooltip'; +import { LifeCycleRaisedButton } from 'ts/components/ui/lifecycle_raised_button'; +import { TokenIcon } from 'ts/components/ui/token_icon'; +import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage'; +import { Dispatcher } from 'ts/redux/dispatcher'; import { BalanceErrs, BlockchainCallErrs, @@ -44,10 +34,11 @@ import { TokenStateByAddress, TokenVisibility, } from 'ts/types'; -import {configs} from 'ts/utils/configs'; -import {constants} from 'ts/utils/constants'; -import {errorReporter} from 'ts/utils/error_reporter'; -import {utils} from 'ts/utils/utils'; +import { colors } from 'ts/utils/colors'; +import { configs } from 'ts/utils/configs'; +import { constants } from 'ts/utils/constants'; +import { errorReporter } from 'ts/utils/error_reporter'; +import { utils } from 'ts/utils/utils'; const ETHER_ICON_PATH = '/images/ether.png'; const ETHER_TOKEN_SYMBOL = 'WETH'; @@ -117,7 +108,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala if (!_.isUndefined(this.state.currentZrxBalance) && !nextZrxTokenBalance.eq(this.state.currentZrxBalance)) { if (this.state.isZRXSpinnerVisible) { const receivedAmount = nextZrxTokenBalance.minus(this.state.currentZrxBalance); - const receiveAmountInUnits = ZeroEx.toUnitAmount(receivedAmount, 18); + const receiveAmountInUnits = ZeroEx.toUnitAmount(receivedAmount, constants.DECIMAL_PLACES_ZRX); this.props.dispatcher.showFlashMessage(`Received ${receiveAmountInUnits.toString(10)} Kovan ZRX`); } this.setState({ @@ -135,7 +126,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala key="errorOkBtn" label="Ok" primary={true} - onTouchTap={this.onErrorDialogToggle.bind(this, false)} + onTouchTap={this._onErrorDialogToggle.bind(this, false)} />, ]; const dharmaDialogActions = [ @@ -143,10 +134,10 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala key="dharmaCloseBtn" label="Close" primary={true} - onTouchTap={this.onDharmaDialogToggle.bind(this, false)} + onTouchTap={this._onDharmaDialogToggle.bind(this, false)} />, ]; - const isTestNetwork = this.props.networkId === constants.TESTNET_NETWORK_ID; + const isTestNetwork = this.props.networkId === constants.NETWORK_ID_TESTNET; const dharmaButtonColumnStyle = { paddingLeft: 3, display: isTestNetwork ? 'table-cell' : 'none', @@ -155,194 +146,141 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala display: isTestNetwork ? 'none' : 'table-cell', }; const allTokenRowHeight = _.size(this.props.tokenByAddress) * TOKEN_TABLE_ROW_HEIGHT; - const tokenTableHeight = allTokenRowHeight < MAX_TOKEN_TABLE_HEIGHT ? - allTokenRowHeight : - MAX_TOKEN_TABLE_HEIGHT; - const isSmallScreen = this.props.screenWidth === ScreenWidths.SM; + const tokenTableHeight = + allTokenRowHeight < MAX_TOKEN_TABLE_HEIGHT ? allTokenRowHeight : MAX_TOKEN_TABLE_HEIGHT; + const isSmallScreen = this.props.screenWidth === ScreenWidths.Sm; const tokenColSpan = isSmallScreen ? TOKEN_COL_SPAN_SM : TOKEN_COL_SPAN_LG; - const dharmaLoanExplanation = 'If you need access to larger amounts of ether,<br> \ + const dharmaLoanExplanation = + 'If you need access to larger amounts of ether,<br> \ you can request a loan from the Dharma Loan<br> \ network. Your loan should be funded in 5<br> \ minutes or less.'; - const allowanceExplanation = '0x smart contracts require access to your<br> \ + const allowanceExplanation = + '0x smart contracts require access to your<br> \ token balances in order to execute trades.<br> \ - Toggling permissions sets an allowance for the<br> \ + Toggling sets an allowance for the<br> \ smart contract so you can start trading that token.'; return ( <div className="lg-px4 md-px4 sm-px1 pb2"> <h3>{isTestNetwork ? 'Test ether' : 'Ether'}</h3> <Divider /> <div className="pt2 pb2"> - {isTestNetwork ? - 'In order to try out the 0x Portal Dapp, request some test ether to pay for \ - gas costs. It might take a bit of time for the test ether to show up.' : - 'Ether must be converted to Ether Tokens in order to be tradable via 0x. \ - You can convert between Ether and Ether Tokens by clicking the "convert" button below.' - } + {isTestNetwork + ? 'In order to try out the 0x Portal Dapp, request some test ether to pay for \ + gas costs. It might take a bit of time for the test ether to show up.' + : 'Ether must be converted to Ether Tokens in order to be tradable via 0x. \ + You can convert between Ether and Ether Tokens from the "Wrap ETH" tab.'} </div> - <Table - selectable={false} - style={styles.bgColor} - > + <Table selectable={false} style={styles.bgColor}> <TableHeader displaySelectAll={false} adjustForCheckbox={false}> <TableRow> <TableHeaderColumn>Currency</TableHeaderColumn> <TableHeaderColumn>Balance</TableHeaderColumn> - <TableRowColumn - className="sm-hide xs-hide" - style={stubColumnStyle} - /> - { - isTestNetwork && - <TableHeaderColumn - style={{paddingLeft: 3}} - > + <TableRowColumn className="sm-hide xs-hide" style={stubColumnStyle} /> + {isTestNetwork && ( + <TableHeaderColumn style={{ paddingLeft: 3 }}> {isSmallScreen ? 'Faucet' : 'Request from faucet'} </TableHeaderColumn> - } - { - isTestNetwork && - <TableHeaderColumn - style={dharmaButtonColumnStyle} - > + )} + {isTestNetwork && ( + <TableHeaderColumn style={dharmaButtonColumnStyle}> {isSmallScreen ? 'Loan' : 'Request Dharma loan'} - <HelpTooltip - style={{paddingLeft: 4}} - explanation={dharmaLoanExplanation} - /> + <HelpTooltip style={{ paddingLeft: 4 }} explanation={dharmaLoanExplanation} /> </TableHeaderColumn> - } + )} </TableRow> </TableHeader> <TableBody displayRowCheckbox={false}> <TableRow key="ETH"> <TableRowColumn className="py1"> - <img - style={{width: ICON_DIMENSION, height: ICON_DIMENSION}} - src={ETHER_ICON_PATH} - /> + <img style={{ width: ICON_DIMENSION, height: ICON_DIMENSION }} src={ETHER_ICON_PATH} /> </TableRowColumn> <TableRowColumn> {this.props.userEtherBalance.toFixed(PRECISION)} ETH - {this.state.isBalanceSpinnerVisible && + {this.state.isBalanceSpinnerVisible && ( <span className="pl1"> <i className="zmdi zmdi-spinner zmdi-hc-spin" /> </span> - } + )} </TableRowColumn> - <TableRowColumn - className="sm-hide xs-hide" - style={stubColumnStyle} - /> - { - isTestNetwork && - <TableRowColumn style={{paddingLeft: 3}}> + <TableRowColumn className="sm-hide xs-hide" style={stubColumnStyle} /> + {isTestNetwork && ( + <TableRowColumn style={{ paddingLeft: 3 }}> <LifeCycleRaisedButton labelReady="Request" labelLoading="Sending..." labelComplete="Sent!" - onClickAsyncFn={this.faucetRequestAsync.bind(this, true)} + onClickAsyncFn={this._faucetRequestAsync.bind(this, true)} /> </TableRowColumn> - } - { - isTestNetwork && + )} + {isTestNetwork && ( <TableRowColumn style={dharmaButtonColumnStyle}> <RaisedButton label="Request" - style={{width: '100%'}} - onTouchTap={this.onDharmaDialogToggle.bind(this)} + style={{ width: '100%' }} + onTouchTap={this._onDharmaDialogToggle.bind(this)} /> </TableRowColumn> - } + )} </TableRow> </TableBody> </Table> - <div className="clearfix" style={{paddingBottom: 1}}> + <div className="clearfix" style={{ paddingBottom: 1 }}> <div className="col col-10"> - <h3 className="pt2"> - {isTestNetwork ? 'Test tokens' : 'Tokens'} - </h3> + <h3 className="pt2">{isTestNetwork ? 'Test tokens' : 'Tokens'}</h3> </div> <div className="col col-1 pt3 align-right"> - <FloatingActionButton - mini={true} - zDepth={0} - onClick={this.onAddTokenClicked.bind(this)} - > + <FloatingActionButton mini={true} zDepth={0} onClick={this._onAddTokenClicked.bind(this)}> <ContentAdd /> </FloatingActionButton> </div> <div className="col col-1 pt3 align-right"> - <FloatingActionButton - mini={true} - zDepth={0} - onClick={this.onRemoveTokenClicked.bind(this)} - > + <FloatingActionButton mini={true} zDepth={0} onClick={this._onRemoveTokenClicked.bind(this)}> <ContentRemove /> </FloatingActionButton> </div> </div> <Divider /> <div className="pt2 pb2"> - {isTestNetwork ? - 'Mint some test tokens you\'d like to use to generate or fill an order using 0x.' : - 'Set trading permissions for a token you\'d like to start trading.' - } + {isTestNetwork + ? "Mint some test tokens you'd like to use to generate or fill an order using 0x." + : "Set trading permissions for a token you'd like to start trading."} </div> - <Table - selectable={false} - bodyStyle={{height: tokenTableHeight}} - style={styles.bgColor} - > + <Table selectable={false} bodyStyle={{ height: tokenTableHeight }} style={styles.bgColor}> <TableHeader displaySelectAll={false} adjustForCheckbox={false}> <TableRow> - <TableHeaderColumn - colSpan={tokenColSpan} - > - Token - </TableHeaderColumn> - <TableHeaderColumn style={{paddingLeft: 3}}>Balance</TableHeaderColumn> - <TableHeaderColumn> - <div className="inline-block">{!isSmallScreen && 'Trade '}Permissions</div> - <HelpTooltip - style={{paddingLeft: 4}} - explanation={allowanceExplanation} - /> - </TableHeaderColumn> + <TableHeaderColumn colSpan={tokenColSpan}>Token</TableHeaderColumn> + <TableHeaderColumn style={{ paddingLeft: 3 }}>Balance</TableHeaderColumn> <TableHeaderColumn> - Action + <div className="inline-block">Allowance</div> + <HelpTooltip style={{ paddingLeft: 4 }} explanation={allowanceExplanation} /> </TableHeaderColumn> - {this.props.screenWidth !== ScreenWidths.SM && - <TableHeaderColumn> - Send - </TableHeaderColumn> - } + <TableHeaderColumn>Action</TableHeaderColumn> + {this.props.screenWidth !== ScreenWidths.Sm && <TableHeaderColumn>Send</TableHeaderColumn>} </TableRow> </TableHeader> - <TableBody displayRowCheckbox={false}> - {this.renderTokenTableRows()} - </TableBody> + <TableBody displayRowCheckbox={false}>{this._renderTokenTableRows()}</TableBody> </Table> <Dialog title="Oh oh" - titleStyle={{fontWeight: 100}} + titleStyle={{ fontWeight: 100 }} actions={errorDialogActions} open={!_.isUndefined(this.state.errorType)} - onRequestClose={this.onErrorDialogToggle.bind(this, false)} + onRequestClose={this._onErrorDialogToggle.bind(this, false)} > - {this.renderErrorDialogBody()} + {this._renderErrorDialogBody()} </Dialog> <Dialog title="Request Dharma Loan" - titleStyle={{fontWeight: 100, backgroundColor: 'rgb(250, 250, 250)'}} - bodyStyle={{backgroundColor: 'rgb(37, 37, 37)'}} - actionsContainerStyle={{backgroundColor: 'rgb(250, 250, 250)'}} + titleStyle={{ fontWeight: 100, backgroundColor: colors.white }} + bodyStyle={{ backgroundColor: colors.dharmaDarkGrey }} + actionsContainerStyle={{ backgroundColor: colors.white }} autoScrollBodyContent={true} actions={dharmaDialogActions} open={this.state.isDharmaDialogVisible} > - {this.renderDharmaLoanFrame()} + {this._renderDharmaLoanFrame()} </Dialog> <AssetPicker userAddress={this.props.userAddress} @@ -351,58 +289,62 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala dispatcher={this.props.dispatcher} isOpen={this.state.isTokenPickerOpen} currentTokenAddress={''} - onTokenChosen={this.onAssetTokenPicked.bind(this)} + onTokenChosen={this._onAssetTokenPicked.bind(this)} tokenByAddress={this.props.tokenByAddress} tokenVisibility={this.state.isAddingToken ? TokenVisibility.UNTRACKED : TokenVisibility.TRACKED} /> </div> ); } - private renderTokenTableRows() { - if (!this.props.blockchainIsLoaded || this.props.blockchainErr !== '') { + private _renderTokenTableRows() { + if (!this.props.blockchainIsLoaded || this.props.blockchainErr !== BlockchainErrs.NoError) { return ''; } - const isSmallScreen = this.props.screenWidth === ScreenWidths.SM; + const isSmallScreen = this.props.screenWidth === ScreenWidths.Sm; const tokenColSpan = isSmallScreen ? TOKEN_COL_SPAN_SM : TOKEN_COL_SPAN_LG; const actionPaddingX = isSmallScreen ? 2 : 24; const allTokens = _.values(this.props.tokenByAddress); const trackedTokens = _.filter(allTokens, t => t.isTracked); const trackedTokensStartingWithEtherToken = trackedTokens.sort( - firstBy((t: Token) => (t.symbol !== ETHER_TOKEN_SYMBOL)) - .thenBy((t: Token) => (t.symbol !== ZRX_TOKEN_SYMBOL)) - .thenBy('address'), + firstBy((t: Token) => t.symbol !== ETHER_TOKEN_SYMBOL) + .thenBy((t: Token) => t.symbol !== ZRX_TOKEN_SYMBOL) + .thenBy('address'), ); const tableRows = _.map( trackedTokensStartingWithEtherToken, - this.renderTokenRow.bind(this, tokenColSpan, actionPaddingX), + this._renderTokenRow.bind(this, tokenColSpan, actionPaddingX), ); return tableRows; } - private renderTokenRow(tokenColSpan: number, actionPaddingX: number, token: Token) { + private _renderTokenRow(tokenColSpan: number, actionPaddingX: number, token: Token) { const tokenState = this.props.tokenStateByAddress[token.address]; - const tokenLink = utils.getEtherScanLinkIfExists(token.address, this.props.networkId, - EtherscanLinkSuffixes.address); - const isMintable = _.includes(configs.symbolsOfMintableTokens, token.symbol) && - this.props.networkId !== constants.MAINNET_NETWORK_ID; + const tokenLink = utils.getEtherScanLinkIfExists( + token.address, + this.props.networkId, + EtherscanLinkSuffixes.Address, + ); + const isMintable = + _.includes(configs.SYMBOLS_OF_MINTABLE_TOKENS, token.symbol) && + this.props.networkId !== constants.NETWORK_ID_MAINNET; return ( - <TableRow key={token.address} style={{height: TOKEN_TABLE_ROW_HEIGHT}}> - <TableRowColumn - colSpan={tokenColSpan} - > - {_.isUndefined(tokenLink) ? - this.renderTokenName(token) : - <a href={tokenLink} target="_blank" style={{textDecoration: 'none'}}> - {this.renderTokenName(token)} + <TableRow key={token.address} style={{ height: TOKEN_TABLE_ROW_HEIGHT }}> + <TableRowColumn colSpan={tokenColSpan}> + {_.isUndefined(tokenLink) ? ( + this._renderTokenName(token) + ) : ( + <a href={tokenLink} target="_blank" style={{ textDecoration: 'none' }}> + {this._renderTokenName(token)} </a> - } + )} </TableRowColumn> - <TableRowColumn style={{paddingRight: 3, paddingLeft: 3}}> - {this.renderAmount(tokenState.balance, token.decimals)} {token.symbol} - {this.state.isZRXSpinnerVisible && token.symbol === ZRX_TOKEN_SYMBOL && - <span className="pl1"> - <i className="zmdi zmdi-spinner zmdi-hc-spin" /> - </span> - } + <TableRowColumn style={{ paddingRight: 3, paddingLeft: 3 }}> + {this._renderAmount(tokenState.balance, token.decimals)} {token.symbol} + {this.state.isZRXSpinnerVisible && + token.symbol === ZRX_TOKEN_SYMBOL && ( + <span className="pl1"> + <i className="zmdi zmdi-spinner zmdi-hc-spin" /> + </span> + )} </TableRowColumn> <TableRowColumn> <AllowanceToggle @@ -410,57 +352,49 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala dispatcher={this.props.dispatcher} token={token} tokenState={tokenState} - onErrorOccurred={this.onErrorOccurred.bind(this)} + onErrorOccurred={this._onErrorOccurred.bind(this)} userAddress={this.props.userAddress} /> </TableRowColumn> - <TableRowColumn - style={{paddingLeft: actionPaddingX, paddingRight: actionPaddingX}} - > - {isMintable && + <TableRowColumn style={{ paddingLeft: actionPaddingX, paddingRight: actionPaddingX }}> + {isMintable && ( <LifeCycleRaisedButton labelReady="Mint" - labelLoading={<span style={{fontSize: 12}}>Minting...</span>} + labelLoading={<span style={{ fontSize: 12 }}>Minting...</span>} labelComplete="Minted!" - onClickAsyncFn={this.onMintTestTokensAsync.bind(this, token)} + onClickAsyncFn={this._onMintTestTokensAsync.bind(this, token)} /> - } - {token.symbol === ETHER_TOKEN_SYMBOL && - <EthWethConversionButton - blockchain={this.props.blockchain} - dispatcher={this.props.dispatcher} - ethToken={this.getWrappedEthToken()} - ethTokenState={tokenState} - userEtherBalance={this.props.userEtherBalance} - onError={this.onEthWethConversionFailed.bind(this)} - /> - } - {token.symbol === ZRX_TOKEN_SYMBOL && this.props.networkId === constants.TESTNET_NETWORK_ID && - <LifeCycleRaisedButton - labelReady="Request" - labelLoading="Sending..." - labelComplete="Sent!" - onClickAsyncFn={this.faucetRequestAsync.bind(this, false)} - /> - } + )} + {token.symbol === ZRX_TOKEN_SYMBOL && + this.props.networkId === constants.NETWORK_ID_TESTNET && ( + <LifeCycleRaisedButton + labelReady="Request" + labelLoading="Sending..." + labelComplete="Sent!" + onClickAsyncFn={this._faucetRequestAsync.bind(this, false)} + /> + )} </TableRowColumn> - {this.props.screenWidth !== ScreenWidths.SM && + {this.props.screenWidth !== ScreenWidths.Sm && ( <TableRowColumn - style={{paddingLeft: actionPaddingX, paddingRight: actionPaddingX}} + style={{ + paddingLeft: actionPaddingX, + paddingRight: actionPaddingX, + }} > <SendButton blockchain={this.props.blockchain} dispatcher={this.props.dispatcher} token={token} tokenState={tokenState} - onError={this.onSendFailed.bind(this)} + onError={this._onSendFailed.bind(this)} /> </TableRowColumn> - } + )} </TableRow> ); } - private onAssetTokenPicked(tokenAddress: string) { + private _onAssetTokenPicked(tokenAddress: string) { if (_.isEmpty(tokenAddress)) { this.setState({ isTokenPickerOpen: false, @@ -468,13 +402,14 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala return; } const token = this.props.tokenByAddress[tokenAddress]; - const isDefaultTrackedToken = _.includes(configs.defaultTrackedTokenSymbols, token.symbol); + const isDefaultTrackedToken = _.includes(configs.DEFAULT_TRACKED_TOKEN_SYMBOLS, token.symbol); if (!this.state.isAddingToken && !isDefaultTrackedToken) { if (token.isRegistered) { // Remove the token from tracked tokens - const newToken = _.assign({}, token, { + const newToken = { + ...token, isTracked: false, - }); + }; this.props.dispatcher.updateTokenByAddress([newToken]); } else { this.props.dispatcher.removeTokenToTokenByAddress(token); @@ -488,82 +423,57 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala isTokenPickerOpen: false, }); } - private onEthWethConversionFailed() { - this.setState({ - errorType: BalanceErrs.wethConversionFailed, - }); - } - private onSendFailed() { + private _onSendFailed() { this.setState({ errorType: BalanceErrs.sendFailed, }); } - private renderAmount(amount: BigNumber, decimals: number) { + private _renderAmount(amount: BigNumber, decimals: number) { const unitAmount = ZeroEx.toUnitAmount(amount, decimals); return unitAmount.toNumber().toFixed(PRECISION); } - private renderTokenName(token: Token) { + private _renderTokenName(token: Token) { const tooltipId = `tooltip-${token.address}`; return ( <div className="flex"> <TokenIcon token={token} diameter={ICON_DIMENSION} /> - <div - data-tip={true} - data-for={tooltipId} - className="mt2 ml2 sm-hide xs-hide" - > + <div data-tip={true} data-for={tooltipId} className="mt2 ml2 sm-hide xs-hide"> {token.name} </div> <ReactTooltip id={tooltipId}>{token.address}</ReactTooltip> </div> ); } - private renderErrorDialogBody() { + private _renderErrorDialogBody() { switch (this.state.errorType) { case BalanceErrs.incorrectNetworkForFaucet: return ( <div> - Our faucet can only send test Ether to addresses on the {constants.TESTNET_NAME} - {' '}testnet (networkId {constants.TESTNET_NETWORK_ID}). Please make sure you are - {' '}connected to the {constants.TESTNET_NAME} testnet and try requesting ether again. + Our faucet can only send test Ether to addresses on the {constants.TESTNET_NAME} testnet + (networkId {constants.NETWORK_ID_TESTNET}). Please make sure you are connected to the{' '} + {constants.TESTNET_NAME} testnet and try requesting ether again. </div> ); case BalanceErrs.faucetRequestFailed: return ( <div> - An unexpected error occurred while trying to request test Ether from our faucet. - {' '}Please refresh the page and try again. + An unexpected error occurred while trying to request test Ether from our faucet. Please refresh + the page and try again. </div> ); case BalanceErrs.faucetQueueIsFull: - return ( - <div> - Our test Ether faucet queue is full. Please try requesting test Ether again later. - </div> - ); + return <div>Our test Ether faucet queue is full. Please try requesting test Ether again later.</div>; case BalanceErrs.mintingFailed: - return ( - <div> - Minting your test tokens failed unexpectedly. Please refresh the page and try again. - </div> - ); - - case BalanceErrs.wethConversionFailed: - return ( - <div> - Converting between Ether and Ether Tokens failed unexpectedly. - Please refresh the page and try again. - </div> - ); + return <div>Minting your test tokens failed unexpectedly. Please refresh the page and try again.</div>; case BalanceErrs.allowanceSettingFailed: return ( <div> - An unexpected error occurred while trying to set your test token allowance. - {' '}Please refresh the page and try again. + An unexpected error occurred while trying to set your test token allowance. Please refresh the + page and try again. </div> ); @@ -574,12 +484,12 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala throw utils.spawnSwitchErr('errorType', this.state.errorType); } } - private renderDharmaLoanFrame() { + private _renderDharmaLoanFrame() { if (utils.isUserOnMobile()) { return ( <h4 style={{ textAlign: 'center' }}> - We apologize -- Dharma loan requests are not available on - mobile yet. Please try again through your desktop browser. + We apologize -- Dharma loan requests are not available on mobile yet. Please try again through your + desktop browser. </h4> ); } else { @@ -592,20 +502,20 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala ); } } - private onErrorOccurred(errorType: BalanceErrs) { + private _onErrorOccurred(errorType: BalanceErrs) { this.setState({ errorType, }); } - private async onMintTestTokensAsync(token: Token): Promise<boolean> { + private async _onMintTestTokensAsync(token: Token): Promise<boolean> { try { await this.props.blockchain.mintTestTokensAsync(token); const amount = ZeroEx.toUnitAmount(constants.MINT_AMOUNT, token.decimals); this.props.dispatcher.showFlashMessage(`Successfully minted ${amount.toString(10)} ${token.symbol}`); return true; } catch (err) { - const errMsg = '' + err; - if (_.includes(errMsg, BlockchainCallErrs.USER_HAS_NO_ASSOCIATED_ADDRESSES)) { + const errMsg = `${err}`; + if (_.includes(errMsg, BlockchainCallErrs.UserHasNoAssociatedAddresses)) { this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); return false; } @@ -614,14 +524,14 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala } utils.consoleLog(`Unexpected error encountered: ${err}`); utils.consoleLog(err.stack); - await errorReporter.reportAsync(err); this.setState({ errorType: BalanceErrs.mintingFailed, }); + await errorReporter.reportAsync(err); return false; } } - private async faucetRequestAsync(isEtherRequest: boolean): Promise<boolean> { + private async _faucetRequestAsync(isEtherRequest: boolean): Promise<boolean> { if (this.props.userAddress === '') { this.props.dispatcher.updateShouldBlockchainErrDialogBeOpen(true); return false; @@ -629,7 +539,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala // If on another network other then the testnet our faucet serves test ether // from, we must show user an error message - if (this.props.blockchain.networkId !== constants.TESTNET_NETWORK_ID) { + if (this.props.blockchain.networkId !== constants.NETWORK_ID_TESTNET) { this.setState({ errorType: BalanceErrs.incorrectNetworkForFaucet, }); @@ -639,17 +549,18 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala await utils.sleepAsync(ARTIFICIAL_FAUCET_REQUEST_DELAY); const segment = isEtherRequest ? 'ether' : 'zrx'; - const response = await fetch(`${constants.ETHER_FAUCET_ENDPOINT}/${segment}/${this.props.userAddress}`); + const response = await fetch(`${constants.URL_ETHER_FAUCET}/${segment}/${this.props.userAddress}`); const responseBody = await response.text(); if (response.status !== constants.SUCCESS_STATUS) { utils.consoleLog(`Unexpected status code: ${response.status} -> ${responseBody}`); - await errorReporter.reportAsync(new Error(`Faucet returned non-200: ${JSON.stringify(response)}`)); - const errorType = response.status === constants.UNAVAILABLE_STATUS ? - BalanceErrs.faucetQueueIsFull : - BalanceErrs.faucetRequestFailed; + const errorType = + response.status === constants.UNAVAILABLE_STATUS + ? BalanceErrs.faucetQueueIsFull + : BalanceErrs.faucetRequestFailed; this.setState({ errorType, }); + await errorReporter.reportAsync(new Error(`Faucet returned non-200: ${JSON.stringify(response)}`)); return false; } @@ -670,28 +581,23 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala } return true; } - private onErrorDialogToggle(isOpen: boolean) { + private _onErrorDialogToggle(isOpen: boolean) { this.setState({ errorType: undefined, }); } - private onDharmaDialogToggle() { + private _onDharmaDialogToggle() { this.setState({ isDharmaDialogVisible: !this.state.isDharmaDialogVisible, }); } - private getWrappedEthToken() { - const tokens = _.values(this.props.tokenByAddress); - const wrappedEthToken = _.find(tokens, {symbol: ETHER_TOKEN_SYMBOL}); - return wrappedEthToken; - } - private onAddTokenClicked() { + private _onAddTokenClicked() { this.setState({ isTokenPickerOpen: true, isAddingToken: true, }); } - private onRemoveTokenClicked() { + private _onRemoveTokenClicked() { this.setState({ isTokenPickerOpen: true, isAddingToken: false, diff --git a/packages/website/ts/components/top_bar.tsx b/packages/website/ts/components/top_bar.tsx index 4398fe667..11d3e7cc2 100644 --- a/packages/website/ts/components/top_bar.tsx +++ b/packages/website/ts/components/top_bar.tsx @@ -1,29 +1,18 @@ import * as _ from 'lodash'; -import AppBar from 'material-ui/AppBar'; import Drawer from 'material-ui/Drawer'; import MenuItem from 'material-ui/MenuItem'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; -import {Link} from 'react-router-dom'; -import {HashLink} from 'react-router-hash-link'; -import { - animateScroll, - Link as ScrollLink, -} from 'react-scroll'; +import { Link } from 'react-router-dom'; import ReactTooltip = require('react-tooltip'); -import {PortalMenu} from 'ts/components/portal_menu'; -import {TopBarMenuItem} from 'ts/components/top_bar_menu_item'; -import {DropDownMenuItem} from 'ts/components/ui/drop_down_menu_item'; -import {Identicon} from 'ts/components/ui/identicon'; -import {DocsInfo} from 'ts/pages/documentation/docs_info'; -import {NestedSidebarMenu} from 'ts/pages/shared/nested_sidebar_menu'; -import {DocsMenu, MenuSubsectionsBySection, Styles, TypeDocNode, WebsitePaths} from 'ts/types'; -import {configs} from 'ts/utils/configs'; -import {constants} from 'ts/utils/constants'; -import {typeDocUtils} from 'ts/utils/typedoc_utils'; - -const CUSTOM_DARK_GRAY = '#231F20'; -const SECTION_HEADER_COLOR = 'rgb(234, 234, 234)'; +import { PortalMenu } from 'ts/components/portal_menu'; +import { TopBarMenuItem } from 'ts/components/top_bar_menu_item'; +import { DropDownMenuItem } from 'ts/components/ui/drop_down_menu_item'; +import { Identicon } from 'ts/components/ui/identicon'; +import { DocsInfo } from 'ts/pages/documentation/docs_info'; +import { NestedSidebarMenu } from 'ts/pages/shared/nested_sidebar_menu'; +import { DocsMenu, MenuSubsectionsBySection, Styles, WebsitePaths } from 'ts/types'; +import { colors } from 'ts/utils/colors'; +import { constants } from 'ts/utils/constants'; interface TopBarProps { userAddress?: string; @@ -52,16 +41,11 @@ const styles: Styles = { whiteSpace: 'nowrap', width: 70, }, - addressPopover: { - backgroundColor: colors.blueGrey500, - color: 'white', - padding: 3, - }, topBar: { - backgroundColor: 'white', + backgroundcolor: colors.white, height: 59, width: '100%', - position: 'fixed', + position: 'relative', top: 0, zIndex: 1100, paddingBottom: 1, @@ -71,7 +55,7 @@ const styles: Styles = { }, menuItem: { fontSize: 14, - color: CUSTOM_DARK_GRAY, + color: colors.darkestGrey, paddingTop: 6, paddingBottom: 6, marginTop: 17, @@ -97,40 +81,28 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> { const isFullWidthPage = this.props.shouldFullWidth; const parentClassNames = `flex mx-auto ${isFullWidthPage ? 'pl2' : 'max-width-4'}`; const developerSectionMenuItems = [ - <Link - key="subMenuItem-zeroEx" - to={WebsitePaths.ZeroExJs} - className="text-decoration-none" - > - <MenuItem style={{fontSize: styles.menuItem.fontSize}} primaryText="0x.js" /> + <Link key="subMenuItem-zeroEx" to={WebsitePaths.ZeroExJs} className="text-decoration-none"> + <MenuItem style={{ fontSize: styles.menuItem.fontSize }} primaryText="0x.js" /> </Link>, - <Link - key="subMenuItem-smartContracts" - to={WebsitePaths.SmartContracts} - className="text-decoration-none" - > - <MenuItem style={{fontSize: styles.menuItem.fontSize}} primaryText="Smart Contracts" /> + <Link key="subMenuItem-smartContracts" to={WebsitePaths.SmartContracts} className="text-decoration-none"> + <MenuItem style={{ fontSize: styles.menuItem.fontSize }} primaryText="Smart Contracts" /> </Link>, - <Link - key="subMenuItem-0xconnect" - to={WebsitePaths.Connect} - className="text-decoration-none" - > - <MenuItem style={{fontSize: styles.menuItem.fontSize}} primaryText="0x Connect" /> + <Link key="subMenuItem-0xconnect" to={WebsitePaths.Connect} className="text-decoration-none"> + <MenuItem style={{ fontSize: styles.menuItem.fontSize }} primaryText="0x Connect" /> </Link>, <a key="subMenuItem-standard-relayer-api" target="_blank" className="text-decoration-none" - href={constants.STANDARD_RELAYER_API_GITHUB} + href={constants.URL_STANDARD_RELAYER_API_GITHUB} > - <MenuItem style={{fontSize: styles.menuItem.fontSize}} primaryText="Standard Relayer API" /> + <MenuItem style={{ fontSize: styles.menuItem.fontSize }} primaryText="Standard Relayer API" /> </a>, <a key="subMenuItem-github" target="_blank" className="text-decoration-none" - href={constants.GITHUB_URL} + href={constants.URL_GITHUB_ORG} > <MenuItem style={{ fontSize: styles.menuItem.fontSize }} primaryText="GitHub" /> </a>, @@ -140,10 +112,10 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> { className="text-decoration-none" href={`${WebsitePaths.Whitepaper}`} > - <MenuItem style={{fontSize: styles.menuItem.fontSize}} primaryText="Whitepaper" /> + <MenuItem style={{ fontSize: styles.menuItem.fontSize }} primaryText="Whitepaper" /> </a>, ]; - const bottomBorderStyle = this.shouldDisplayBottomBar() ? styles.bottomBar : {}; + const bottomBorderStyle = this._shouldDisplayBottomBar() ? styles.bottomBar : {}; const fullWidthClasses = isFullWidthPage ? 'pr4' : ''; const logoUrl = isNightVersion ? '/images/protocol_logo_white.png' : '/images/protocol_logo_black.png'; const menuClasses = `col col-${isFullWidthPage ? '4' : '5'} ${fullWidthClasses} lg-pr0 md-pr2 sm-hide xs-hide`; @@ -154,19 +126,17 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> { paddingTop: 16, }; return ( - <div style={{...styles.topBar, ...bottomBorderStyle, ...this.props.style}} className="pb1"> + <div style={{ ...styles.topBar, ...bottomBorderStyle, ...this.props.style }} className="pb1"> <div className={parentClassNames}> - <div className="col col-2 sm-pl2 md-pl2 lg-pl0" style={{paddingTop: 15}}> + <div className="col col-2 sm-pl2 md-pl2 lg-pl0" style={{ paddingTop: 15 }}> <Link to={`${WebsitePaths.Home}`} className="text-decoration-none"> <img src={logoUrl} height="30" /> </Link> </div> <div className={`col col-${isFullWidthPage ? '8' : '9'} lg-hide md-hide`} /> <div className={`col col-${isFullWidthPage ? '6' : '5'} sm-hide xs-hide`} /> - {!this.isViewingPortal() && - <div - className={menuClasses} - > + {!this._isViewingPortal() && ( + <div className={menuClasses}> <div className="flex justify-between"> <DropDownMenuItem title="Developers" @@ -196,110 +166,97 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> { /> </div> </div> - } - {this.props.blockchainIsLoaded && !_.isEmpty(this.props.userAddress) && - <div className="col col-5"> - {this.renderUser()} - </div> - } - {!this.isViewingPortal() && - <div - className={`col ${isFullWidthPage ? 'col-2 pl2' : 'col-1'} md-hide lg-hide`} - > - <div style={menuIconStyle}> - <i - className="zmdi zmdi-menu" - onClick={this.onMenuButtonClick.bind(this)} - /> - </div> + )} + {this.props.blockchainIsLoaded && + !_.isEmpty(this.props.userAddress) && ( + <div className="col col-5 sm-hide xs-hide">{this._renderUser()}</div> + )} + <div className={`col ${isFullWidthPage ? 'col-2 pl2' : 'col-1'} md-hide lg-hide`}> + <div style={menuIconStyle}> + <i className="zmdi zmdi-menu" onClick={this._onMenuButtonClick.bind(this)} /> </div> - } + </div> </div> - {this.renderDrawer()} + {this._renderDrawer()} </div> ); } - private renderDrawer() { + private _renderDrawer() { return ( <Drawer open={this.state.isDrawerOpen} docked={false} openSecondary={true} - onRequestChange={this.onMenuButtonClick.bind(this)} + onRequestChange={this._onMenuButtonClick.bind(this)} > - {this.renderPortalMenu()} - {this.renderDocsMenu()} - {this.renderWiki()} - <div className="pl1 py1 mt3" style={{backgroundColor: SECTION_HEADER_COLOR}}>Website</div> + {this._renderPortalMenu()} + {this._renderDocsMenu()} + {this._renderWiki()} + <div className="pl1 py1 mt3" style={{ backgroundColor: colors.lightGrey }}> + Website + </div> <Link to={WebsitePaths.Home} className="text-decoration-none"> <MenuItem className="py2">Home</MenuItem> </Link> <Link to={`${WebsitePaths.Wiki}`} className="text-decoration-none"> <MenuItem className="py2">Wiki</MenuItem> </Link> - {!this.isViewing0xjsDocs() && + {!this._isViewing0xjsDocs() && ( <Link to={WebsitePaths.ZeroExJs} className="text-decoration-none"> <MenuItem className="py2">0x.js Docs</MenuItem> </Link> - } - {!this.isViewingConnectDocs() && + )} + {!this._isViewingConnectDocs() && ( <Link to={WebsitePaths.Connect} className="text-decoration-none"> <MenuItem className="py2">0x Connect Docs</MenuItem> </Link> - } - {!this.isViewingSmartContractsDocs() && + )} + {!this._isViewingSmartContractsDocs() && ( <Link to={WebsitePaths.SmartContracts} className="text-decoration-none"> <MenuItem className="py2">Smart Contract Docs</MenuItem> </Link> - } - {!this.isViewingPortal() && + )} + {!this._isViewingPortal() && ( <Link to={`${WebsitePaths.Portal}`} className="text-decoration-none"> <MenuItem className="py2">Portal DApp</MenuItem> </Link> - } - <a - className="text-decoration-none" - target="_blank" - href={`${WebsitePaths.Whitepaper}`} - > + )} + <a className="text-decoration-none" target="_blank" href={`${WebsitePaths.Whitepaper}`}> <MenuItem className="py2">Whitepaper</MenuItem> </a> <Link to={`${WebsitePaths.About}`} className="text-decoration-none"> <MenuItem className="py2">About</MenuItem> </Link> - <a - className="text-decoration-none" - target="_blank" - href={constants.BLOG_URL} - > + <a className="text-decoration-none" target="_blank" href={constants.URL_BLOG}> <MenuItem className="py2">Blog</MenuItem> </a> <Link to={`${WebsitePaths.FAQ}`} className="text-decoration-none"> - <MenuItem - className="py2" - onTouchTap={this.onMenuButtonClick.bind(this)} - > + <MenuItem className="py2" onTouchTap={this._onMenuButtonClick.bind(this)}> FAQ </MenuItem> </Link> </Drawer> ); } - private renderDocsMenu() { - if (!this.isViewing0xjsDocs() && !this.isViewingSmartContractsDocs() && !this.isViewingConnectDocs() - || _.isUndefined(this.props.menu)) { - return; + private _renderDocsMenu(): React.ReactNode { + if ( + (!this._isViewing0xjsDocs() && !this._isViewingSmartContractsDocs() && !this._isViewingConnectDocs()) || + _.isUndefined(this.props.menu) + ) { + return undefined; } const sectionTitle = `${this.props.docsInfo.displayName} Docs`; return ( <div className="lg-hide md-hide"> - <div className="pl1 py1" style={{backgroundColor: SECTION_HEADER_COLOR}}>{sectionTitle}</div> + <div className="pl1 py1" style={{ backgroundColor: colors.lightGrey }}> + {sectionTitle} + </div> <NestedSidebarMenu topLevelMenu={this.props.menu} menuSubsectionsBySection={this.props.menuSubsectionsBySection} shouldDisplaySectionHeaders={false} - onMenuItemClick={this.onMenuButtonClick.bind(this)} + onMenuItemClick={this._onMenuButtonClick.bind(this)} selectedVersion={this.props.docsVersion} docPath={this.props.docsInfo.websitePath} versions={this.props.availableDocVersions} @@ -307,51 +264,45 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> { </div> ); } - private renderWiki() { - if (!this.isViewingWiki()) { - return; + private _renderWiki(): React.ReactNode { + if (!this._isViewingWiki()) { + return undefined; } return ( <div className="lg-hide md-hide"> - <div className="pl1 py1" style={{backgroundColor: SECTION_HEADER_COLOR}}>0x Protocol Wiki</div> + <div className="pl1 py1" style={{ backgroundColor: colors.lightGrey }}> + 0x Protocol Wiki + </div> <NestedSidebarMenu topLevelMenu={this.props.menuSubsectionsBySection} menuSubsectionsBySection={this.props.menuSubsectionsBySection} shouldDisplaySectionHeaders={false} - onMenuItemClick={this.onMenuButtonClick.bind(this)} + onMenuItemClick={this._onMenuButtonClick.bind(this)} /> </div> ); } - private renderPortalMenu() { - if (!this.isViewingPortal()) { - return; + private _renderPortalMenu(): React.ReactNode { + if (!this._isViewingPortal()) { + return undefined; } return ( <div className="lg-hide md-hide"> - <div className="pl1 py1" style={{backgroundColor: SECTION_HEADER_COLOR}}>Portal DApp</div> - <PortalMenu - menuItemStyle={{color: 'black'}} - onClick={this.onMenuButtonClick.bind(this)} - /> + <div className="pl1 py1" style={{ backgroundColor: colors.lightGrey }}> + Portal DApp + </div> + <PortalMenu menuItemStyle={{ color: 'black' }} onClick={this._onMenuButtonClick.bind(this)} /> </div> ); } - private renderUser() { + private _renderUser() { const userAddress = this.props.userAddress; const identiconDiameter = 26; return ( - <div - className="flex right lg-pr0 md-pr2 sm-pr2" - style={{paddingTop: 16}} - > - <div - style={styles.address} - data-tip={true} - data-for="userAddressTooltip" - > + <div className="flex right lg-pr0 md-pr2 sm-pr2" style={{ paddingTop: 16 }}> + <div style={styles.address} data-tip={true} data-for="userAddressTooltip"> {!_.isEmpty(userAddress) ? userAddress : ''} </div> <ReactTooltip id="userAddressTooltip">{userAddress}</ReactTooltip> @@ -361,31 +312,36 @@ export class TopBar extends React.Component<TopBarProps, TopBarState> { </div> ); } - private onMenuButtonClick() { + private _onMenuButtonClick() { this.setState({ isDrawerOpen: !this.state.isDrawerOpen, }); } - private isViewingPortal() { + private _isViewingPortal() { return _.includes(this.props.location.pathname, WebsitePaths.Portal); } - private isViewingFAQ() { + private _isViewingFAQ() { return _.includes(this.props.location.pathname, WebsitePaths.FAQ); } - private isViewing0xjsDocs() { + private _isViewing0xjsDocs() { return _.includes(this.props.location.pathname, WebsitePaths.ZeroExJs); } - private isViewingConnectDocs() { + private _isViewingConnectDocs() { return _.includes(this.props.location.pathname, WebsitePaths.Connect); } - private isViewingSmartContractsDocs() { + private _isViewingSmartContractsDocs() { return _.includes(this.props.location.pathname, WebsitePaths.SmartContracts); } - private isViewingWiki() { + private _isViewingWiki() { return _.includes(this.props.location.pathname, WebsitePaths.Wiki); } - private shouldDisplayBottomBar() { - return this.isViewingWiki() || this.isViewing0xjsDocs() || this.isViewingFAQ() || - this.isViewingSmartContractsDocs() || this.isViewingConnectDocs(); + private _shouldDisplayBottomBar() { + return ( + this._isViewingWiki() || + this._isViewing0xjsDocs() || + this._isViewingFAQ() || + this._isViewingSmartContractsDocs() || + this._isViewingConnectDocs() + ); } } diff --git a/packages/website/ts/components/top_bar_menu_item.tsx b/packages/website/ts/components/top_bar_menu_item.tsx index de429fba6..96ee86142 100644 --- a/packages/website/ts/components/top_bar_menu_item.tsx +++ b/packages/website/ts/components/top_bar_menu_item.tsx @@ -1,11 +1,10 @@ import * as _ from 'lodash'; import * as React from 'react'; -import {Link} from 'react-router-dom'; -import {Styles} from 'ts/types'; +import { Link } from 'react-router-dom'; +import { colors } from 'ts/utils/colors'; -const CUSTOM_DARK_GRAY = '#231F20'; const DEFAULT_STYLE = { - color: CUSTOM_DARK_GRAY, + color: colors.darkestGrey, }; interface TopBarMenuItemProps { @@ -27,24 +26,24 @@ export class TopBarMenuItem extends React.Component<TopBarMenuItemProps, TopBarM isNightVersion: false, }; public render() { - const primaryStyles = this.props.isPrimary ? { - borderRadius: 4, - border: `1px solid ${this.props.isNightVersion ? '#979797' : 'rgb(230, 229, 229)'}`, - marginTop: 15, - paddingLeft: 9, - paddingRight: 9, - width: 77, - } : {}; + const primaryStyles = this.props.isPrimary + ? { + borderRadius: 4, + border: `1px solid ${this.props.isNightVersion ? colors.grey : colors.greyishPink}`, + marginTop: 15, + paddingLeft: 9, + paddingRight: 9, + width: 77, + } + : {}; const menuItemColor = this.props.isNightVersion ? 'white' : this.props.style.color; - const linkColor = _.isUndefined(menuItemColor) ? - CUSTOM_DARK_GRAY : - menuItemColor; + const linkColor = _.isUndefined(menuItemColor) ? colors.darkestGrey : menuItemColor; return ( <div className={`center ${this.props.className}`} - style={{...this.props.style, ...primaryStyles, color: menuItemColor}} + style={{ ...this.props.style, ...primaryStyles, color: menuItemColor }} > - <Link to={this.props.path} className="text-decoration-none" style={{color: linkColor}}> + <Link to={this.props.path} className="text-decoration-none" style={{ color: linkColor }}> {this.props.title} </Link> </div> diff --git a/packages/website/ts/components/track_token_confirmation.tsx b/packages/website/ts/components/track_token_confirmation.tsx index b9b2ef18a..76971aefa 100644 --- a/packages/website/ts/components/track_token_confirmation.tsx +++ b/packages/website/ts/components/track_token_confirmation.tsx @@ -1,11 +1,9 @@ import * as _ from 'lodash'; -import Dialog from 'material-ui/Dialog'; -import FlatButton from 'material-ui/FlatButton'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; -import {Party} from 'ts/components/ui/party'; -import {Token, TokenByAddress} from 'ts/types'; -import {utils} from 'ts/utils/utils'; +import { Party } from 'ts/components/ui/party'; +import { Token, TokenByAddress } from 'ts/types'; +import { colors } from 'ts/utils/colors'; +import { utils } from 'ts/utils/utils'; interface TrackTokenConfirmationProps { tokens: Token[]; @@ -16,25 +14,23 @@ interface TrackTokenConfirmationProps { interface TrackTokenConfirmationState {} -export class TrackTokenConfirmation extends - React.Component<TrackTokenConfirmationProps, TrackTokenConfirmationState> { +export class TrackTokenConfirmation extends React.Component<TrackTokenConfirmationProps, TrackTokenConfirmationState> { public render() { const isMultipleTokens = this.props.tokens.length > 1; const allTokens = _.values(this.props.tokenByAddress); return ( - <div style={{color: colors.grey700}}> - {this.props.isAddingTokenToTracked ? + <div style={{ color: colors.grey700 }}> + {this.props.isAddingTokenToTracked ? ( <div className="py4 my4 center"> <span className="pr1"> <i className="zmdi zmdi-spinner zmdi-hc-spin" /> </span> <span>Adding token{isMultipleTokens && 's'}...</span> - </div> : + </div> + ) : ( <div> - <div> - You do not currently track the following token{isMultipleTokens && 's'}: - </div> - <div className="py2 clearfix mx-auto center" style={{width: 355}}> + <div>You do not currently track the following token{isMultipleTokens && 's'}:</div> + <div className="py2 clearfix mx-auto center" style={{ width: 355 }}> {_.map(this.props.tokens, (token: Token) => ( <div key={`token-profile-${token.name}`} @@ -52,13 +48,13 @@ export class TrackTokenConfirmation extends ))} </div> <div> - Tracking a token adds it to the balances section of 0x Portal and - allows you to generate/fill orders involving the token + Tracking a token adds it to the balances section of 0x Portal and allows you to + generate/fill orders involving the token {isMultipleTokens && 's'}. Would you like to start tracking{' '} - {isMultipleTokens ? 'these' : 'this'}{' '}token? + {isMultipleTokens ? 'these' : 'this'} token? </div> </div> - } + )} </div> ); } diff --git a/packages/website/ts/components/trade_history/trade_history.tsx b/packages/website/ts/components/trade_history/trade_history.tsx index 59f85a03d..635358627 100644 --- a/packages/website/ts/components/trade_history/trade_history.tsx +++ b/packages/website/ts/components/trade_history/trade_history.tsx @@ -2,10 +2,10 @@ import * as _ from 'lodash'; import Divider from 'material-ui/Divider'; import Paper from 'material-ui/Paper'; import * as React from 'react'; -import {TradeHistoryItem} from 'ts/components/trade_history/trade_history_item'; -import {tradeHistoryStorage} from 'ts/local_storage/trade_history_storage'; -import {Fill, TokenByAddress} from 'ts/types'; -import {utils} from 'ts/utils/utils'; +import { TradeHistoryItem } from 'ts/components/trade_history/trade_history_item'; +import { tradeHistoryStorage } from 'ts/local_storage/trade_history_storage'; +import { Fill, TokenByAddress } from 'ts/types'; +import { utils } from 'ts/utils/utils'; const FILL_POLLING_INTERVAL = 1000; @@ -20,19 +20,19 @@ interface TradeHistoryState { } export class TradeHistory extends React.Component<TradeHistoryProps, TradeHistoryState> { - private fillPollingIntervalId: number; + private _fillPollingIntervalId: number; public constructor(props: TradeHistoryProps) { super(props); - const sortedFills = this.getSortedFills(); + const sortedFills = this._getSortedFills(); this.state = { sortedFills, }; } public componentWillMount() { - this.startPollingForFills(); + this._startPollingForFills(); } public componentWillUnmount() { - this.stopPollingForFills(); + this._stopPollingForFills(); } public componentDidMount() { window.scrollTo(0, 0); @@ -42,16 +42,16 @@ export class TradeHistory extends React.Component<TradeHistoryProps, TradeHistor <div className="lg-px4 md-px4 sm-px2"> <h3>Trade history</h3> <Divider /> - <div className="pt2" style={{height: 608, overflow: 'scroll'}}> - {this.renderTrades()} + <div className="pt2" style={{ height: 608, overflow: 'scroll' }}> + {this._renderTrades()} </div> </div> ); } - private renderTrades() { - const numNonCustomFills = this.numFillsWithoutCustomERC20Tokens(); + private _renderTrades() { + const numNonCustomFills = this._numFillsWithoutCustomERC20Tokens(); if (numNonCustomFills === 0) { - return this.renderEmptyNotice(); + return this._renderEmptyNotice(); } return _.map(this.state.sortedFills, (fill, index) => { @@ -66,14 +66,14 @@ export class TradeHistory extends React.Component<TradeHistoryProps, TradeHistor ); }); } - private renderEmptyNotice() { + private _renderEmptyNotice() { return ( - <Paper className="mt1 p2 mx-auto center" style={{width: '80%'}}> + <Paper className="mt1 p2 mx-auto center" style={{ width: '80%' }}> No filled orders yet. </Paper> ); } - private numFillsWithoutCustomERC20Tokens() { + private _numFillsWithoutCustomERC20Tokens() { let numNonCustomFills = 0; const tokens = _.values(this.props.tokenByAddress); _.each(this.state.sortedFills, fill => { @@ -93,9 +93,9 @@ export class TradeHistory extends React.Component<TradeHistoryProps, TradeHistor }); return numNonCustomFills; } - private startPollingForFills() { - this.fillPollingIntervalId = window.setInterval(() => { - const sortedFills = this.getSortedFills(); + private _startPollingForFills() { + this._fillPollingIntervalId = window.setInterval(() => { + const sortedFills = this._getSortedFills(); if (!utils.deepEqual(sortedFills, this.state.sortedFills)) { this.setState({ sortedFills, @@ -103,10 +103,10 @@ export class TradeHistory extends React.Component<TradeHistoryProps, TradeHistor } }, FILL_POLLING_INTERVAL); } - private stopPollingForFills() { - clearInterval(this.fillPollingIntervalId); + private _stopPollingForFills() { + clearInterval(this._fillPollingIntervalId); } - private getSortedFills() { + private _getSortedFills() { const fillsByHash = tradeHistoryStorage.getUserFillsByHash(this.props.userAddress, this.props.networkId); const fills = _.values(fillsByHash); const sortedFills = _.sortBy(fills, [(fill: Fill) => fill.blockTimestamp * -1]); diff --git a/packages/website/ts/components/trade_history/trade_history_item.tsx b/packages/website/ts/components/trade_history/trade_history_item.tsx index 4dcceadb7..7e42e64e6 100644 --- a/packages/website/ts/components/trade_history/trade_history_item.tsx +++ b/packages/website/ts/components/trade_history/trade_history_item.tsx @@ -1,14 +1,14 @@ -import {ZeroEx} from '0x.js'; -import BigNumber from 'bignumber.js'; +import { ZeroEx } from '0x.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import Paper from 'material-ui/Paper'; -import {colors} from 'material-ui/styles'; import * as moment from 'moment'; import * as React from 'react'; import * as ReactTooltip from 'react-tooltip'; -import {EtherScanIcon} from 'ts/components/ui/etherscan_icon'; -import {Party} from 'ts/components/ui/party'; -import {EtherscanLinkSuffixes, Fill, Token, TokenByAddress} from 'ts/types'; +import { EtherScanIcon } from 'ts/components/ui/etherscan_icon'; +import { Party } from 'ts/components/ui/party'; +import { EtherscanLinkSuffixes, Fill, Token, TokenByAddress } from 'ts/types'; +import { colors } from 'ts/utils/colors'; const PRECISION = 5; const IDENTICON_DIAMETER = 40; @@ -44,30 +44,26 @@ export class TradeHistoryItem extends React.Component<TradeHistoryItemProps, Tra fontWeight: 100, display: 'inline-block', }; - const amountColClassNames = 'col col-12 lg-col-4 md-col-4 lg-py2 md-py2 sm-py1 lg-pr2 md-pr2 \ + const amountColClassNames = + 'col col-12 lg-col-4 md-col-4 lg-py2 md-py2 sm-py1 lg-pr2 md-pr2 \ lg-right-align md-right-align sm-center'; return ( - <Paper - className="py1" - style={{margin: '3px 3px 15px 3px'}} - > + <Paper className="py1" style={{ margin: '3px 3px 15px 3px' }}> <div className="clearfix"> - <div className="col col-12 lg-col-1 md-col-1 pt2 lg-pl3 md-pl3"> - {this.renderDate()} - </div> + <div className="col col-12 lg-col-1 md-col-1 pt2 lg-pl3 md-pl3">{this._renderDate()}</div> <div className="col col-12 lg-col-6 md-col-6 lg-pl3 md-pl3" - style={{fontSize: 12, fontWeight: 100}} + style={{ fontSize: 12, fontWeight: 100 }} > - <div className="flex sm-mx-auto xs-mx-auto" style={{paddingTop: 4, width: 224}}> + <div className="flex sm-mx-auto xs-mx-auto" style={{ paddingTop: 4, width: 224 }}> <Party label="Maker" address={fill.maker} identiconDiameter={IDENTICON_DIAMETER} networkId={this.props.networkId} /> - <i style={{fontSize: 30}} className="zmdi zmdi-swap py3" /> + <i style={{ fontSize: 30 }} className="zmdi zmdi-swap py3" /> <Party label="Taker" address={fill.taker} @@ -76,18 +72,15 @@ export class TradeHistoryItem extends React.Component<TradeHistoryItemProps, Tra /> </div> </div> - <div - className={amountColClassNames} - style={amountColStyle} - > - {this.renderAmounts(makerToken, takerToken)} + <div className={amountColClassNames} style={amountColStyle}> + {this._renderAmounts(makerToken, takerToken)} </div> <div className="col col-12 lg-col-1 md-col-1 lg-pr3 md-pr3 lg-py3 md-py3 sm-pb1 sm-center"> - <div className="pt1 lg-right md-right sm-mx-auto" style={{width: 13}}> + <div className="pt1 lg-right md-right sm-mx-auto" style={{ width: 13 }}> <EtherScanIcon addressOrTxHash={fill.transactionHash} networkId={this.props.networkId} - etherscanLinkSuffixes={EtherscanLinkSuffixes.tx} + etherscanLinkSuffixes={EtherscanLinkSuffixes.Tx} /> </div> </div> @@ -95,7 +88,7 @@ export class TradeHistoryItem extends React.Component<TradeHistoryItemProps, Tra </Paper> ); } - private renderAmounts(makerToken: Token, takerToken: Token) { + private _renderAmounts(makerToken: Token, takerToken: Token) { const fill = this.props.fill; const filledTakerTokenAmountInUnits = ZeroEx.toUnitAmount(fill.filledTakerTokenAmount, takerToken.decimals); const filledMakerTokenAmountInUnits = ZeroEx.toUnitAmount(fill.filledMakerTokenAmount, takerToken.decimals); @@ -124,31 +117,26 @@ export class TradeHistoryItem extends React.Component<TradeHistoryItemProps, Tra givenToken = takerToken; } else { // This condition should never be hit - throw new Error('Found Fill that wasn\'t performed by this user'); + throw new Error("Found Fill that wasn't performed by this user"); } return ( <div> - <div - style={{color: colors.green400, fontSize: 16}} - > - <span>+{' '}</span> - {this.renderAmount(receiveAmount, receiveToken.symbol, receiveToken.decimals)} + <div style={{ color: colors.green400, fontSize: 16 }}> + <span>+ </span> + {this._renderAmount(receiveAmount, receiveToken.symbol, receiveToken.decimals)} </div> - <div - className="pb1 inline-block" - style={{color: colors.red200, fontSize: 16}} - > - <span>-{' '}</span> - {this.renderAmount(givenAmount, givenToken.symbol, givenToken.decimals)} + <div className="pb1 inline-block" style={{ color: colors.red200, fontSize: 16 }}> + <span>- </span> + {this._renderAmount(givenAmount, givenToken.symbol, givenToken.decimals)} </div> - <div style={{color: colors.grey400, fontSize: 14}}> + <div style={{ color: colors.grey400, fontSize: 14 }}> {exchangeRate.toFixed(PRECISION)} {givenToken.symbol}/{receiveToken.symbol} </div> </div> ); } - private renderDate() { + private _renderDate() { const blockMoment = moment.unix(this.props.fill.blockTimestamp); if (!blockMoment.isValid()) { return null; @@ -160,17 +148,18 @@ export class TradeHistoryItem extends React.Component<TradeHistoryItemProps, Tra const dateTooltipId = `${this.props.fill.transactionHash}-date`; return ( - <div - data-tip={true} - data-for={dateTooltipId} - > - <div className="center pt1" style={{fontSize: 13}}>{monthAbreviation}</div> - <div className="center" style={{fontSize: 24, fontWeight: 100}}>{dayOfMonth}</div> + <div data-tip={true} data-for={dateTooltipId}> + <div className="center pt1" style={{ fontSize: 13 }}> + {monthAbreviation} + </div> + <div className="center" style={{ fontSize: 24, fontWeight: 100 }}> + {dayOfMonth} + </div> <ReactTooltip id={dateTooltipId}>{formattedBlockDate}</ReactTooltip> </div> ); } - private renderAmount(amount: BigNumber, symbol: string, decimals: number) { + private _renderAmount(amount: BigNumber, symbol: string, decimals: number) { const unitAmount = ZeroEx.toUnitAmount(amount, decimals); return ( <span> diff --git a/packages/website/ts/components/ui/alert.tsx b/packages/website/ts/components/ui/alert.tsx index 71d2388f2..54881b499 100644 --- a/packages/website/ts/components/ui/alert.tsx +++ b/packages/website/ts/components/ui/alert.tsx @@ -1,19 +1,17 @@ -import {colors} from 'material-ui/styles'; import * as React from 'react'; -import {AlertTypes} from 'ts/types'; - -const CUSTOM_GREEN = 'rgb(137, 199, 116)'; +import { AlertTypes } from 'ts/types'; +import { colors } from 'ts/utils/colors'; interface AlertProps { type: AlertTypes; - message: string|React.ReactNode; + message: string | React.ReactNode; } export function Alert(props: AlertProps) { const isAlert = props.type === AlertTypes.ERROR; const errMsgStyles = { - background: isAlert ? colors.red200 : CUSTOM_GREEN, - color: 'white', + background: isAlert ? colors.red200 : colors.lightestGreen, + color: colors.white, marginTop: 10, padding: 4, paddingLeft: 8, diff --git a/packages/website/ts/components/ui/badge.tsx b/packages/website/ts/components/ui/badge.tsx index 15d5ea227..7f7ea006e 100644 --- a/packages/website/ts/components/ui/badge.tsx +++ b/packages/website/ts/components/ui/badge.tsx @@ -1,7 +1,6 @@ import * as _ from 'lodash'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; -import {Styles} from 'ts/types'; +import { Styles } from 'ts/types'; const styles: Styles = { badge: { @@ -43,14 +42,14 @@ export class Badge extends React.Component<BadgeProps, BadgeState> { <div className="p1 center" style={badgeStyle} - onMouseOver={this.setHoverState.bind(this, true)} - onMouseOut={this.setHoverState.bind(this, false)} + onMouseOver={this._setHoverState.bind(this, true)} + onMouseOut={this._setHoverState.bind(this, false)} > {this.props.title} </div> ); } - private setHoverState(isHovering: boolean) { + private _setHoverState(isHovering: boolean) { this.setState({ isHovering, }); diff --git a/packages/website/ts/components/ui/copy_icon.tsx b/packages/website/ts/components/ui/copy_icon.tsx index 5f8e6a060..df55e0922 100644 --- a/packages/website/ts/components/ui/copy_icon.tsx +++ b/packages/website/ts/components/ui/copy_icon.tsx @@ -1,9 +1,9 @@ import * as _ from 'lodash'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; import * as CopyToClipboard from 'react-copy-to-clipboard'; import * as ReactDOM from 'react-dom'; import ReactTooltip = require('react-tooltip'); +import { colors } from 'ts/utils/colors'; interface CopyIconProps { data: string; @@ -15,8 +15,8 @@ interface CopyIconState { } export class CopyIcon extends React.Component<CopyIconProps, CopyIconState> { - private copyTooltipTimeoutId: number; - private copyable: HTMLInputElement; + private _copyTooltipTimeoutId: number; + private _copyable: HTMLInputElement; constructor(props: CopyIconProps) { super(props); this.state = { @@ -25,57 +25,55 @@ export class CopyIcon extends React.Component<CopyIconProps, CopyIconState> { } public componentDidUpdate() { // Remove tooltip if hover away - if (!this.state.isHovering && this.copyTooltipTimeoutId) { - clearInterval(this.copyTooltipTimeoutId); - this.hideTooltip(); + if (!this.state.isHovering && this._copyTooltipTimeoutId) { + clearInterval(this._copyTooltipTimeoutId); + this._hideTooltip(); } } public render() { return ( <div className="inline-block"> - <CopyToClipboard text={this.props.data} onCopy={this.onCopy.bind(this)}> - <div - className="inline flex" - style={{cursor: 'pointer', color: colors.amber600}} - ref={this.setRefToProperty.bind(this)} - data-tip={true} - data-for="copy" - data-event="click" - data-iscapture={true} // This let's the click event continue to propogate - onMouseOver={this.setHoverState.bind(this, true)} - onMouseOut={this.setHoverState.bind(this, false)} - > - <div> - <i style={{fontSize: 15}} className="zmdi zmdi-copy" /> - </div> - {this.props.callToAction && - <div className="pl1">{this.props.callToAction}</div> - } + <CopyToClipboard text={this.props.data} onCopy={this._onCopy.bind(this)}> + <div + className="inline flex" + style={{ cursor: 'pointer', color: colors.amber600 }} + ref={this._setRefToProperty.bind(this)} + data-tip={true} + data-for="copy" + data-event="click" + data-iscapture={true} // This let's the click event continue to propogate + onMouseOver={this._setHoverState.bind(this, true)} + onMouseOut={this._setHoverState.bind(this, false)} + > + <div> + <i style={{ fontSize: 15 }} className="zmdi zmdi-copy" /> </div> - </CopyToClipboard> + {this.props.callToAction && <div className="pl1">{this.props.callToAction}</div>} + </div> + </CopyToClipboard> <ReactTooltip id="copy">Copied!</ReactTooltip> </div> ); } - private setRefToProperty(el: HTMLInputElement) { - this.copyable = el; + private _setRefToProperty(el: HTMLInputElement) { + this._copyable = el; } - private setHoverState(isHovering: boolean) { + private _setHoverState(isHovering: boolean) { this.setState({ isHovering, }); } - private onCopy() { - if (this.copyTooltipTimeoutId) { - clearInterval(this.copyTooltipTimeoutId); + private _onCopy() { + if (this._copyTooltipTimeoutId) { + clearInterval(this._copyTooltipTimeoutId); } const tooltipLifespanMs = 1000; - this.copyTooltipTimeoutId = window.setTimeout(() => { - this.hideTooltip(); + this._copyTooltipTimeoutId = window.setTimeout(() => { + this._hideTooltip(); }, tooltipLifespanMs); } - private hideTooltip() { - ReactTooltip.hide(ReactDOM.findDOMNode(this.copyable)); + private _hideTooltip() { + ReactTooltip.hide(ReactDOM.findDOMNode(this._copyable)); } } diff --git a/packages/website/ts/components/ui/drop_down_menu_item.tsx b/packages/website/ts/components/ui/drop_down_menu_item.tsx index 05b88f7ce..a578fb4f9 100644 --- a/packages/website/ts/components/ui/drop_down_menu_item.tsx +++ b/packages/website/ts/components/ui/drop_down_menu_item.tsx @@ -1,16 +1,10 @@ import * as _ from 'lodash'; import Menu from 'material-ui/Menu'; -import MenuItem from 'material-ui/MenuItem'; import Popover from 'material-ui/Popover'; import * as React from 'react'; -import {Link} from 'react-router-dom'; -import { - Link as ScrollLink, -} from 'react-scroll'; -import {Styles, WebsitePaths} from 'ts/types'; +import { colors } from 'ts/utils/colors'; const CHECK_CLOSE_POPOVER_INTERVAL_MS = 300; -const CUSTOM_LIGHT_GRAY = '#848484'; const DEFAULT_STYLE = { fontSize: 14, }; @@ -34,8 +28,8 @@ export class DropDownMenuItem extends React.Component<DropDownMenuItemProps, Dro menuItemStyle: DEFAULT_STYLE, isNightVersion: false, }; - private isHovering: boolean; - private popoverCloseCheckIntervalId: number; + private _isHovering: boolean; + private _popoverCloseCheckIntervalId: number; constructor(props: DropDownMenuItemProps) { super(props); this.state = { @@ -43,73 +37,66 @@ export class DropDownMenuItem extends React.Component<DropDownMenuItemProps, Dro }; } public componentDidMount() { - this.popoverCloseCheckIntervalId = window.setInterval(() => { - this.checkIfShouldClosePopover(); + this._popoverCloseCheckIntervalId = window.setInterval(() => { + this._checkIfShouldClosePopover(); }, CHECK_CLOSE_POPOVER_INTERVAL_MS); } public componentWillUnmount() { - window.clearInterval(this.popoverCloseCheckIntervalId); + window.clearInterval(this._popoverCloseCheckIntervalId); } public render() { const colorStyle = this.props.isNightVersion ? 'white' : this.props.style.color; return ( <div - style={{...this.props.style, color: colorStyle}} - onMouseEnter={this.onHover.bind(this)} - onMouseLeave={this.onHoverOff.bind(this)} + style={{ ...this.props.style, color: colorStyle }} + onMouseEnter={this._onHover.bind(this)} + onMouseLeave={this._onHoverOff.bind(this)} > <div className="flex relative"> - <div style={{paddingRight: 10}}> - {this.props.title} - </div> - <div className="absolute" style={{paddingLeft: 3, right: 3, top: -2}}> - <i className="zmdi zmdi-caret-right" style={{fontSize: 22}} /> + <div style={{ paddingRight: 10 }}>{this.props.title}</div> + <div className="absolute" style={{ paddingLeft: 3, right: 3, top: -2 }}> + <i className="zmdi zmdi-caret-right" style={{ fontSize: 22 }} /> </div> </div> <Popover open={this.state.isDropDownOpen} anchorEl={this.state.anchorEl} - anchorOrigin={{horizontal: 'middle', vertical: 'bottom'}} - targetOrigin={{horizontal: 'middle', vertical: 'top'}} - onRequestClose={this.closePopover.bind(this)} + anchorOrigin={{ horizontal: 'middle', vertical: 'bottom' }} + targetOrigin={{ horizontal: 'middle', vertical: 'top' }} + onRequestClose={this._closePopover.bind(this)} useLayerForClickAway={false} > - <div - onMouseEnter={this.onHover.bind(this)} - onMouseLeave={this.onHoverOff.bind(this)} - > - <Menu style={{color: CUSTOM_LIGHT_GRAY}}> - {this.props.subMenuItems} - </Menu> + <div onMouseEnter={this._onHover.bind(this)} onMouseLeave={this._onHoverOff.bind(this)}> + <Menu style={{ color: colors.grey }}>{this.props.subMenuItems}</Menu> </div> </Popover> </div> ); } - private onHover(event: React.FormEvent<HTMLInputElement>) { - this.isHovering = true; - this.checkIfShouldOpenPopover(event); + private _onHover(event: React.FormEvent<HTMLInputElement>) { + this._isHovering = true; + this._checkIfShouldOpenPopover(event); } - private checkIfShouldOpenPopover(event: React.FormEvent<HTMLInputElement>) { + private _checkIfShouldOpenPopover(event: React.FormEvent<HTMLInputElement>) { if (this.state.isDropDownOpen) { return; // noop } this.setState({ - isDropDownOpen: true, - anchorEl: event.currentTarget, + isDropDownOpen: true, + anchorEl: event.currentTarget, }); } - private onHoverOff(event: React.FormEvent<HTMLInputElement>) { - this.isHovering = false; + private _onHoverOff(event: React.FormEvent<HTMLInputElement>) { + this._isHovering = false; } - private checkIfShouldClosePopover() { - if (!this.state.isDropDownOpen || this.isHovering) { + private _checkIfShouldClosePopover() { + if (!this.state.isDropDownOpen || this._isHovering) { return; // noop } - this.closePopover(); + this._closePopover(); } - private closePopover() { + private _closePopover() { this.setState({ isDropDownOpen: false, }); diff --git a/packages/website/ts/components/ui/ethereum_address.tsx b/packages/website/ts/components/ui/ethereum_address.tsx index b3bc0bc59..b75d97e39 100644 --- a/packages/website/ts/components/ui/ethereum_address.tsx +++ b/packages/website/ts/components/ui/ethereum_address.tsx @@ -1,8 +1,8 @@ import * as React from 'react'; import ReactTooltip = require('react-tooltip'); -import {EtherScanIcon} from 'ts/components/ui/etherscan_icon'; -import {EtherscanLinkSuffixes} from 'ts/types'; -import {utils} from 'ts/utils/utils'; +import { EtherScanIcon } from 'ts/components/ui/etherscan_icon'; +import { EtherscanLinkSuffixes } from 'ts/types'; +import { utils } from 'ts/utils/utils'; interface EthereumAddressProps { address: string; @@ -14,19 +14,14 @@ export const EthereumAddress = (props: EthereumAddressProps) => { const truncatedAddress = utils.getAddressBeginAndEnd(props.address); return ( <div> - <div - className="inline" - style={{fontSize: 13}} - data-tip={true} - data-for={tooltipId} - > + <div className="inline" style={{ fontSize: 13 }} data-tip={true} data-for={tooltipId}> {truncatedAddress} </div> <div className="pl1 inline"> <EtherScanIcon addressOrTxHash={props.address} networkId={props.networkId} - etherscanLinkSuffixes={EtherscanLinkSuffixes.address} + etherscanLinkSuffixes={EtherscanLinkSuffixes.Address} /> </div> <ReactTooltip id={tooltipId}>{props.address}</ReactTooltip> diff --git a/packages/website/ts/components/ui/etherscan_icon.tsx b/packages/website/ts/components/ui/etherscan_icon.tsx index 9b4d172f1..3b17bd0fa 100644 --- a/packages/website/ts/components/ui/etherscan_icon.tsx +++ b/packages/website/ts/components/ui/etherscan_icon.tsx @@ -1,9 +1,9 @@ import * as _ from 'lodash'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; import ReactTooltip = require('react-tooltip'); -import {EtherscanLinkSuffixes} from 'ts/types'; -import {utils} from 'ts/utils/utils'; +import { EtherscanLinkSuffixes } from 'ts/types'; +import { colors } from 'ts/utils/colors'; +import { utils } from 'ts/utils/utils'; interface EtherScanIconProps { addressOrTxHash: string; @@ -13,38 +13,29 @@ interface EtherScanIconProps { export const EtherScanIcon = (props: EtherScanIconProps) => { const etherscanLinkIfExists = utils.getEtherScanLinkIfExists( - props.addressOrTxHash, props.networkId, EtherscanLinkSuffixes.address, + props.addressOrTxHash, + props.networkId, + EtherscanLinkSuffixes.Address, ); const transactionTooltipId = `${props.addressOrTxHash}-etherscan-icon-tooltip`; return ( <div className="inline"> - {!_.isUndefined(etherscanLinkIfExists) ? - <a - href={etherscanLinkIfExists} - target="_blank" - > + {!_.isUndefined(etherscanLinkIfExists) ? ( + <a href={etherscanLinkIfExists} target="_blank"> {renderIcon()} - </a> : - <div - className="inline" - data-tip={true} - data-for={transactionTooltipId} - > + </a> + ) : ( + <div className="inline" data-tip={true} data-for={transactionTooltipId}> {renderIcon()} <ReactTooltip id={transactionTooltipId}> Your network (id: {props.networkId}) is not supported by Etherscan </ReactTooltip> </div> - } + )} </div> ); }; function renderIcon() { - return ( - <i - style={{color: colors.amber600}} - className="zmdi zmdi-open-in-new" - /> - ); + return <i style={{ color: colors.amber600 }} className="zmdi zmdi-open-in-new" />; } diff --git a/packages/website/ts/components/ui/fake_text_field.tsx b/packages/website/ts/components/ui/fake_text_field.tsx index 90bc47f01..f3d9410f6 100644 --- a/packages/website/ts/components/ui/fake_text_field.tsx +++ b/packages/website/ts/components/ui/fake_text_field.tsx @@ -1,7 +1,6 @@ -import {colors} from 'material-ui/styles'; import * as React from 'react'; -import {InputLabel} from 'ts/components/ui/input_label'; -import {Styles} from 'ts/types'; +import { InputLabel } from 'ts/components/ui/input_label'; +import { Styles } from 'ts/types'; const styles: Styles = { hr: { @@ -26,7 +25,7 @@ export function FakeTextField(props: FakeTextFieldProps) { return ( <div className="relative"> {props.label !== '' && <InputLabel text={props.label} />} - <div className="pb2" style={{height: 23}}> + <div className="pb2" style={{ height: 23 }}> {props.children} </div> <hr style={styles.hr} /> diff --git a/packages/website/ts/components/ui/flash_message.tsx b/packages/website/ts/components/ui/flash_message.tsx index ab4edbbb0..2cb1fc764 100644 --- a/packages/website/ts/components/ui/flash_message.tsx +++ b/packages/website/ts/components/ui/flash_message.tsx @@ -1,13 +1,13 @@ import * as _ from 'lodash'; import Snackbar from 'material-ui/Snackbar'; import * as React from 'react'; -import {Dispatcher} from 'ts/redux/dispatcher'; +import { Dispatcher } from 'ts/redux/dispatcher'; const SHOW_DURATION_MS = 4000; interface FlashMessageProps { dispatcher: Dispatcher; - flashMessage?: string|React.ReactNode; + flashMessage?: string | React.ReactNode; showDurationMs?: number; bodyStyle?: React.CSSProperties; } @@ -26,7 +26,7 @@ export class FlashMessage extends React.Component<FlashMessageProps, FlashMessag open={true} message={this.props.flashMessage} autoHideDuration={this.props.showDurationMs} - onRequestClose={this.onClose.bind(this)} + onRequestClose={this._onClose.bind(this)} bodyStyle={this.props.bodyStyle} /> ); @@ -34,7 +34,7 @@ export class FlashMessage extends React.Component<FlashMessageProps, FlashMessag return null; } } - private onClose() { + private _onClose() { this.props.dispatcher.hideFlashMessage(); } } diff --git a/packages/website/ts/components/ui/help_tooltip.tsx b/packages/website/ts/components/ui/help_tooltip.tsx index 003b795ef..d827eebb9 100644 --- a/packages/website/ts/components/ui/help_tooltip.tsx +++ b/packages/website/ts/components/ui/help_tooltip.tsx @@ -9,13 +9,13 @@ interface HelpTooltipProps { export const HelpTooltip = (props: HelpTooltipProps) => { return ( <div - style={{...props.style}} + style={{ ...props.style }} className="inline-block" data-tip={props.explanation} data-for="helpTooltip" data-multiline={true} > - <i style={{fontSize: 16}} className="zmdi zmdi-help" /> + <i style={{ fontSize: 16 }} className="zmdi zmdi-help" /> <ReactTooltip id="helpTooltip" /> </div> ); diff --git a/packages/website/ts/components/ui/identicon.tsx b/packages/website/ts/components/ui/identicon.tsx index a741ae43b..bad6c2a78 100644 --- a/packages/website/ts/components/ui/identicon.tsx +++ b/packages/website/ts/components/ui/identicon.tsx @@ -1,7 +1,7 @@ import blockies = require('blockies'); import * as _ from 'lodash'; import * as React from 'react'; -import {constants} from 'ts/utils/constants'; +import { constants } from 'ts/utils/constants'; interface IdenticonProps { address: string; @@ -27,9 +27,21 @@ export class Identicon extends React.Component<IdenticonProps, IdenticonState> { return ( <div className="circle mx-auto relative transitionFix" - style={{width: diameter, height: diameter, overflow: 'hidden', ...this.props.style}} + style={{ + width: diameter, + height: diameter, + overflow: 'hidden', + ...this.props.style, + }} > - <img src={icon.toDataURL()} style={{width: diameter, height: diameter, imageRendering: 'pixelated'}}/> + <img + src={icon.toDataURL()} + style={{ + width: diameter, + height: diameter, + imageRendering: 'pixelated', + }} + /> </div> ); } diff --git a/packages/website/ts/components/ui/input_label.tsx b/packages/website/ts/components/ui/input_label.tsx index 852097519..e2009ad20 100644 --- a/packages/website/ts/components/ui/input_label.tsx +++ b/packages/website/ts/components/ui/input_label.tsx @@ -1,5 +1,5 @@ -import {colors} from 'material-ui/styles'; import * as React from 'react'; +import { colors } from 'ts/utils/colors'; export interface InputLabelProps { text: string | Element | React.ReactNode; @@ -7,7 +7,7 @@ export interface InputLabelProps { const styles = { label: { - color: colors.grey500, + color: colors.grey, fontSize: 12, pointerEvents: 'none', textAlign: 'left', @@ -21,7 +21,5 @@ const styles = { }; export const InputLabel = (props: InputLabelProps) => { - return ( - <label style={styles.label}>{props.text}</label> - ); + return <label style={styles.label}>{props.text}</label>; }; diff --git a/packages/website/ts/components/ui/labeled_switcher.tsx b/packages/website/ts/components/ui/labeled_switcher.tsx deleted file mode 100644 index 80a8fbe94..000000000 --- a/packages/website/ts/components/ui/labeled_switcher.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import * as _ from 'lodash'; -import {colors} from 'material-ui/styles'; -import * as React from 'react'; - -const CUSTOM_BLUE = '#63A6F1'; - -interface LabeledSwitcherProps { - labelLeft: string; - labelRight: string; - isLeftInitiallySelected: boolean; - onLeftLabelClickAsync: () => Promise<boolean>; - onRightLabelClickAsync: () => Promise<boolean>; -} - -interface LabeledSwitcherState { - isLeftSelected: boolean; -} - -export class LabeledSwitcher extends React.Component<LabeledSwitcherProps, LabeledSwitcherState> { - constructor(props: LabeledSwitcherProps) { - super(props); - this.state = { - isLeftSelected: props.isLeftInitiallySelected, - }; - } - public render() { - const isLeft = true; - return ( - <div - className="rounded clearfix" - > - {this.renderLabel(this.props.labelLeft, isLeft, this.state.isLeftSelected)} - {this.renderLabel(this.props.labelRight, !isLeft, !this.state.isLeftSelected)} - </div> - ); - } - private renderLabel(title: string, isLeft: boolean, isSelected: boolean) { - const borderStyle = `2px solid ${isSelected ? '#4F8BCF' : '#DADADA'}`; - const style = { - cursor: 'pointer', - backgroundColor: isSelected ? CUSTOM_BLUE : colors.grey200, - color: isSelected ? 'white' : '#A5A5A5', - boxShadow: isSelected ? `inset 0px 0px 4px #4083CE` : 'inset 0px 0px 4px #F7F6F6', - borderTop: borderStyle, - borderBottom: borderStyle, - [isLeft ? 'borderLeft' : 'borderRight']: borderStyle, - paddingTop: 12, - paddingBottom: 12, - }; - return ( - <div - className={`col col-6 center p1 ${isLeft ? 'rounded-left' : 'rounded-right'}`} - style={style} - onClick={this.onLabelClickAsync.bind(this, isLeft)} - > - {title} - </div> - ); - } - private async onLabelClickAsync(isLeft: boolean): Promise<void> { - this.setState({ - isLeftSelected: isLeft, - }); - const didSucceed = isLeft ? - await this.props.onLeftLabelClickAsync() : - await this.props.onRightLabelClickAsync(); - if (!didSucceed) { - this.setState({ - isLeftSelected: !isLeft, - }); - } - } -} diff --git a/packages/website/ts/components/ui/lifecycle_raised_button.tsx b/packages/website/ts/components/ui/lifecycle_raised_button.tsx index cba94ca8c..8ff856a75 100644 --- a/packages/website/ts/components/ui/lifecycle_raised_button.tsx +++ b/packages/website/ts/components/ui/lifecycle_raised_button.tsx @@ -1,25 +1,24 @@ import * as _ from 'lodash'; import RaisedButton from 'material-ui/RaisedButton'; import * as React from 'react'; -import {Blockchain} from 'ts/blockchain'; -import {Token} from 'ts/types'; -import {utils} from 'ts/utils/utils'; +import { colors } from 'ts/utils/colors'; +import { utils } from 'ts/utils/utils'; const COMPLETE_STATE_SHOW_LENGTH_MS = 2000; enum ButtonState { - READY, - LOADING, - COMPLETE, + READY, + LOADING, + COMPLETE, } interface LifeCycleRaisedButtonProps { isHidden?: boolean; isDisabled?: boolean; isPrimary?: boolean; - labelReady: React.ReactNode|string; - labelLoading: React.ReactNode|string; - labelComplete: React.ReactNode|string; + labelReady: React.ReactNode | string; + labelLoading: React.ReactNode | string; + labelComplete: React.ReactNode | string; onClickAsyncFn: () => Promise<boolean>; backgroundColor?: string; labelColor?: string; @@ -29,15 +28,14 @@ interface LifeCycleRaisedButtonState { buttonState: ButtonState; } -export class LifeCycleRaisedButton extends - React.Component<LifeCycleRaisedButtonProps, LifeCycleRaisedButtonState> { +export class LifeCycleRaisedButton extends React.Component<LifeCycleRaisedButtonProps, LifeCycleRaisedButtonState> { public static defaultProps: Partial<LifeCycleRaisedButtonProps> = { isDisabled: false, - backgroundColor: 'white', - labelColor: 'rgb(97, 97, 97)', + backgroundColor: colors.white, + labelColor: colors.darkGrey, }; - private buttonTimeoutId: number; - private didUnmount: boolean; + private _buttonTimeoutId: number; + private _didUnmount: boolean; constructor(props: LifeCycleRaisedButtonProps) { super(props); this.state = { @@ -45,8 +43,8 @@ export class LifeCycleRaisedButton extends }; } public componentWillUnmount() { - clearTimeout(this.buttonTimeoutId); - this.didUnmount = true; + clearTimeout(this._buttonTimeoutId); + this._didUnmount = true; } public render() { if (this.props.isHidden) { @@ -71,7 +69,7 @@ export class LifeCycleRaisedButton extends <RaisedButton primary={this.props.isPrimary} label={label} - style={{width: '100%'}} + style={{ width: '100%' }} backgroundColor={this.props.backgroundColor} labelColor={this.props.labelColor} onTouchTap={this.onClickAsync.bind(this)} @@ -84,14 +82,14 @@ export class LifeCycleRaisedButton extends buttonState: ButtonState.LOADING, }); const didSucceed = await this.props.onClickAsyncFn(); - if (this.didUnmount) { + if (this._didUnmount) { return; // noop since unmount called before async callback returned. } if (didSucceed) { this.setState({ buttonState: ButtonState.COMPLETE, }); - this.buttonTimeoutId = window.setTimeout(() => { + this._buttonTimeoutId = window.setTimeout(() => { this.setState({ buttonState: ButtonState.READY, }); diff --git a/packages/website/ts/components/ui/loading.tsx b/packages/website/ts/components/ui/loading.tsx index 83636b5ff..aa319e9e9 100644 --- a/packages/website/ts/components/ui/loading.tsx +++ b/packages/website/ts/components/ui/loading.tsx @@ -1,9 +1,9 @@ import * as _ from 'lodash'; import Paper from 'material-ui/Paper'; import * as React from 'react'; -import {DefaultPlayer as Video} from 'react-html5video'; +import { DefaultPlayer as Video } from 'react-html5video'; import 'react-html5video/dist/styles.css'; -import {utils} from 'ts/utils/utils'; +import { utils } from 'ts/utils/utils'; interface LoadingProps {} @@ -12,11 +12,12 @@ interface LoadingState {} export class Loading extends React.Component<LoadingProps, LoadingState> { public render() { return ( - <div className="pt4 sm-px2 sm-pt2 sm-m1" style={{height: 500}}> - <Paper className="mx-auto" style={{maxWidth: 400}}> - {utils.isUserOnMobile() ? - <img className="p1" src="/gifs/0xAnimation.gif" width="96%" /> : - <div style={{pointerEvents: 'none'}}> + <div className="pt4 sm-px2 sm-pt2 sm-m1" style={{ height: 500 }}> + <Paper className="mx-auto" style={{ maxWidth: 400 }}> + {utils.isUserOnMobile() ? ( + <img className="p1" src="/gifs/0xAnimation.gif" width="96%" /> + ) : ( + <div style={{ pointerEvents: 'none' }}> <Video autoPlay={true} loop={true} @@ -27,8 +28,10 @@ export class Loading extends React.Component<LoadingProps, LoadingState> { <source src="/videos/0xAnimation.mp4" type="video/mp4" /> </Video> </div> - } - <div className="center pt2" style={{paddingBottom: 11}}>Connecting to the blockchain...</div> + )} + <div className="center pt2" style={{ paddingBottom: 11 }}> + Connecting to the blockchain... + </div> </Paper> </div> ); diff --git a/packages/website/ts/components/ui/menu_item.tsx b/packages/website/ts/components/ui/menu_item.tsx index 862f28457..3482f436c 100644 --- a/packages/website/ts/components/ui/menu_item.tsx +++ b/packages/website/ts/components/ui/menu_item.tsx @@ -1,9 +1,6 @@ import * as _ from 'lodash'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; -import {Link} from 'react-router-dom'; -import {Styles} from 'ts/types'; -import {constants} from 'ts/utils/constants'; +import { Link } from 'react-router-dom'; interface MenuItemProps { to: string; @@ -33,20 +30,20 @@ export class MenuItem extends React.Component<MenuItemProps, MenuItemState> { opacity: this.state.isHovering ? 0.5 : 1, }; return ( - <Link to={this.props.to} style={{textDecoration: 'none', ...this.props.style}}> + <Link to={this.props.to} style={{ textDecoration: 'none', ...this.props.style }}> <div onClick={this.props.onClick.bind(this)} className={`mx-auto ${this.props.className}`} style={menuItemStyles} - onMouseEnter={this.onToggleHover.bind(this, true)} - onMouseLeave={this.onToggleHover.bind(this, false)} + onMouseEnter={this._onToggleHover.bind(this, true)} + onMouseLeave={this._onToggleHover.bind(this, false)} > {this.props.children} </div> </Link> ); } - private onToggleHover(isHovering: boolean) { + private _onToggleHover(isHovering: boolean) { this.setState({ isHovering, }); diff --git a/packages/website/ts/components/ui/party.tsx b/packages/website/ts/components/ui/party.tsx index 5bafa6071..ca2577b61 100644 --- a/packages/website/ts/components/ui/party.tsx +++ b/packages/website/ts/components/ui/party.tsx @@ -1,16 +1,14 @@ import * as _ from 'lodash'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; import ReactTooltip = require('react-tooltip'); -import {EthereumAddress} from 'ts/components/ui/ethereum_address'; -import {Identicon} from 'ts/components/ui/identicon'; -import {EtherscanLinkSuffixes} from 'ts/types'; -import {utils} from 'ts/utils/utils'; +import { EthereumAddress } from 'ts/components/ui/ethereum_address'; +import { Identicon } from 'ts/components/ui/identicon'; +import { EtherscanLinkSuffixes } from 'ts/types'; +import { colors } from 'ts/utils/colors'; +import { utils } from 'ts/utils/utils'; -const MIN_ADDRESS_WIDTH = 60; const IMAGE_DIMENSION = 100; const IDENTICON_DIAMETER = 95; -const CHECK_MARK_GREEN = 'rgb(0, 195, 62)'; interface PartyProps { label: string; @@ -33,10 +31,7 @@ export class Party extends React.Component<PartyProps, PartyState> { public render() { const label = this.props.label; const address = this.props.address; - const tooltipId = `${label}-${address}-tooltip`; const identiconDiameter = this.props.identiconDiameter; - const addressWidth = identiconDiameter > MIN_ADDRESS_WIDTH ? - identiconDiameter : MIN_ADDRESS_WIDTH; const emptyIdenticonStyles = { width: identiconDiameter, height: identiconDiameter, @@ -49,100 +44,94 @@ export class Party extends React.Component<PartyProps, PartyState> { height: IMAGE_DIMENSION, }; const etherscanLinkIfExists = utils.getEtherScanLinkIfExists( - this.props.address, this.props.networkId, EtherscanLinkSuffixes.address, + this.props.address, + this.props.networkId, + EtherscanLinkSuffixes.Address, ); const isRegistered = this.props.isInTokenRegistry; const registeredTooltipId = `${this.props.address}-${isRegistered}-registeredTooltip`; const uniqueNameAndSymbolTooltipId = `${this.props.address}-${isRegistered}-uniqueTooltip`; return ( - <div style={{overflow: 'hidden'}}> + <div style={{ overflow: 'hidden' }}> <div className="pb1 center">{label}</div> - {_.isEmpty(address) ? - <div - className="circle mx-auto" - style={emptyIdenticonStyles} - /> : - <a - href={etherscanLinkIfExists} - target="_blank" - > - {isRegistered && !_.isUndefined(this.props.alternativeImage) ? - <img - style={tokenImageStyle} - src={this.props.alternativeImage} - /> : - <div - className="mx-auto" - style={{height: identiconDiameter, width: identiconDiameter}} - > - <Identicon - address={this.props.address} - diameter={identiconDiameter} - style={this.props.identiconStyle} - /> - </div> - } - </a> - } - <div - className="mx-auto center pt1" - > - <div style={{height: 25}}> + {_.isEmpty(address) ? ( + <div className="circle mx-auto" style={emptyIdenticonStyles} /> + ) : ( + <a href={etherscanLinkIfExists} target="_blank"> + {isRegistered && !_.isUndefined(this.props.alternativeImage) ? ( + <img style={tokenImageStyle} src={this.props.alternativeImage} /> + ) : ( + <div className="mx-auto" style={{ height: identiconDiameter, width: identiconDiameter }}> + <Identicon + address={this.props.address} + diameter={identiconDiameter} + style={this.props.identiconStyle} + /> + </div> + )} + </a> + )} + <div className="mx-auto center pt1"> + <div style={{ height: 25 }}> <EthereumAddress address={address} networkId={this.props.networkId} /> </div> - {!_.isUndefined(this.props.isInTokenRegistry) && + {!_.isUndefined(this.props.isInTokenRegistry) && ( <div> <div data-tip={true} data-for={registeredTooltipId} className="mx-auto" - style={{fontSize: 13, width: 127}} + style={{ fontSize: 13, width: 127 }} > - <span style={{color: isRegistered ? CHECK_MARK_GREEN : colors.red500}}> + <span + style={{ + color: isRegistered ? colors.brightGreen : colors.red500, + }} + > <i className={`zmdi ${isRegistered ? 'zmdi-check-circle' : 'zmdi-alert-triangle'}`} /> </span>{' '} <span>{isRegistered ? 'Registered' : 'Unregistered'} token</span> <ReactTooltip id={registeredTooltipId}> - {isRegistered ? + {isRegistered ? ( <div> This token address was found in the token registry<br /> smart contract and is therefore believed to be a<br /> legitimate token. - </div> : + </div> + ) : ( <div> This token is not included in the token registry<br /> smart contract. We cannot guarantee the legitimacy<br /> of this token. Make sure to verify its address on Etherscan. </div> - } + )} </ReactTooltip> </div> </div> - } - {!_.isUndefined(this.props.hasUniqueNameAndSymbol) && !this.props.hasUniqueNameAndSymbol && - <div> - <div - data-tip={true} - data-for={uniqueNameAndSymbolTooltipId} - className="mx-auto" - style={{fontSize: 13, width: 127}} - > - <span style={{color: colors.red500}}> - <i - className="zmdi zmdi-alert-octagon" - /> - </span>{' '} - <span>Suspicious token</span> - <ReactTooltip id={uniqueNameAndSymbolTooltipId}> - This token shares it's name, symbol or both with<br /> - a token in the 0x Token Registry but it has a different<br /> - smart contract address. This is most likely a scam token! - </ReactTooltip> + )} + {!_.isUndefined(this.props.hasUniqueNameAndSymbol) && + !this.props.hasUniqueNameAndSymbol && ( + <div> + <div + data-tip={true} + data-for={uniqueNameAndSymbolTooltipId} + className="mx-auto" + style={{ fontSize: 13, width: 127 }} + > + <span style={{ color: colors.red500 }}> + <i className="zmdi zmdi-alert-octagon" /> + </span>{' '} + <span>Suspicious token</span> + <ReactTooltip id={uniqueNameAndSymbolTooltipId}> + This token shares it's name, symbol or both with<br /> + a token in the 0x Token Registry but it has a different<br /> + smart contract address. This is most likely a scam token! + </ReactTooltip> + </div> </div> - </div> - } + )} </div> </div> ); diff --git a/packages/website/ts/components/ui/required_label.tsx b/packages/website/ts/components/ui/required_label.tsx index db69d7278..a5e7a22ce 100644 --- a/packages/website/ts/components/ui/required_label.tsx +++ b/packages/website/ts/components/ui/required_label.tsx @@ -1,15 +1,15 @@ -import {colors} from 'material-ui/styles'; import * as React from 'react'; +import { colors } from 'ts/utils/colors'; export interface RequiredLabelProps { - label: string|React.ReactNode; + label: string | React.ReactNode; } export const RequiredLabel = (props: RequiredLabelProps) => { return ( <span> {props.label} - <span style={{color: colors.red600}}>*</span> + <span style={{ color: colors.red600 }}>*</span> </span> ); }; diff --git a/packages/website/ts/components/ui/simple_loading.tsx b/packages/website/ts/components/ui/simple_loading.tsx index d55d7851d..81744196d 100644 --- a/packages/website/ts/components/ui/simple_loading.tsx +++ b/packages/website/ts/components/ui/simple_loading.tsx @@ -1,5 +1,4 @@ import CircularProgress from 'material-ui/CircularProgress'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; export interface SimpleLoadingProps { @@ -8,15 +7,10 @@ export interface SimpleLoadingProps { export const SimpleLoading = (props: SimpleLoadingProps) => { return ( - <div className="mx-auto pt3" style={{maxWidth: 400, height: 409}}> - <div - className="relative" - style={{top: '50%', transform: 'translateY(-50%)', height: 95}} - > + <div className="mx-auto pt3" style={{ maxWidth: 400, height: 409 }}> + <div className="relative" style={{ top: '50%', transform: 'translateY(-50%)', height: 95 }}> <CircularProgress /> - <div className="pt3 pb3"> - {props.message} - </div> + <div className="pt3 pb3">{props.message}</div> </div> </div> ); diff --git a/packages/website/ts/components/ui/swap_icon.tsx b/packages/website/ts/components/ui/swap_icon.tsx index 2e6ae89bb..c41592287 100644 --- a/packages/website/ts/components/ui/swap_icon.tsx +++ b/packages/website/ts/components/ui/swap_icon.tsx @@ -1,7 +1,6 @@ import * as _ from 'lodash'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; -import {constants} from 'ts/utils/constants'; +import { colors } from 'ts/utils/colors'; interface SwapIconProps { swapTokensFn: () => void; @@ -26,19 +25,16 @@ export class SwapIcon extends React.Component<SwapIconProps, SwapIconState> { return ( <div className="mx-auto pt4" - style={{cursor: 'pointer', height: 50, width: 37.5}} + style={{ cursor: 'pointer', height: 50, width: 37.5 }} onClick={this.props.swapTokensFn} - onMouseEnter={this.onToggleHover.bind(this, true)} - onMouseLeave={this.onToggleHover.bind(this, false)} + onMouseEnter={this._onToggleHover.bind(this, true)} + onMouseLeave={this._onToggleHover.bind(this, false)} > - <i - style={swapStyles} - className="zmdi zmdi-swap" - /> + <i style={swapStyles} className="zmdi zmdi-swap" /> </div> ); } - private onToggleHover(isHovering: boolean) { + private _onToggleHover(isHovering: boolean) { this.setState({ isHovering, }); diff --git a/packages/website/ts/components/ui/token_icon.tsx b/packages/website/ts/components/ui/token_icon.tsx index d3a7c9a8c..ff57a96de 100644 --- a/packages/website/ts/components/ui/token_icon.tsx +++ b/packages/website/ts/components/ui/token_icon.tsx @@ -1,7 +1,7 @@ import * as _ from 'lodash'; import * as React from 'react'; -import {Identicon} from 'ts/components/ui/identicon'; -import {Token} from 'ts/types'; +import { Identicon } from 'ts/components/ui/identicon'; +import { Token } from 'ts/types'; interface TokenIconProps { token: Token; @@ -16,13 +16,11 @@ export class TokenIcon extends React.Component<TokenIconProps, TokenIconState> { const diameter = this.props.diameter; return ( <div> - {(token.isRegistered && !_.isUndefined(token.iconUrl)) ? - <img - style={{width: diameter, height: diameter}} - src={token.iconUrl} - /> : + {token.isRegistered && !_.isUndefined(token.iconUrl) ? ( + <img style={{ width: diameter, height: diameter }} src={token.iconUrl} /> + ) : ( <Identicon address={token.address} diameter={diameter} /> - } + )} </div> ); } diff --git a/packages/website/ts/components/visual_order.tsx b/packages/website/ts/components/visual_order.tsx index 037a321ff..092954086 100644 --- a/packages/website/ts/components/visual_order.tsx +++ b/packages/website/ts/components/visual_order.tsx @@ -1,10 +1,9 @@ -import {ZeroEx} from '0x.js'; +import { ZeroEx } from '0x.js'; import * as _ from 'lodash'; import * as React from 'react'; -import {Party} from 'ts/components/ui/party'; -import {AssetToken, Token, TokenByAddress} from 'ts/types'; -import {constants} from 'ts/utils/constants'; -import {utils} from 'ts/utils/utils'; +import { Party } from 'ts/components/ui/party'; +import { AssetToken, Token, TokenByAddress } from 'ts/types'; +import { utils } from 'ts/utils/utils'; const PRECISION = 5; @@ -43,13 +42,13 @@ export class VisualOrder extends React.Component<VisualOrderProps, VisualOrderSt </div> <div className="col col-2 center pt1"> <div className="pb1"> - {this.renderAmount(this.props.takerAssetToken, this.props.takerToken)} + {this._renderAmount(this.props.takerAssetToken, this.props.takerToken)} </div> <div className="lg-p2 md-p2 sm-p1"> - <img src="/images/trade_arrows.png" style={{width: 47}} /> + <img src="/images/trade_arrows.png" style={{ width: 47 }} /> </div> <div className="pt1"> - {this.renderAmount(this.props.makerAssetToken, this.props.makerToken)} + {this._renderAmount(this.props.makerAssetToken, this.props.makerToken)} </div> </div> <div className="col col-5 center"> @@ -66,10 +65,10 @@ export class VisualOrder extends React.Component<VisualOrderProps, VisualOrderSt </div> ); } - private renderAmount(assetToken: AssetToken, token: Token) { + private _renderAmount(assetToken: AssetToken, token: Token) { const unitAmount = ZeroEx.toUnitAmount(assetToken.amount, token.decimals); return ( - <div style={{fontSize: 13}}> + <div style={{ fontSize: 13 }}> {unitAmount.toNumber().toFixed(PRECISION)} {token.symbol} </div> ); diff --git a/packages/website/ts/containers/connect_documentation.tsx b/packages/website/ts/containers/connect_documentation.tsx index b074d955b..3e02a7d05 100644 --- a/packages/website/ts/containers/connect_documentation.tsx +++ b/packages/website/ts/containers/connect_documentation.tsx @@ -1,18 +1,14 @@ -import BigNumber from 'bignumber.js'; import * as _ from 'lodash'; import * as React from 'react'; -import {connect} from 'react-redux'; -import {Dispatch, Store as ReduxStore} from 'redux'; -import {Blockchain} from 'ts/blockchain'; -import {DocsInfo} from 'ts/pages/documentation/docs_info'; -import { - Documentation as DocumentationComponent, - DocumentationAllProps, -} from 'ts/pages/documentation/documentation'; -import {Dispatcher} from 'ts/redux/dispatcher'; -import {State} from 'ts/redux/reducer'; -import {DocsInfoConfig, WebsitePaths} from 'ts/types'; -import {typeDocUtils} from 'ts/utils/typedoc_utils'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; +import { DocsInfo } from 'ts/pages/documentation/docs_info'; +import { Documentation as DocumentationComponent, DocumentationAllProps } from 'ts/pages/documentation/documentation'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { State } from 'ts/redux/reducer'; +import { DocsInfoConfig, WebsitePaths } from 'ts/types'; +import { constants } from 'ts/utils/constants'; +import { typeDocUtils } from 'ts/utils/typedoc_utils'; /* tslint:disable:no-var-requires */ const IntroMarkdown = require('md/docs/connect/introduction'); @@ -23,7 +19,8 @@ const connectDocSections = { introduction: 'introduction', installation: 'installation', httpClient: 'httpClient', - types: 'types', + webSocketOrderbookChannel: 'webSocketOrderbookChannel', + types: constants.TYPES_SECTION_NAME, }; const docsInfoConfig: DocsInfoConfig = { @@ -33,18 +30,11 @@ const docsInfoConfig: DocsInfoConfig = { websitePath: WebsitePaths.Connect, docsJsonRoot: 'https://s3.amazonaws.com/connect-docs-jsons', menu: { - introduction: [ - connectDocSections.introduction, - ], - install: [ - connectDocSections.installation, - ], - httpClient: [ - connectDocSections.httpClient, - ], - types: [ - connectDocSections.types, - ], + introduction: [connectDocSections.introduction], + install: [connectDocSections.installation], + httpClient: [connectDocSections.httpClient], + webSocketOrderbookChannel: [connectDocSections.webSocketOrderbookChannel], + types: [connectDocSections.types], }, sectionNameToMarkdown: { [connectDocSections.introduction]: IntroMarkdown, @@ -56,6 +46,9 @@ const docsInfoConfig: DocsInfoConfig = { 'Client', 'FeesRequest', 'FeesResponse', + 'OrderbookChannel', + 'OrderbookChannelHandler', + 'OrderbookChannelSubscriptionOpts', 'OrderbookRequest', 'OrderbookResponse', 'OrdersRequest', @@ -64,14 +57,16 @@ const docsInfoConfig: DocsInfoConfig = { 'TokenTradeInfo', 'Order', 'SignedOrder', + 'ECSignature', ], sectionNameToModulePath: { [connectDocSections.httpClient]: ['"src/http_client"'], + [connectDocSections.webSocketOrderbookChannel]: ['"src/ws_orderbook_channel"'], [connectDocSections.types]: ['"src/types"'], }, menuSubsectionToVersionWhenIntroduced: {}, sections: connectDocSections, - visibleConstructors: [connectDocSections.httpClient], + visibleConstructors: [connectDocSections.httpClient, connectDocSections.webSocketOrderbookChannel], convertToDocAgnosticFormatFn: typeDocUtils.convertToDocAgnosticFormat.bind(typeDocUtils), }; const docsInfo = new DocsInfo(docsInfoConfig); @@ -96,5 +91,6 @@ const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({ dispatcher: new Dispatcher(dispatch), }); -export const Documentation: React.ComponentClass<DocumentationAllProps> = - connect(mapStateToProps, mapDispatchToProps)(DocumentationComponent); +export const Documentation: React.ComponentClass<DocumentationAllProps> = connect(mapStateToProps, mapDispatchToProps)( + DocumentationComponent, +); diff --git a/packages/website/ts/containers/generate_order_form.tsx b/packages/website/ts/containers/generate_order_form.tsx index 864d2702e..3fd31087f 100644 --- a/packages/website/ts/containers/generate_order_form.tsx +++ b/packages/website/ts/containers/generate_order_form.tsx @@ -1,12 +1,11 @@ -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import * as React from 'react'; -import {connect} from 'react-redux'; -import {Dispatch, Store as ReduxStore} from 'redux'; -import {Blockchain} from 'ts/blockchain'; -import {GenerateOrderForm as GenerateOrderFormComponent} from 'ts/components/generate_order/generate_order_form'; -import {Dispatcher} from 'ts/redux/dispatcher'; -import {State} from 'ts/redux/reducer'; +import { connect } from 'react-redux'; +import { Blockchain } from 'ts/blockchain'; +import { GenerateOrderForm as GenerateOrderFormComponent } from 'ts/components/generate_order/generate_order_form'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { State } from 'ts/redux/reducer'; import { BlockchainErrs, HashData, @@ -50,5 +49,6 @@ const mapStateToProps = (state: State, ownProps: GenerateOrderFormProps): Connec userAddress: state.userAddress, }); -export const GenerateOrderForm: React.ComponentClass<GenerateOrderFormProps> = - connect(mapStateToProps)(GenerateOrderFormComponent); +export const GenerateOrderForm: React.ComponentClass<GenerateOrderFormProps> = connect(mapStateToProps)( + GenerateOrderFormComponent, +); diff --git a/packages/website/ts/containers/portal.tsx b/packages/website/ts/containers/portal.tsx index 2987764f4..f0247935b 100644 --- a/packages/website/ts/containers/portal.tsx +++ b/packages/website/ts/containers/portal.tsx @@ -1,64 +1,50 @@ -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import * as React from 'react'; -import {connect} from 'react-redux'; -import {Dispatch, Store as ReduxStore} from 'redux'; -import { - Portal as PortalComponent, - PortalAllProps as PortalComponentAllProps, - PortalPassedProps as PortalComponentPassedProps, -} from 'ts/components/portal'; -import {Dispatcher} from 'ts/redux/dispatcher'; -import {State} from 'ts/redux/reducer'; -import { - BlockchainErrs, - Fill, - HashData, - Order, - ScreenWidths, - Side, - TokenByAddress, - TokenStateByAddress, -} from 'ts/types'; -import {constants} from 'ts/utils/constants'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; +import { Portal as PortalComponent, PortalAllProps as PortalComponentAllProps } from 'ts/components/portal'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { State } from 'ts/redux/reducer'; +import { BlockchainErrs, HashData, Order, ScreenWidths, Side, TokenByAddress, TokenStateByAddress } from 'ts/types'; +import { constants } from 'ts/utils/constants'; -interface MapStateToProps { +interface ConnectedState { blockchainErr: BlockchainErrs; blockchainIsLoaded: boolean; hashData: HashData; networkId: number; nodeVersion: string; - orderFillAmount: number; + orderFillAmount: BigNumber; tokenByAddress: TokenByAddress; tokenStateByAddress: TokenStateByAddress; - userEtherBalance: number; + userEtherBalance: BigNumber; screenWidth: ScreenWidths; shouldBlockchainErrDialogBeOpen: boolean; userAddress: string; userSuppliedOrderCache: Order; + flashMessage?: string | React.ReactNode; } -interface ConnectedState {} - interface ConnectedDispatch { dispatcher: Dispatcher; } const mapStateToProps = (state: State, ownProps: PortalComponentAllProps): ConnectedState => { - const receiveAssetToken = state.sideToAssetToken[Side.receive]; - const depositAssetToken = state.sideToAssetToken[Side.deposit]; - const receiveAddress = !_.isUndefined(receiveAssetToken.address) ? - receiveAssetToken.address : constants.NULL_ADDRESS; - const depositAddress = !_.isUndefined(depositAssetToken.address) ? - depositAssetToken.address : constants.NULL_ADDRESS; - const receiveAmount = !_.isUndefined(receiveAssetToken.amount) ? - receiveAssetToken.amount : new BigNumber(0); - const depositAmount = !_.isUndefined(depositAssetToken.amount) ? - depositAssetToken.amount : new BigNumber(0); + const receiveAssetToken = state.sideToAssetToken[Side.Receive]; + const depositAssetToken = state.sideToAssetToken[Side.Deposit]; + const receiveAddress = !_.isUndefined(receiveAssetToken.address) + ? receiveAssetToken.address + : constants.NULL_ADDRESS; + const depositAddress = !_.isUndefined(depositAssetToken.address) + ? depositAssetToken.address + : constants.NULL_ADDRESS; + const receiveAmount = !_.isUndefined(receiveAssetToken.amount) ? receiveAssetToken.amount : new BigNumber(0); + const depositAmount = !_.isUndefined(depositAssetToken.amount) ? depositAssetToken.amount : new BigNumber(0); const hashData = { depositAmount, depositTokenContractAddr: depositAddress, - feeRecipientAddress: constants.FEE_RECIPIENT_ADDRESS, + feeRecipientAddress: constants.NULL_ADDRESS, makerFee: constants.MAKER_FEE, orderExpiryTimestamp: state.orderExpiryTimestamp, orderMakerAddress: state.userAddress, @@ -90,5 +76,6 @@ const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({ dispatcher: new Dispatcher(dispatch), }); -export const Portal: React.ComponentClass<PortalComponentPassedProps> = - connect(mapStateToProps, mapDispatchToProps)(PortalComponent); +export const Portal: React.ComponentClass<PortalComponentAllProps> = connect(mapStateToProps, mapDispatchToProps)( + PortalComponent, +); diff --git a/packages/website/ts/containers/smart_contracts_documentation.tsx b/packages/website/ts/containers/smart_contracts_documentation.tsx index ea2b19b8c..8be33b546 100644 --- a/packages/website/ts/containers/smart_contracts_documentation.tsx +++ b/packages/website/ts/containers/smart_contracts_documentation.tsx @@ -1,52 +1,38 @@ import * as _ from 'lodash'; import * as React from 'react'; -import {connect} from 'react-redux'; -import {Dispatch, Store as ReduxStore} from 'redux'; -import {DocsInfo} from 'ts/pages/documentation/docs_info'; -import { - Documentation as DocumentationComponent, - DocumentationAllProps, -} from 'ts/pages/documentation/documentation'; -import {Dispatcher} from 'ts/redux/dispatcher'; -import {State} from 'ts/redux/reducer'; -import {DocsInfoConfig, WebsitePaths} from 'ts/types'; -import {constants} from 'ts/utils/constants'; -import {doxityUtils} from 'ts/utils/doxity_utils'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; +import { DocsInfo } from 'ts/pages/documentation/docs_info'; +import { Documentation as DocumentationComponent, DocumentationAllProps } from 'ts/pages/documentation/documentation'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { State } from 'ts/redux/reducer'; +import { DocsInfoConfig, SmartContractDocSections as Sections, WebsitePaths } from 'ts/types'; +import { doxityUtils } from 'ts/utils/doxity_utils'; /* tslint:disable:no-var-requires */ const IntroMarkdown = require('md/docs/smart_contracts/introduction'); /* tslint:enable:no-var-requires */ -const sections = constants.smartContractDocSections; - const docsInfoConfig: DocsInfoConfig = { displayName: '0x Smart Contracts', packageUrl: 'https://github.com/0xProject/contracts', websitePath: WebsitePaths.SmartContracts, docsJsonRoot: 'https://s3.amazonaws.com/smart-contracts-docs-json', menu: { - introduction: [ - sections.Introduction, - ], - contracts: [ - sections.Exchange, - sections.TokenRegistry, - sections.ZRXToken, - sections.EtherToken, - sections.TokenTransferProxy, - ], + introduction: [Sections.Introduction], + contracts: [Sections.Exchange, Sections.TokenRegistry, Sections.ZRXToken, Sections.TokenTransferProxy], }, sectionNameToMarkdown: { - [sections.Introduction]: IntroMarkdown, + [Sections.Introduction]: IntroMarkdown, + }, + sections: { + Introduction: Sections.Introduction, + Exchange: Sections.Exchange, + TokenTransferProxy: Sections.TokenTransferProxy, + TokenRegistry: Sections.TokenRegistry, + ZRXToken: Sections.ZRXToken, }, - sections, - visibleConstructors: [ - sections.Exchange, - sections.TokenRegistry, - sections.ZRXToken, - sections.EtherToken, - sections.TokenTransferProxy, - ], + visibleConstructors: [Sections.Exchange, Sections.TokenRegistry, Sections.ZRXToken, Sections.TokenTransferProxy], convertToDocAgnosticFormatFn: doxityUtils.convertToDocAgnosticFormat.bind(doxityUtils), }; const docsInfo = new DocsInfo(docsInfoConfig); @@ -71,5 +57,6 @@ const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({ docsInfo, }); -export const Documentation: React.ComponentClass<DocumentationAllProps> = - connect(mapStateToProps, mapDispatchToProps)(DocumentationComponent); +export const Documentation: React.ComponentClass<DocumentationAllProps> = connect(mapStateToProps, mapDispatchToProps)( + DocumentationComponent, +); diff --git a/packages/website/ts/containers/zero_ex_js_documentation.tsx b/packages/website/ts/containers/zero_ex_js_documentation.tsx index 58c0ee186..8ae6a7b73 100644 --- a/packages/website/ts/containers/zero_ex_js_documentation.tsx +++ b/packages/website/ts/containers/zero_ex_js_documentation.tsx @@ -1,18 +1,14 @@ -import BigNumber from 'bignumber.js'; import * as _ from 'lodash'; import * as React from 'react'; -import {connect} from 'react-redux'; -import {Dispatch, Store as ReduxStore} from 'redux'; -import {Blockchain} from 'ts/blockchain'; -import {DocsInfo} from 'ts/pages/documentation/docs_info'; -import { - Documentation as DocumentationComponent, - DocumentationAllProps, -} from 'ts/pages/documentation/documentation'; -import {Dispatcher} from 'ts/redux/dispatcher'; -import {State} from 'ts/redux/reducer'; -import {DocsInfoConfig, WebsitePaths} from 'ts/types'; -import {typeDocUtils} from 'ts/utils/typedoc_utils'; +import { connect } from 'react-redux'; +import { Dispatch } from 'redux'; +import { DocsInfo } from 'ts/pages/documentation/docs_info'; +import { Documentation as DocumentationComponent, DocumentationAllProps } from 'ts/pages/documentation/documentation'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { State } from 'ts/redux/reducer'; +import { DocsInfoConfig, WebsitePaths } from 'ts/types'; +import { constants } from 'ts/utils/constants'; +import { typeDocUtils } from 'ts/utils/typedoc_utils'; /* tslint:disable:no-var-requires */ const IntroMarkdown = require('md/docs/0xjs/introduction'); @@ -36,7 +32,7 @@ const zeroExJsDocSections = { etherToken: 'etherToken', proxy: 'proxy', orderWatcher: 'orderWatcher', - types: 'types', + types: constants.TYPES_SECTION_NAME, }; const docsInfoConfig: DocsInfoConfig = { @@ -46,20 +42,10 @@ const docsInfoConfig: DocsInfoConfig = { websitePath: WebsitePaths.ZeroExJs, docsJsonRoot: 'https://s3.amazonaws.com/0xjs-docs-jsons', menu: { - introduction: [ - zeroExJsDocSections.introduction, - ], - install: [ - zeroExJsDocSections.installation, - ], - topics: [ - zeroExJsDocSections.async, - zeroExJsDocSections.errors, - zeroExJsDocSections.versioning, - ], - zeroEx: [ - zeroExJsDocSections.zeroEx, - ], + introduction: [zeroExJsDocSections.introduction], + install: [zeroExJsDocSections.installation], + topics: [zeroExJsDocSections.async, zeroExJsDocSections.errors, zeroExJsDocSections.versioning], + zeroEx: [zeroExJsDocSections.zeroEx], contracts: [ zeroExJsDocSections.exchange, zeroExJsDocSections.token, @@ -67,12 +53,8 @@ const docsInfoConfig: DocsInfoConfig = { zeroExJsDocSections.etherToken, zeroExJsDocSections.proxy, ], - orderWatcher: [ - zeroExJsDocSections.orderWatcher, - ], - types: [ - zeroExJsDocSections.types, - ], + orderWatcher: [zeroExJsDocSections.orderWatcher], + types: [zeroExJsDocSections.types], }, sectionNameToMarkdown: { [zeroExJsDocSections.introduction]: IntroMarkdown, @@ -97,6 +79,7 @@ const docsInfoConfig: DocsInfoConfig = { 'ExchangeEvents', 'IndexedFilterValues', 'SubscriptionOpts', + 'BlockRange', 'BlockParam', 'OrderFillOrKillRequest', 'OrderCancellationRequest', @@ -109,6 +92,9 @@ const docsInfoConfig: DocsInfoConfig = { 'LogErrorContractEventArgs', 'LogFillContractEventArgs', 'LogCancelContractEventArgs', + 'EtherTokenContractEventArgs', + 'WithdrawalContractEventArgs', + 'DepositContractEventArgs', 'TokenEvents', 'ExchangeContractEventArgs', 'TransferContractEventArgs', @@ -117,6 +103,8 @@ const docsInfoConfig: DocsInfoConfig = { 'ZeroExConfig', 'TransactionReceiptWithDecodedLogs', 'LogWithDecodedArgs', + 'EtherTokenEvents', + 'BlockParamLiteral', 'DecodedLogArgs', 'MethodOpts', 'ValidateOrderFillableOpts', @@ -177,5 +165,6 @@ const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({ dispatcher: new Dispatcher(dispatch), }); -export const Documentation: React.ComponentClass<DocumentationAllProps> = - connect(mapStateToProps, mapDispatchToProps)(DocumentationComponent); +export const Documentation: React.ComponentClass<DocumentationAllProps> = connect(mapStateToProps, mapDispatchToProps)( + DocumentationComponent, +); diff --git a/packages/website/ts/globals.d.ts b/packages/website/ts/globals.d.ts index b4611f583..383e5cbe0 100644 --- a/packages/website/ts/globals.d.ts +++ b/packages/website/ts/globals.d.ts @@ -55,11 +55,6 @@ interface System { } declare var System: System; -// ethereum-address declarations -declare module 'ethereum-address' { - export const isAddress: (address: string) => boolean; -} - // jsonschema declarations // Source: https://github.com/tdegrunt/jsonschema/blob/master/lib/index.d.ts declare interface Schema { @@ -96,7 +91,7 @@ declare interface Schema { dependencies?: { [name: string]: Schema | string[]; }; - 'enum'?: any[]; + enum?: any[]; type?: string | string[]; allOf?: Schema[]; anyOf?: Schema[]; @@ -135,23 +130,25 @@ declare module 'web3-provider-engine/subproviders/subprovider' { declare module 'web3-provider-engine/subproviders/rpc' { import * as Web3 from 'web3'; class RpcSubprovider { - constructor(options: {rpcUrl: string}); + constructor(options: { rpcUrl: string }); public handleRequest( - payload: Web3.JSONRPCRequestPayload, next: () => void, end: (err: Error|null, data?: any) => void, + payload: Web3.JSONRPCRequestPayload, + next: () => void, + end: (err: Error | null, data?: any) => void, ): void; } export = RpcSubprovider; } declare module 'web3-provider-engine' { - class Web3ProviderEngine { - public on(event: string, handler: () => void): void; - public send(payload: any): void; - public sendAsync(payload: any, callback: (error: any, response: any) => void): void; - public addProvider(provider: any): void; - public start(): void; - public stop(): void; - } - export = Web3ProviderEngine; + class Web3ProviderEngine { + public on(event: string, handler: () => void): void; + public send(payload: any): void; + public sendAsync(payload: any, callback: (error: any, response: any) => void): void; + public addProvider(provider: any): void; + public start(): void; + public stop(): void; + } + export = Web3ProviderEngine; } declare interface Artifact { diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx index 922102d96..ffb551561 100644 --- a/packages/website/ts/index.tsx +++ b/packages/website/ts/index.tsx @@ -1,97 +1,47 @@ // Polyfills -import 'whatwg-fetch'; - -import BigNumber from 'bignumber.js'; -import {colors, getMuiTheme, MuiThemeProvider} from 'material-ui/styles'; +import { MuiThemeProvider } from 'material-ui/styles'; import * as React from 'react'; -import {render} from 'react-dom'; -import {Provider} from 'react-redux'; -import {BrowserRouter as Router, Link, Redirect, Route, Switch} from 'react-router-dom'; +import { render } from 'react-dom'; +import { Provider } from 'react-redux'; +import { BrowserRouter as Router, Redirect, Route, Switch } from 'react-router-dom'; import * as injectTapEventPlugin from 'react-tap-event-plugin'; -import {createStore, Store as ReduxStore} from 'redux'; -import {createLazyComponent} from 'ts/lazy_component'; -import {tradeHistoryStorage} from 'ts/local_storage/trade_history_storage'; -import {About} from 'ts/pages/about/about'; -import {FAQ} from 'ts/pages/faq/faq'; -import {Landing} from 'ts/pages/landing/landing'; -import {NotFound} from 'ts/pages/not_found'; -import {Wiki} from 'ts/pages/wiki/wiki'; -import {reducer, State} from 'ts/redux/reducer'; -import {WebsitePaths} from 'ts/types'; -import {constants} from 'ts/utils/constants'; +import { createStore, Store as ReduxStore } from 'redux'; +import { createLazyComponent } from 'ts/lazy_component'; +import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage'; +import { tradeHistoryStorage } from 'ts/local_storage/trade_history_storage'; +import { About } from 'ts/pages/about/about'; +import { FAQ } from 'ts/pages/faq/faq'; +import { Landing } from 'ts/pages/landing/landing'; +import { NotFound } from 'ts/pages/not_found'; +import { Wiki } from 'ts/pages/wiki/wiki'; +import { reducer, State } from 'ts/redux/reducer'; +import { WebsitePaths } from 'ts/types'; +import { muiTheme } from 'ts/utils/mui_theme'; +import 'whatwg-fetch'; injectTapEventPlugin(); -// 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, -}); - // Check if we've introduced an update that requires us to clear the tradeHistory local storage entries tradeHistoryStorage.clearIfRequired(); - -const CUSTOM_GREY = 'rgb(39, 39, 39)'; -const CUSTOM_GREEN = 'rgb(102, 222, 117)'; -const CUSTOM_DARKER_GREEN = 'rgb(77, 197, 92)'; +trackedTokenStorage.clearIfRequired(); import 'basscss/css/basscss.css'; import 'less/all.less'; -const muiTheme = getMuiTheme({ - appBar: { - height: 45, - color: 'white', - textColor: 'black', - }, - palette: { - pickerHeaderColor: constants.CUSTOM_BLUE, - primary1Color: constants.CUSTOM_BLUE, - primary2Color: constants.CUSTOM_BLUE, - textColor: colors.grey700, - }, - datePicker: { - color: colors.grey700, - textColor: 'white', - calendarTextColor: 'white', - selectColor: CUSTOM_GREY, - selectTextColor: 'white', - }, - timePicker: { - color: colors.grey700, - textColor: 'white', - accentColor: 'white', - headerColor: CUSTOM_GREY, - selectColor: CUSTOM_GREY, - selectTextColor: CUSTOM_GREY, - }, - toggle: { - thumbOnColor: CUSTOM_GREEN, - trackOnColor: CUSTOM_DARKER_GREEN, - }, -}); - // We pass modulePromise returning lambda instead of module promise, // cause we only want to import the module when the user navigates to the page. // At the same time webpack statically parses for System.import() to determine bundle chunk split points // so each lazy import needs it's own `System.import()` declaration. -const LazyPortal = createLazyComponent( - 'Portal', async () => System.import<any>(/* webpackChunkName: "portal" */'ts/containers/portal'), +const LazyPortal = createLazyComponent('Portal', async () => + System.import<any>(/* webpackChunkName: "portal" */ 'ts/containers/portal'), ); -const LazyZeroExJSDocumentation = createLazyComponent( - 'Documentation', - async () => System.import<any>(/* webpackChunkName: "zeroExDocs" */'ts/containers/zero_ex_js_documentation'), +const LazyZeroExJSDocumentation = createLazyComponent('Documentation', async () => + System.import<any>(/* webpackChunkName: "zeroExDocs" */ 'ts/containers/zero_ex_js_documentation'), ); -const LazySmartContractsDocumentation = createLazyComponent( - 'Documentation', - async () => System.import<any>( - /* webpackChunkName: "smartContractDocs" */'ts/containers/smart_contracts_documentation', - ), +const LazySmartContractsDocumentation = createLazyComponent('Documentation', async () => + System.import<any>(/* webpackChunkName: "smartContractDocs" */ 'ts/containers/smart_contracts_documentation'), ); -const LazyConnectDocumentation = createLazyComponent( - 'Documentation', - async () => System.import<any>( - /* webpackChunkName: "connectDocs" */'ts/containers/connect_documentation', - ), +const LazyConnectDocumentation = createLazyComponent('Documentation', async () => + System.import<any>(/* webpackChunkName: "connectDocs" */ 'ts/containers/connect_documentation'), ); const store: ReduxStore<State> = createStore(reducer); @@ -103,7 +53,7 @@ render( <div> <Switch> <Route exact={true} path="/" component={Landing as any} /> - <Redirect from="/otc" to={`${WebsitePaths.Portal}`}/> + <Redirect from="/otc" to={`${WebsitePaths.Portal}`} /> <Route path={`${WebsitePaths.Portal}`} component={LazyPortal} /> <Route path={`${WebsitePaths.FAQ}`} component={FAQ as any} /> <Route path={`${WebsitePaths.About}`} component={About as any} /> @@ -120,6 +70,6 @@ render( </Provider> </MuiThemeProvider> </div> - </Router>, + </Router>, document.getElementById('app'), ); diff --git a/packages/website/ts/lazy_component.tsx b/packages/website/ts/lazy_component.tsx index 359a1fe65..48800c2dd 100644 --- a/packages/website/ts/lazy_component.tsx +++ b/packages/website/ts/lazy_component.tsx @@ -23,20 +23,20 @@ export class LazyComponent extends React.Component<LazyComponentProps, LazyCompo } public componentWillMount() { // tslint:disable-next-line:no-floating-promises - this.loadComponentFireAndForgetAsync(this.props); + this._loadComponentFireAndForgetAsync(this.props); } public componentWillReceiveProps(nextProps: LazyComponentProps) { if (nextProps.reactComponentPromise !== this.props.reactComponentPromise) { // tslint:disable-next-line:no-floating-promises - this.loadComponentFireAndForgetAsync(nextProps); + this._loadComponentFireAndForgetAsync(nextProps); } } public render() { - return _.isUndefined(this.state.component) ? - null : - React.createElement(this.state.component, this.props.reactComponentProps); + return _.isUndefined(this.state.component) + ? null + : React.createElement(this.state.component, this.props.reactComponentProps); } - private async loadComponentFireAndForgetAsync(props: LazyComponentProps) { + private async _loadComponentFireAndForgetAsync(props: LazyComponentProps) { const component = await props.reactComponentPromise; this.setState({ component, @@ -61,11 +61,6 @@ export const createLazyComponent = (componentName: string, lazyImport: () => Pro } return component; })(); - return ( - <LazyComponent - reactComponentPromise={reactComponentPromise} - reactComponentProps={props} - /> - ); + return <LazyComponent reactComponentPromise={reactComponentPromise} reactComponentProps={props} />; }; }; diff --git a/packages/website/ts/local_storage/tracked_token_storage.ts b/packages/website/ts/local_storage/tracked_token_storage.ts index 051a78ae1..7733e8436 100644 --- a/packages/website/ts/local_storage/tracked_token_storage.ts +++ b/packages/website/ts/local_storage/tracked_token_storage.ts @@ -1,26 +1,37 @@ import * as _ from 'lodash'; -import {localStorage} from 'ts/local_storage/local_storage'; -import {Token, TrackedTokensByNetworkId} from 'ts/types'; +import { localStorage } from 'ts/local_storage/local_storage'; +import { Token, TrackedTokensByUserAddress } from 'ts/types'; +import { configs } from 'ts/utils/configs'; const TRACKED_TOKENS_KEY = 'trackedTokens'; +const TRACKED_TOKENS_CLEAR_KEY = 'lastClearTrackedTokensDate'; export const trackedTokenStorage = { - addTrackedTokenToUser(userAddress: string, networkId: number, token: Token) { + // Clear trackedTokens localStorage if we've updated the config variable in an update + // that introduced a backward incompatible change requiring the tracked tokens to be re-set + clearIfRequired(): void { + const lastClearFillDate = localStorage.getItemIfExists(TRACKED_TOKENS_CLEAR_KEY); + if (lastClearFillDate !== configs.LAST_LOCAL_STORAGE_TRACKED_TOKEN_CLEARANCE_DATE) { + localStorage.removeItem(TRACKED_TOKENS_KEY); + } + localStorage.setItem(TRACKED_TOKENS_CLEAR_KEY, configs.LAST_LOCAL_STORAGE_TRACKED_TOKEN_CLEARANCE_DATE); + }, + addTrackedTokenToUser(userAddress: string, networkId: number, token: Token): void { const trackedTokensByUserAddress = this.getTrackedTokensByUserAddress(); let trackedTokensByNetworkId = trackedTokensByUserAddress[userAddress]; if (_.isUndefined(trackedTokensByNetworkId)) { trackedTokensByNetworkId = {}; } - const trackedTokens = !_.isUndefined(trackedTokensByNetworkId[networkId]) ? - trackedTokensByNetworkId[networkId] : - []; + const trackedTokens = !_.isUndefined(trackedTokensByNetworkId[networkId]) + ? trackedTokensByNetworkId[networkId] + : []; trackedTokens.push(token); trackedTokensByNetworkId[networkId] = trackedTokens; trackedTokensByUserAddress[userAddress] = trackedTokensByNetworkId; const trackedTokensByUserAddressJSONString = JSON.stringify(trackedTokensByUserAddress); localStorage.setItem(TRACKED_TOKENS_KEY, trackedTokensByUserAddressJSONString); }, - getTrackedTokensByUserAddress(): TrackedTokensByNetworkId { + getTrackedTokensByUserAddress(): TrackedTokensByUserAddress { const trackedTokensJSONString = localStorage.getItemIfExists(TRACKED_TOKENS_KEY); if (_.isEmpty(trackedTokensJSONString)) { return {}; @@ -41,7 +52,7 @@ export const trackedTokenStorage = { const trackedTokens = trackedTokensByNetworkId[networkId]; return trackedTokens; }, - removeTrackedToken(userAddress: string, networkId: number, tokenAddress: string) { + removeTrackedToken(userAddress: string, networkId: number, tokenAddress: string): void { const trackedTokensByUserAddress = this.getTrackedTokensByUserAddress(); const trackedTokensByNetworkId = trackedTokensByUserAddress[userAddress]; const trackedTokens = trackedTokensByNetworkId[networkId]; diff --git a/packages/website/ts/local_storage/trade_history_storage.tsx b/packages/website/ts/local_storage/trade_history_storage.tsx index 0d627e000..df731236e 100644 --- a/packages/website/ts/local_storage/trade_history_storage.tsx +++ b/packages/website/ts/local_storage/trade_history_storage.tsx @@ -1,10 +1,10 @@ -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import ethUtil = require('ethereumjs-util'); import * as _ from 'lodash'; -import {localStorage} from 'ts/local_storage/local_storage'; -import {Fill} from 'ts/types'; -import {configs} from 'ts/utils/configs'; -import {constants} from 'ts/utils/constants'; +import { localStorage } from 'ts/local_storage/local_storage'; +import { Fill } from 'ts/types'; +import { configs } from 'ts/utils/configs'; +import { constants } from 'ts/utils/constants'; const FILLS_KEY = 'fills'; const FILLS_LATEST_BLOCK = 'fillsLatestBlock'; @@ -16,7 +16,7 @@ export const tradeHistoryStorage = { // the blockchain clearIfRequired() { const lastClearFillDate = localStorage.getItemIfExists(FILL_CLEAR_KEY); - if (lastClearFillDate !== configs.lastLocalStorageFillClearanceDate) { + if (lastClearFillDate !== configs.LAST_LOCAL_STORAGE_FILL_CLEARANCE_DATE) { const localStorageKeys = localStorage.getAllKeys(); _.each(localStorageKeys, key => { if (_.startsWith(key, `${FILLS_KEY}-`) || _.startsWith(key, `${FILLS_LATEST_BLOCK}-`)) { @@ -24,7 +24,7 @@ export const tradeHistoryStorage = { } }); } - localStorage.setItem(FILL_CLEAR_KEY, configs.lastLocalStorageFillClearanceDate); + localStorage.setItem(FILL_CLEAR_KEY, configs.LAST_LOCAL_STORAGE_FILL_CLEARANCE_DATE); }, addFillToUser(userAddress: string, networkId: number, fill: Fill) { const fillsByHash = this.getUserFillsByHash(userAddress, networkId); @@ -50,7 +50,7 @@ export const tradeHistoryStorage = { const userFillsKey = this._getUserFillsKey(userAddress, networkId); localStorage.setItem(userFillsKey, userFillsJSONString); }, - getUserFillsByHash(userAddress: string, networkId: number): {[fillHash: string]: Fill} { + getUserFillsByHash(userAddress: string, networkId: number): { [fillHash: string]: Fill } { const userFillsKey = this._getUserFillsKey(userAddress, networkId); const userFillsJSONString = localStorage.getItemIfExists(userFillsKey); if (_.isEmpty(userFillsJSONString)) { @@ -58,10 +58,10 @@ export const tradeHistoryStorage = { } const userFillsByHash = JSON.parse(userFillsJSONString); _.each(userFillsByHash, (fill, hash) => { - fill.paidMakerFee = new BigNumber(fill.paidMakerFee); - fill.paidTakerFee = new BigNumber(fill.paidTakerFee); - fill.filledTakerTokenAmount = new BigNumber(fill.filledTakerTokenAmount); - fill.filledMakerTokenAmount = new BigNumber(fill.filledMakerTokenAmount); + fill.paidMakerFee = new BigNumber(fill.paidMakerFee); + fill.paidTakerFee = new BigNumber(fill.paidTakerFee); + fill.filledTakerTokenAmount = new BigNumber(fill.filledTakerTokenAmount); + fill.filledMakerTokenAmount = new BigNumber(fill.filledMakerTokenAmount); }); return userFillsByHash; }, diff --git a/packages/website/ts/pages/about/about.tsx b/packages/website/ts/pages/about/about.tsx index 3af05e8a4..c929673f5 100644 --- a/packages/website/ts/pages/about/about.tsx +++ b/packages/website/ts/pages/about/about.tsx @@ -1,21 +1,13 @@ import * as _ from 'lodash'; -import RaisedButton from 'material-ui/RaisedButton'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; import * as DocumentTitle from 'react-document-title'; -import {Link} from 'react-router-dom'; -import {Footer} from 'ts/components/footer'; -import {TopBar} from 'ts/components/top_bar'; -import {Profile} from 'ts/pages/about/profile'; -import {Question} from 'ts/pages/faq/question'; -import {ProfileInfo, Styles} from 'ts/types'; -import {configs} from 'ts/utils/configs'; -import {constants} from 'ts/utils/constants'; -import {utils} from 'ts/utils/utils'; - -const CUSTOM_BACKGROUND_COLOR = '#F0F0F0'; -const CUSTOM_GRAY = '#4C4C4C'; -const CUSTOM_LIGHT_GRAY = '#A2A2A2'; +import { Footer } from 'ts/components/footer'; +import { TopBar } from 'ts/components/top_bar'; +import { Profile } from 'ts/pages/about/profile'; +import { ProfileInfo, Styles } from 'ts/types'; +import { colors } from 'ts/utils/colors'; +import { constants } from 'ts/utils/constants'; +import { utils } from 'ts/utils/utils'; const teamRow1: ProfileInfo[] = [ { @@ -48,6 +40,9 @@ const teamRow1: ProfileInfo[] = [ github: 'https://github.com/fabioberger', medium: 'https://medium.com/@fabioberger', }, +]; + +const teamRow2: ProfileInfo[] = [ { name: 'Alex Xu', title: 'Director of Operations', @@ -56,11 +51,8 @@ const teamRow1: ProfileInfo[] = [ image: '/images/team/alex.jpg', linkedIn: 'https://www.linkedin.com/in/alex-xu/', github: '', - medium: '', + medium: 'https://medium.com/@aqxu', }, -]; - -const teamRow2: ProfileInfo[] = [ { name: 'Leonid Logvinov', title: 'Engineer', @@ -69,7 +61,7 @@ const teamRow2: ProfileInfo[] = [ image: '/images/team/leonid.png', linkedIn: 'https://www.linkedin.com/in/leonidlogvinov/', github: 'https://github.com/LogvinovLeon', - medium: '', + medium: 'https://medium.com/@Logvinov', }, { name: 'Ben Burns', @@ -81,23 +73,36 @@ const teamRow2: ProfileInfo[] = [ github: '', medium: '', }, - { - name: 'Philippe Castonguay', - title: 'Dev Relations Manager', - description: `Developer relations. Previously computational neuroscience \ - research at Janelia. Statistics at Western University. MA Dropout.`, - image: '/images/team/philippe.png', - linkedIn: '', - github: 'https://github.com/PhABC', - medium: '', - }, +]; + +const teamRow3: ProfileInfo[] = [ { name: 'Brandon Millman', title: 'Senior Engineer', description: `Full-stack engineer. Previously senior software engineer at \ Twitter. Electrical and Computer Engineering at Duke.`, image: '/images/team/brandon.png', - linkedIn: 'https://www.linkedin.com/company-beta/17942619/', + linkedIn: 'https://www.linkedin.com/in/brandon-millman-b093a022/', + github: 'https://github.com/BMillman19', + medium: 'https://medium.com/@bchillman', + }, + { + name: 'Tom Schmidt', + title: 'Product Manager', + description: `Previously engineering at Apple, product management at Facebook and Instagram. Computer Science at Stanford.`, + image: '/images/team/tom.jpg', + linkedIn: 'https://www.linkedin.com/in/tomhschmidt/', + github: 'https://github.com/tomhschmidt', + medium: '', + }, + { + name: 'Jacob Evans', + title: 'Blockchain Engineer', + description: `Previously software engineer at Qantas and RSA Security.`, + image: '/images/team/jacob.jpg', + linkedIn: 'https://www.linkedin.com/in/dekzter/', + github: 'https://github.com/dekz', + medium: '', }, ]; @@ -149,6 +154,12 @@ const styles: Styles = { color: 'black', paddingTop: 110, }, + weAreHiring: { + fontSize: 30, + color: colors.darkestGrey, + fontFamily: 'Roboto Mono', + letterSpacing: 7.5, + }, }; export class About extends React.Component<AboutProps, AboutState> { @@ -157,95 +168,79 @@ export class About extends React.Component<AboutProps, AboutState> { } public render() { return ( - <div style={{backgroundColor: CUSTOM_BACKGROUND_COLOR}}> - <DocumentTitle title="0x About Us"/> + <div style={{ backgroundColor: colors.lightestGrey }}> + <DocumentTitle title="0x About Us" /> <TopBar blockchainIsLoaded={false} location={this.props.location} - style={{backgroundColor: CUSTOM_BACKGROUND_COLOR}} + style={{ backgroundColor: colors.lightestGrey }} /> - <div - id="about" - className="mx-auto max-width-4 py4" - style={{color: colors.grey800}} - > - <div - className="mx-auto pb4 sm-px3" - style={{maxWidth: 435}} - > - <div - style={styles.header} - > - About us: - </div> + <div id="about" className="mx-auto max-width-4 py4" style={{ color: colors.grey800 }}> + <div className="mx-auto pb4 sm-px3" style={{ maxWidth: 435 }}> + <div style={styles.header}>About us:</div> <div className="pt3" - style={{fontSize: 17, color: CUSTOM_GRAY, lineHeight: 1.5}} + style={{ + fontSize: 17, + color: colors.darkestGrey, + lineHeight: 1.5, + }} > - Our team is a diverse and globally distributed group with backgrounds - in engineering, research, business and design. We are passionate about - decentralized technology and its potential to act as an equalizing force - in the world. + Our team is a diverse and globally distributed group with backgrounds in engineering, + research, business and design. We are passionate about decentralized technology and its + potential to act as an equalizing force in the world. </div> </div> <div className="pt3 md-px4 lg-px0"> - <div className="clearfix pb3"> - {this.renderProfiles(teamRow1)} - </div> - <div className="clearfix"> - {this.renderProfiles(teamRow2)} - </div> + <div className="clearfix pb3">{this._renderProfiles(teamRow1)}</div> + <div className="clearfix">{this._renderProfiles(teamRow2)}</div> + <div className="clearfix">{this._renderProfiles(teamRow3)}</div> </div> <div className="pt3 pb2"> <div className="pt2 pb3 sm-center md-pl4 lg-pl0 md-ml3" - style={{color: CUSTOM_LIGHT_GRAY, fontSize: 24, fontFamily: 'Roboto Mono'}} + style={{ + color: colors.grey, + fontSize: 24, + fontFamily: 'Roboto Mono', + }} > Advisors: </div> - <div className="clearfix"> - {this.renderProfiles(advisors)} - </div> + <div className="clearfix">{this._renderProfiles(advisors)}</div> </div> - <div className="mx-auto py4 sm-px3" style={{maxWidth: 308}}> - <div - className="pb2" - style={{fontSize: 30, color: CUSTOM_GRAY, fontFamily: 'Roboto Mono', letterSpacing: 7.5}} - > + <div className="mx-auto py4 sm-px3" style={{ maxWidth: 308 }}> + <div className="pb2" style={styles.weAreHiring}> WE'RE HIRING </div> <div className="pb4 mb4" - style={{fontSize: 16, color: CUSTOM_GRAY, lineHeight: 1.5, letterSpacing: '0.5px'}} + style={{ + fontSize: 16, + color: colors.darkestGrey, + lineHeight: 1.5, + letterSpacing: '0.5px', + }} > We are seeking outstanding candidates to{' '} - <a - href={constants.ANGELLIST_URL} - target="_blank" - style={{color: 'black'}} - > + <a href={constants.URL_ANGELLIST} target="_blank" style={{ color: 'black' }}> join our team </a> . We value passion, diversity and unique perspectives. </div> </div> </div> - <Footer location={this.props.location} /> + <Footer /> </div> ); } - private renderProfiles(profiles: ProfileInfo[]) { + private _renderProfiles(profiles: ProfileInfo[]) { const numIndiv = profiles.length; - const colSize = utils.getColSize(profiles.length); + const colSize = utils.getColSize(numIndiv); return _.map(profiles, profile => { return ( - <div - key={`profile-${profile.name}`} - > - <Profile - colSize={colSize} - profileInfo={profile} - /> + <div key={`profile-${profile.name}`}> + <Profile colSize={colSize} profileInfo={profile} /> </div> ); }); diff --git a/packages/website/ts/pages/about/profile.tsx b/packages/website/ts/pages/about/profile.tsx index 71dbd09b5..18b4e0d5a 100644 --- a/packages/website/ts/pages/about/profile.tsx +++ b/packages/website/ts/pages/about/profile.tsx @@ -1,9 +1,7 @@ import * as _ from 'lodash'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; -import {Element as ScrollElement} from 'react-scroll'; -import {ProfileInfo, Styles} from 'ts/types'; -import {utils} from 'ts/utils/utils'; +import { ProfileInfo, Styles } from 'ts/types'; +import { colors } from 'ts/utils/colors'; const IMAGE_DIMENSION = 149; const styles: Styles = { @@ -26,43 +24,30 @@ interface ProfileProps { export function Profile(props: ProfileProps) { return ( - <div - className={`lg-col md-col lg-col-${props.colSize} md-col-6`} - > - <div - style={{maxWidth: 300}} - className="mx-auto lg-px3 md-px3 sm-px4 sm-pb3" - > - <div - className="circle overflow-hidden mx-auto" - style={styles.imageContainer} - > - <img - width={IMAGE_DIMENSION} - src={props.profileInfo.image} - /> + <div className={`lg-col md-col lg-col-${props.colSize} md-col-6`}> + <div style={{ maxWidth: 300 }} className="mx-auto lg-px3 md-px3 sm-px4 sm-pb3"> + <div className="circle overflow-hidden mx-auto" style={styles.imageContainer}> + <img width={IMAGE_DIMENSION} src={props.profileInfo.image} /> </div> - <div - className="center" - style={{fontSize: 18, fontWeight: 'bold', paddingTop: 20}} - > + <div className="center" style={{ fontSize: 18, fontWeight: 'bold', paddingTop: 20 }}> {props.profileInfo.name} </div> - {!_.isUndefined(props.profileInfo.title) && + {!_.isUndefined(props.profileInfo.title) && ( <div className="pt1 center" - style={{fontSize: 14, fontFamily: 'Roboto Mono', color: '#818181'}} + style={{ + fontSize: 14, + fontFamily: 'Roboto Mono', + color: colors.darkGrey, + }} > {props.profileInfo.title.toUpperCase()} </div> - } - <div - style={{minHeight: 60, lineHeight: 1.4}} - className="pt1 pb2 mx-auto lg-h6 md-h6 sm-h5 sm-center" - > + )} + <div style={{ minHeight: 60, lineHeight: 1.4 }} className="pt1 pb2 mx-auto lg-h6 md-h6 sm-h5 sm-center"> {props.profileInfo.description} </div> - <div className="flex pb3 mx-auto sm-hide xs-hide" style={{width: 180, opacity: 0.5}}> + <div className="flex pb3 mx-auto sm-hide xs-hide" style={{ width: 280, opacity: 0.5 }}> {renderSocialMediaIcons(props.profileInfo)} </div> </div> @@ -86,13 +71,8 @@ function renderSocialMediaIcon(iconName: string, url: string) { return ( <div key={url} className="pr1"> - <a - href={url} - style={{color: 'inherit'}} - target="_blank" - className="text-decoration-none" - > - <i className={`zmdi ${iconName}`} style={{...styles.socalIcon}} /> + <a href={url} style={{ color: 'inherit' }} target="_blank" className="text-decoration-none"> + <i className={`zmdi ${iconName}`} style={{ ...styles.socalIcon }} /> </a> </div> ); diff --git a/packages/website/ts/pages/documentation/comment.tsx b/packages/website/ts/pages/documentation/comment.tsx index 78bbdc069..23cfd96bd 100644 --- a/packages/website/ts/pages/documentation/comment.tsx +++ b/packages/website/ts/pages/documentation/comment.tsx @@ -1,7 +1,7 @@ import * as _ from 'lodash'; import * as React from 'react'; import * as ReactMarkdown from 'react-markdown'; -import {MarkdownCodeBlock} from 'ts/pages/shared/markdown_code_block'; +import { MarkdownCodeBlock } from 'ts/pages/shared/markdown_code_block'; interface CommentProps { comment: string; @@ -15,10 +15,9 @@ const defaultProps = { export const Comment: React.SFC<CommentProps> = (props: CommentProps) => { return ( <div className={`${props.className} comment`}> - <ReactMarkdown - source={props.comment} - renderers={{CodeBlock: MarkdownCodeBlock}} - /> + <ReactMarkdown source={props.comment} renderers={{ CodeBlock: MarkdownCodeBlock }} /> </div> ); }; + +Comment.defaultProps = defaultProps; diff --git a/packages/website/ts/pages/documentation/custom_enum.tsx b/packages/website/ts/pages/documentation/custom_enum.tsx index 7dced9b60..8d50a2f52 100644 --- a/packages/website/ts/pages/documentation/custom_enum.tsx +++ b/packages/website/ts/pages/documentation/custom_enum.tsx @@ -1,7 +1,7 @@ import * as _ from 'lodash'; import * as React from 'react'; -import {CustomType} from 'ts/types'; -import {utils} from 'ts/utils/utils'; +import { CustomType } from 'ts/types'; +import { utils } from 'ts/utils/utils'; const STRING_ENUM_CODE_PREFIX = ' strEnum('; @@ -23,8 +23,9 @@ export function CustomEnum(props: CustomEnumProps) { return ( <span> {`{`} - {'\t'}{enumValues} - <br /> + {'\t'} + {enumValues} + <br /> {`}`} </span> ); diff --git a/packages/website/ts/pages/documentation/docs_info.ts b/packages/website/ts/pages/documentation/docs_info.ts index 1afcf8aaf..4b1ec122a 100644 --- a/packages/website/ts/pages/documentation/docs_info.ts +++ b/packages/website/ts/pages/documentation/docs_info.ts @@ -18,8 +18,8 @@ export class DocsInfo { public docsJsonRoot: string; public menu: DocsMenu; public sections: SectionsMap; - public sectionNameToMarkdown: {[sectionName: string]: string}; - private docsInfo: DocsInfoConfig; + public sectionNameToMarkdown: { [sectionName: string]: string }; + private _docsInfo: DocsInfoConfig; constructor(config: DocsInfoConfig) { this.displayName = config.displayName; this.packageUrl = config.packageUrl; @@ -28,35 +28,34 @@ export class DocsInfo { this.docsJsonRoot = config.docsJsonRoot; this.sections = config.sections; this.sectionNameToMarkdown = config.sectionNameToMarkdown; - this.docsInfo = config; + this._docsInfo = config; } public isPublicType(typeName: string): boolean { - if (_.isUndefined(this.docsInfo.publicTypes)) { + if (_.isUndefined(this._docsInfo.publicTypes)) { return false; } - const isPublic = _.includes(this.docsInfo.publicTypes, typeName); + const isPublic = _.includes(this._docsInfo.publicTypes, typeName); return isPublic; } public getModulePathsIfExists(sectionName: string): string[] { - const modulePathsIfExists = this.docsInfo.sectionNameToModulePath[sectionName]; + const modulePathsIfExists = this._docsInfo.sectionNameToModulePath[sectionName]; return modulePathsIfExists; } - public getMenu(selectedVersion?: string): {[section: string]: string[]} { - if (_.isUndefined(selectedVersion) || _.isUndefined(this.docsInfo.menuSubsectionToVersionWhenIntroduced)) { - return this.docsInfo.menu; + public getMenu(selectedVersion?: string): { [section: string]: string[] } { + if (_.isUndefined(selectedVersion) || _.isUndefined(this._docsInfo.menuSubsectionToVersionWhenIntroduced)) { + return this._docsInfo.menu; } - const finalMenu = _.cloneDeep(this.docsInfo.menu); + const finalMenu = _.cloneDeep(this._docsInfo.menu); if (_.isUndefined(finalMenu.contracts)) { return finalMenu; } // TODO: refactor to include more sections then simply the `contracts` section finalMenu.contracts = _.filter(finalMenu.contracts, (contractName: string) => { - const versionIntroducedIfExists = this.docsInfo.menuSubsectionToVersionWhenIntroduced[contractName]; + const versionIntroducedIfExists = this._docsInfo.menuSubsectionToVersionWhenIntroduced[contractName]; if (!_.isUndefined(versionIntroducedIfExists)) { - const existsInSelectedVersion = compareVersions(selectedVersion, - versionIntroducedIfExists) >= 0; + const existsInSelectedVersion = compareVersions(selectedVersion, versionIntroducedIfExists) >= 0; return existsInSelectedVersion; } else { return true; @@ -104,9 +103,9 @@ export class DocsInfo { return typeDefinitionByName; } public isVisibleConstructor(sectionName: string): boolean { - return _.includes(this.docsInfo.visibleConstructors, sectionName); + return _.includes(this._docsInfo.visibleConstructors, sectionName); } - public convertToDocAgnosticFormat(docObj: DoxityDocObj|TypeDocNode): DocAgnosticFormat { - return this.docsInfo.convertToDocAgnosticFormatFn(docObj, this); + public convertToDocAgnosticFormat(docObj: DoxityDocObj | TypeDocNode): DocAgnosticFormat { + return this._docsInfo.convertToDocAgnosticFormatFn(docObj, this); } } diff --git a/packages/website/ts/pages/documentation/documentation.tsx b/packages/website/ts/pages/documentation/documentation.tsx index be99e77a2..2315847ad 100644 --- a/packages/website/ts/pages/documentation/documentation.tsx +++ b/packages/website/ts/pages/documentation/documentation.tsx @@ -1,60 +1,48 @@ import findVersions = require('find-versions'); import * as _ from 'lodash'; import CircularProgress from 'material-ui/CircularProgress'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; import DocumentTitle = require('react-document-title'); -import { - scroller, -} from 'react-scroll'; +import { scroller } from 'react-scroll'; import semverSort = require('semver-sort'); -import {TopBar} from 'ts/components/top_bar'; -import {Badge} from 'ts/components/ui/badge'; -import {Comment} from 'ts/pages/documentation/comment'; -import {DocsInfo} from 'ts/pages/documentation/docs_info'; -import {EventDefinition} from 'ts/pages/documentation/event_definition'; -import {MethodBlock} from 'ts/pages/documentation/method_block'; -import {SourceLink} from 'ts/pages/documentation/source_link'; -import {Type} from 'ts/pages/documentation/type'; -import {TypeDefinition} from 'ts/pages/documentation/type_definition'; -import {AnchorTitle} from 'ts/pages/shared/anchor_title'; -import {MarkdownSection} from 'ts/pages/shared/markdown_section'; -import {NestedSidebarMenu} from 'ts/pages/shared/nested_sidebar_menu'; -import {SectionHeader} from 'ts/pages/shared/section_header'; -import {Dispatcher} from 'ts/redux/dispatcher'; +import { TopBar } from 'ts/components/top_bar'; +import { Badge } from 'ts/components/ui/badge'; +import { Comment } from 'ts/pages/documentation/comment'; +import { DocsInfo } from 'ts/pages/documentation/docs_info'; +import { EventDefinition } from 'ts/pages/documentation/event_definition'; +import { MethodBlock } from 'ts/pages/documentation/method_block'; +import { SourceLink } from 'ts/pages/documentation/source_link'; +import { Type } from 'ts/pages/documentation/type'; +import { TypeDefinition } from 'ts/pages/documentation/type_definition'; +import { MarkdownSection } from 'ts/pages/shared/markdown_section'; +import { NestedSidebarMenu } from 'ts/pages/shared/nested_sidebar_menu'; +import { SectionHeader } from 'ts/pages/shared/section_header'; +import { Dispatcher } from 'ts/redux/dispatcher'; import { AddressByContractName, - CustomType, DocAgnosticFormat, - Docs, - DocsInfoConfig, DoxityDocObj, EtherscanLinkSuffixes, Event, - MenuSubsectionsBySection, Networks, Property, SolidityMethod, Styles, TypeDefinitionByName, - TypeDocNode, TypescriptMethod, - WebsitePaths, } from 'ts/types'; -import {constants} from 'ts/utils/constants'; -import {docUtils} from 'ts/utils/doc_utils'; -import {utils} from 'ts/utils/utils'; +import { colors } from 'ts/utils/colors'; +import { configs } from 'ts/utils/configs'; +import { constants } from 'ts/utils/constants'; +import { docUtils } from 'ts/utils/doc_utils'; +import { utils } from 'ts/utils/utils'; -const SCROLL_TO_TIMEOUT = 500; const SCROLL_TOP_ID = 'docsScrollTop'; -const CUSTOM_PURPLE = '#690596'; -const CUSTOM_RED = '#e91751'; -const CUSTOM_TURQUOIS = '#058789'; -const networkNameToColor: {[network: string]: string} = { - [Networks.kovan]: CUSTOM_PURPLE, - [Networks.ropsten]: CUSTOM_RED, - [Networks.mainnet]: CUSTOM_TURQUOIS, +const networkNameToColor: { [network: string]: string } = { + [Networks.kovan]: colors.purple, + [Networks.ropsten]: colors.red, + [Networks.mainnet]: colors.turquois, }; export interface DocumentationAllProps { @@ -73,13 +61,13 @@ interface DocumentationState { const styles: Styles = { mainContainers: { position: 'absolute', - top: 60, + top: 1, left: 0, bottom: 0, right: 0, overflowZ: 'hidden', overflowY: 'scroll', - minHeight: 'calc(100vh - 60px)', + minHeight: 'calc(100vh - 1px)', WebkitOverflowScrolling: 'touch', }, menuContainer: { @@ -89,8 +77,7 @@ const styles: Styles = { }, }; -export class Documentation extends - React.Component<DocumentationAllProps, DocumentationState> { +export class Documentation extends React.Component<DocumentationAllProps, DocumentationState> { constructor(props: DocumentationAllProps) { super(props); this.state = { @@ -103,15 +90,15 @@ export class Documentation extends const versions = findVersions(lastSegment); const preferredVersionIfExists = versions.length > 0 ? versions[0] : undefined; // tslint:disable-next-line:no-floating-promises - this.fetchJSONDocsFireAndForgetAsync(preferredVersionIfExists); + this._fetchJSONDocsFireAndForgetAsync(preferredVersionIfExists); } public render() { - const menuSubsectionsBySection = _.isUndefined(this.state.docAgnosticFormat) ? - {} : - this.props.docsInfo.getMenuSubsectionsBySection(this.state.docAgnosticFormat); + const menuSubsectionsBySection = _.isUndefined(this.state.docAgnosticFormat) + ? {} + : this.props.docsInfo.getMenuSubsectionsBySection(this.state.docAgnosticFormat); return ( <div> - <DocumentTitle title={`${this.props.docsInfo.displayName} Documentation`}/> + <DocumentTitle title={`${this.props.docsInfo.displayName} Documentation`} /> <TopBar blockchainIsLoaded={false} location={this.props.location} @@ -122,29 +109,26 @@ export class Documentation extends shouldFullWidth={true} docsInfo={this.props.docsInfo} /> - {_.isUndefined(this.state.docAgnosticFormat) ? - <div - className="col col-12" - style={styles.mainContainers} - > + {_.isUndefined(this.state.docAgnosticFormat) ? ( + <div className="col col-12" style={styles.mainContainers}> <div className="relative sm-px2 sm-pt2 sm-m1" - style={{height: 122, top: '50%', transform: 'translateY(-50%)'}} + style={{ height: 122, top: '50%', transform: 'translateY(-50%)' }} > <div className="center pb2"> <CircularProgress size={40} thickness={5} /> </div> - <div className="center pt2" style={{paddingBottom: 11}}>Loading documentation...</div> + <div className="center pt2" style={{ paddingBottom: 11 }}> + Loading documentation... + </div> </div> - </div> : - <div - className="mx-auto flex" - style={{color: colors.grey800, height: 43}} - > + </div> + ) : ( + <div className="mx-auto flex" style={{ color: colors.grey800, height: 43 }}> <div className="relative col md-col-3 lg-col-3 lg-pl0 md-pl1 sm-hide xs-hide"> <div className="border-right absolute" - style={{...styles.menuContainer, ...styles.mainContainers}} + style={{ ...styles.menuContainer, ...styles.mainContainers }} > <NestedSidebarMenu selectedVersion={this.props.docsVersion} @@ -156,35 +140,31 @@ export class Documentation extends </div> </div> <div className="relative col lg-col-9 md-col-9 sm-col-12 col-12"> - <div - id="documentation" - style={styles.mainContainers} - className="absolute" - > + <div id="documentation" style={styles.mainContainers} className="absolute"> <div id={SCROLL_TOP_ID} /> <h1 className="md-pl2 sm-pl3"> <a href={this.props.docsInfo.packageUrl} target="_blank"> {this.props.docsInfo.displayName} </a> </h1> - {this.renderDocumentation()} + {this._renderDocumentation()} </div> </div> </div> - } + )} </div> ); } - private renderDocumentation(): React.ReactNode { + private _renderDocumentation(): React.ReactNode { const subMenus = _.values(this.props.docsInfo.getMenu()); const orderedSectionNames = _.flatten(subMenus); const typeDefinitionByName = this.props.docsInfo.getTypeDefinitionsByName(this.state.docAgnosticFormat); - const renderedSections = _.map(orderedSectionNames, this.renderSection.bind(this, typeDefinitionByName)); + const renderedSections = _.map(orderedSectionNames, this._renderSection.bind(this, typeDefinitionByName)); return renderedSections; } - private renderSection(typeDefinitionByName: TypeDefinitionByName, sectionName: string): React.ReactNode { + private _renderSection(typeDefinitionByName: TypeDefinitionByName, sectionName: string): React.ReactNode { const markdownFileIfExists = this.props.docsInfo.sectionNameToMarkdown[sectionName]; if (!_.isUndefined(markdownFileIfExists)) { return ( @@ -205,6 +185,7 @@ export class Documentation extends const typeDefs = _.map(sortedTypes, customType => { return ( <TypeDefinition + sectionName={sectionName} key={`type-${customType.name}`} customType={customType} docsInfo={this.props.docsInfo} @@ -213,12 +194,12 @@ export class Documentation extends }); const sortedProperties = _.sortBy(docSection.properties, 'name'); - const propertyDefs = _.map(sortedProperties, this.renderProperty.bind(this)); + const propertyDefs = _.map(sortedProperties, this._renderProperty.bind(this, sectionName)); const sortedMethods = _.sortBy(docSection.methods, 'name'); const methodDefs = _.map(sortedMethods, method => { const isConstructor = false; - return this.renderMethodBlocks(method, sectionName, isConstructor, typeDefinitionByName); + return this._renderMethodBlocks(method, sectionName, isConstructor, typeDefinitionByName); }); const sortedEvents = _.sortBy(docSection.events, 'name'); @@ -227,148 +208,143 @@ export class Documentation extends <EventDefinition key={`event-${event.name}-${i}`} event={event} + sectionName={sectionName} docsInfo={this.props.docsInfo} /> ); }); return ( - <div - key={`section-${sectionName}`} - className="py2 pr3 md-pl2 sm-pl3" - > + <div key={`section-${sectionName}`} className="py2 pr3 md-pl2 sm-pl3"> <div className="flex"> - <div style={{marginRight: 7}}> - <SectionHeader sectionName={sectionName} /> - </div> - {this.renderNetworkBadgesIfExists(sectionName)} + <div style={{ marginRight: 7 }}> + <SectionHeader sectionName={sectionName} /> + </div> + {this._renderNetworkBadgesIfExists(sectionName)} </div> - {docSection.comment && - <Comment - comment={docSection.comment} - /> - } + {docSection.comment && <Comment comment={docSection.comment} />} {docSection.constructors.length > 0 && - this.props.docsInfo.isVisibleConstructor(sectionName) && - <div> - <h2 className="thin">Constructor</h2> - {this.renderConstructors(docSection.constructors, sectionName, typeDefinitionByName)} - </div> - } - {docSection.properties.length > 0 && + this.props.docsInfo.isVisibleConstructor(sectionName) && ( + <div> + <h2 className="thin">Constructor</h2> + {this._renderConstructors(docSection.constructors, sectionName, typeDefinitionByName)} + </div> + )} + {docSection.properties.length > 0 && ( <div> <h2 className="thin">Properties</h2> <div>{propertyDefs}</div> </div> - } - {docSection.methods.length > 0 && + )} + {docSection.methods.length > 0 && ( <div> <h2 className="thin">Methods</h2> <div>{methodDefs}</div> </div> - } - {!_.isUndefined(docSection.events) && docSection.events.length > 0 && - <div> - <h2 className="thin">Events</h2> - <div>{eventDefs}</div> - </div> - } - {!_.isUndefined(typeDefs) && typeDefs.length > 0 && - <div> - <div>{typeDefs}</div> - </div> - } + )} + {!_.isUndefined(docSection.events) && + docSection.events.length > 0 && ( + <div> + <h2 className="thin">Events</h2> + <div>{eventDefs}</div> + </div> + )} + {!_.isUndefined(typeDefs) && + typeDefs.length > 0 && ( + <div> + <div>{typeDefs}</div> + </div> + )} </div> ); } - private renderNetworkBadgesIfExists(sectionName: string) { - const networkToAddressByContractName = constants.contractAddresses[this.props.docsVersion]; - const badges = _.map(networkToAddressByContractName, + private _renderNetworkBadgesIfExists(sectionName: string) { + const networkToAddressByContractName = configs.CONTRACT_ADDRESS[this.props.docsVersion]; + const badges = _.map( + networkToAddressByContractName, (addressByContractName: AddressByContractName, networkName: string) => { const contractAddress = addressByContractName[sectionName]; if (_.isUndefined(contractAddress)) { return null; } const linkIfExists = utils.getEtherScanLinkIfExists( - contractAddress, constants.networkIdByName[networkName], EtherscanLinkSuffixes.address, + contractAddress, + constants.NETWORK_ID_BY_NAME[networkName], + EtherscanLinkSuffixes.Address, ); return ( <a key={`badge-${networkName}-${sectionName}`} href={linkIfExists} target="_blank" - style={{color: 'white', textDecoration: 'none'}} + style={{ color: colors.white, textDecoration: 'none' }} > - <Badge - title={networkName} - backgroundColor={networkNameToColor[networkName]} - /> + <Badge title={networkName} backgroundColor={networkNameToColor[networkName]} /> </a> ); - }); + }, + ); return badges; } - private renderConstructors(constructors: SolidityMethod[]|TypescriptMethod[], - sectionName: string, - typeDefinitionByName: TypeDefinitionByName): React.ReactNode { + private _renderConstructors( + constructors: SolidityMethod[] | TypescriptMethod[], + sectionName: string, + typeDefinitionByName: TypeDefinitionByName, + ): React.ReactNode { const constructorDefs = _.map(constructors, constructor => { - return this.renderMethodBlocks( - constructor, sectionName, constructor.isConstructor, typeDefinitionByName, - ); + return this._renderMethodBlocks(constructor, sectionName, constructor.isConstructor, typeDefinitionByName); }); - return ( - <div> - {constructorDefs} - </div> - ); + return <div>{constructorDefs}</div>; } - private renderProperty(property: Property): React.ReactNode { + private _renderProperty(sectionName: string, property: Property): React.ReactNode { return ( - <div - key={`property-${property.name}-${property.type.name}`} - className="pb3" - > + <div key={`property-${property.name}-${property.type.name}`} className="pb3"> <code className="hljs"> - {property.name}: <Type type={property.type} docsInfo={this.props.docsInfo} /> + {property.name}: + <Type type={property.type} sectionName={sectionName} docsInfo={this.props.docsInfo} /> </code> - {property.source && + {property.source && ( <SourceLink version={this.props.docsVersion} source={property.source} baseUrl={this.props.docsInfo.packageUrl} subPackageName={this.props.docsInfo.subPackageName} /> - } - {property.comment && - <Comment - comment={property.comment} - className="py2" - /> - } + )} + {property.comment && <Comment comment={property.comment} className="py2" />} </div> ); } - private renderMethodBlocks(method: SolidityMethod|TypescriptMethod, sectionName: string, - isConstructor: boolean, typeDefinitionByName: TypeDefinitionByName): React.ReactNode { + private _renderMethodBlocks( + method: SolidityMethod | TypescriptMethod, + sectionName: string, + isConstructor: boolean, + typeDefinitionByName: TypeDefinitionByName, + ): React.ReactNode { return ( <MethodBlock - key={`method-${method.name}-${sectionName}`} - method={method} - typeDefinitionByName={typeDefinitionByName} - libraryVersion={this.props.docsVersion} - docsInfo={this.props.docsInfo} + key={`method-${method.name}-${sectionName}`} + sectionName={sectionName} + method={method} + typeDefinitionByName={typeDefinitionByName} + libraryVersion={this.props.docsVersion} + docsInfo={this.props.docsInfo} /> ); } - private scrollToHash(): void { + private _scrollToHash(): void { const hashWithPrefix = this.props.location.hash; let hash = hashWithPrefix.slice(1); if (_.isEmpty(hash)) { hash = SCROLL_TOP_ID; // scroll to the top } - scroller.scrollTo(hash, {duration: 0, offset: 0, containerId: 'documentation'}); + scroller.scrollTo(hash, { + duration: 0, + offset: 0, + containerId: 'documentation', + }); } - private async fetchJSONDocsFireAndForgetAsync(preferredVersionIfExists?: string): Promise<void> { + private async _fetchJSONDocsFireAndForgetAsync(preferredVersionIfExists?: string): Promise<void> { const versionToFileName = await docUtils.getVersionToFileNameAsync(this.props.docsInfo.docsJsonRoot); const versions = _.keys(versionToFileName); this.props.dispatcher.updateAvailableDocVersions(versions); @@ -386,14 +362,18 @@ export class Documentation extends const versionFileNameToFetch = versionToFileName[versionToFetch]; const versionDocObj = await docUtils.getJSONDocFileAsync( - versionFileNameToFetch, this.props.docsInfo.docsJsonRoot, + versionFileNameToFetch, + this.props.docsInfo.docsJsonRoot, ); const docAgnosticFormat = this.props.docsInfo.convertToDocAgnosticFormat(versionDocObj as DoxityDocObj); - this.setState({ - docAgnosticFormat, - }, () => { - this.scrollToHash(); - }); + this.setState( + { + docAgnosticFormat, + }, + () => { + this._scrollToHash(); + }, + ); } } diff --git a/packages/website/ts/pages/documentation/enum.tsx b/packages/website/ts/pages/documentation/enum.tsx index 8fcd2c252..7dfdee771 100644 --- a/packages/website/ts/pages/documentation/enum.tsx +++ b/packages/website/ts/pages/documentation/enum.tsx @@ -1,9 +1,6 @@ import * as _ from 'lodash'; import * as React from 'react'; -import {EnumValue, TypeDocNode} from 'ts/types'; -import {utils} from 'ts/utils/utils'; - -const STRING_ENUM_CODE_PREFIX = ' strEnum('; +import { EnumValue } from 'ts/types'; interface EnumProps { values: EnumValue[]; @@ -11,15 +8,14 @@ interface EnumProps { export function Enum(props: EnumProps) { const values = _.map(props.values, (value, i) => { - const isLast = i === props.values.length - 1; const defaultValueIfAny = !_.isUndefined(value.defaultValue) ? ` = ${value.defaultValue}` : ''; return `\n\t${value.name}${defaultValueIfAny},`; }); return ( <span> {`{`} - {values} - <br /> + {values} + <br /> {`}`} </span> ); diff --git a/packages/website/ts/pages/documentation/event_definition.tsx b/packages/website/ts/pages/documentation/event_definition.tsx index 469e6bb37..0e53e38e7 100644 --- a/packages/website/ts/pages/documentation/event_definition.tsx +++ b/packages/website/ts/pages/documentation/event_definition.tsx @@ -1,17 +1,14 @@ import * as _ from 'lodash'; import * as React from 'react'; -import {DocsInfo} from 'ts/pages/documentation/docs_info'; -import {Type} from 'ts/pages/documentation/type'; -import {AnchorTitle} from 'ts/pages/shared/anchor_title'; -import {Event, EventArg, HeaderSizes} from 'ts/types'; -import {constants} from 'ts/utils/constants'; -import {utils} from 'ts/utils/utils'; - -const KEYWORD_COLOR = '#a81ca6'; -const CUSTOM_GREEN = 'rgb(77, 162, 75)'; +import { DocsInfo } from 'ts/pages/documentation/docs_info'; +import { Type } from 'ts/pages/documentation/type'; +import { AnchorTitle } from 'ts/pages/shared/anchor_title'; +import { Event, EventArg, HeaderSizes } from 'ts/types'; +import { colors } from 'ts/utils/colors'; interface EventDefinitionProps { event: Event; + sectionName: string; docsInfo: DocsInfo; } @@ -30,11 +27,11 @@ export class EventDefinition extends React.Component<EventDefinitionProps, Event const event = this.props.event; return ( <div - id={event.name} + id={`${this.props.sectionName}-${event.name}`} className="pb2" - style={{overflow: 'hidden', width: '100%'}} - onMouseOver={this.setAnchorVisibility.bind(this, true)} - onMouseOut={this.setAnchorVisibility.bind(this, false)} + style={{ overflow: 'hidden', width: '100%' }} + onMouseOver={this._setAnchorVisibility.bind(this, true)} + onMouseOut={this._setAnchorVisibility.bind(this, false)} > <AnchorTitle headerSize={HeaderSizes.H3} @@ -42,28 +39,24 @@ export class EventDefinition extends React.Component<EventDefinitionProps, Event id={event.name} shouldShowAnchor={this.state.shouldShowAnchor} /> - <div style={{fontSize: 16}}> + <div style={{ fontSize: 16 }}> <pre> - <code className="hljs"> - {this.renderEventCode()} - </code> + <code className="hljs">{this._renderEventCode()}</code> </pre> </div> </div> ); } - private renderEventCode() { - const indexed = <span style={{color: CUSTOM_GREEN}}> indexed</span>; + private _renderEventCode() { + const indexed = <span style={{ color: colors.green }}> indexed</span>; const eventArgs = _.map(this.props.event.eventArgs, (eventArg: EventArg) => { const type = ( - <Type - type={eventArg.type} - docsInfo={this.props.docsInfo} - /> + <Type type={eventArg.type} sectionName={this.props.sectionName} docsInfo={this.props.docsInfo} /> ); return ( <span key={`eventArg-${eventArg.name}`}> - {eventArg.name}{eventArg.isIndexed ? indexed : ''}: {type}, + {eventArg.name} + {eventArg.isIndexed ? indexed : ''}: {type}, </span> ); }); @@ -73,14 +66,15 @@ export class EventDefinition extends React.Component<EventDefinitionProps, Event return ( <span> {`{`} - <br /> - {'\t'}{argList} - <br /> + <br /> + {'\t'} + {argList} + <br /> {`}`} </span> ); } - private setAnchorVisibility(shouldShowAnchor: boolean) { + private _setAnchorVisibility(shouldShowAnchor: boolean) { this.setState({ shouldShowAnchor, }); diff --git a/packages/website/ts/pages/documentation/interface.tsx b/packages/website/ts/pages/documentation/interface.tsx index e671db2b8..16a772125 100644 --- a/packages/website/ts/pages/documentation/interface.tsx +++ b/packages/website/ts/pages/documentation/interface.tsx @@ -1,12 +1,13 @@ import * as _ from 'lodash'; import * as React from 'react'; -import {DocsInfo} from 'ts/pages/documentation/docs_info'; -import {MethodSignature} from 'ts/pages/documentation/method_signature'; -import {Type} from 'ts/pages/documentation/type'; -import {CustomType, TypeDocTypes} from 'ts/types'; +import { DocsInfo } from 'ts/pages/documentation/docs_info'; +import { MethodSignature } from 'ts/pages/documentation/method_signature'; +import { Type } from 'ts/pages/documentation/type'; +import { CustomType, TypeDocTypes } from 'ts/types'; interface InterfaceProps { type: CustomType; + sectionName: string; docsInfo: DocsInfo; } @@ -16,15 +17,17 @@ export function Interface(props: InterfaceProps) { return ( <span key={`property-${property.name}-${property.type}-${type.name}`}> {property.name}:{' '} - {property.type.typeDocType !== TypeDocTypes.Reflection ? - <Type type={property.type} docsInfo={props.docsInfo} /> : + {property.type.typeDocType !== TypeDocTypes.Reflection ? ( + <Type type={property.type} sectionName={props.sectionName} docsInfo={props.docsInfo} /> + ) : ( <MethodSignature method={property.type.method} + sectionName={props.sectionName} shouldHideMethodName={true} shouldUseArrowSyntax={true} docsInfo={props.docsInfo} /> - }, + )}, </span> ); }); @@ -33,14 +36,14 @@ export function Interface(props: InterfaceProps) { const is = type.indexSignature; const param = ( <span key={`indexSigParams-${is.keyName}-${is.keyType}-${type.name}`}> - {is.keyName}: <Type type={is.keyType} docsInfo={props.docsInfo} /> + {is.keyName}: <Type type={is.keyType} sectionName={props.sectionName} docsInfo={props.docsInfo} /> </span> ); - properties.push(( + properties.push( <span key={`indexSignature-${type.name}-${is.keyType.name}`}> [{param}]: {is.valueName}, - </span> - )); + </span>, + ); } const propertyList = _.reduce(properties, (prev: React.ReactNode, curr: React.ReactNode) => { return [prev, '\n\t', curr]; @@ -48,9 +51,10 @@ export function Interface(props: InterfaceProps) { return ( <span> {`{`} - <br /> - {'\t'}{propertyList} - <br /> + <br /> + {'\t'} + {propertyList} + <br /> {`}`} </span> ); diff --git a/packages/website/ts/pages/documentation/method_block.tsx b/packages/website/ts/pages/documentation/method_block.tsx index 44e549211..dfde5931b 100644 --- a/packages/website/ts/pages/documentation/method_block.tsx +++ b/packages/website/ts/pages/documentation/method_block.tsx @@ -1,27 +1,17 @@ import * as _ from 'lodash'; -import {Chip} from 'material-ui/Chip'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; -import * as ReactMarkdown from 'react-markdown'; -import {Comment} from 'ts/pages/documentation/comment'; -import {DocsInfo} from 'ts/pages/documentation/docs_info'; -import {MethodSignature} from 'ts/pages/documentation/method_signature'; -import {SourceLink} from 'ts/pages/documentation/source_link'; -import {AnchorTitle} from 'ts/pages/shared/anchor_title'; -import { - HeaderSizes, - Parameter, - SolidityMethod, - Styles, - TypeDefinitionByName, - TypeDocNode, - TypescriptMethod, -} from 'ts/types'; -import {typeDocUtils} from 'ts/utils/typedoc_utils'; -import {utils} from 'ts/utils/utils'; +import { Comment } from 'ts/pages/documentation/comment'; +import { DocsInfo } from 'ts/pages/documentation/docs_info'; +import { MethodSignature } from 'ts/pages/documentation/method_signature'; +import { SourceLink } from 'ts/pages/documentation/source_link'; +import { AnchorTitle } from 'ts/pages/shared/anchor_title'; +import { HeaderSizes, Parameter, SolidityMethod, Styles, TypeDefinitionByName, TypescriptMethod } from 'ts/types'; +import { colors } from 'ts/utils/colors'; +import { typeDocUtils } from 'ts/utils/typedoc_utils'; interface MethodBlockProps { - method: SolidityMethod|TypescriptMethod; + method: SolidityMethod | TypescriptMethod; + sectionName: string; libraryVersion: string; typeDefinitionByName: TypeDefinitionByName; docsInfo: DocsInfo; @@ -35,7 +25,7 @@ const styles: Styles = { chip: { fontSize: 13, backgroundColor: colors.lightBlueA700, - color: 'white', + color: colors.white, height: 11, borderRadius: 14, marginTop: 19, @@ -58,119 +48,93 @@ export class MethodBlock extends React.Component<MethodBlockProps, MethodBlockSt return ( <div - id={method.name} - style={{overflow: 'hidden', width: '100%'}} + id={`${this.props.sectionName}-${method.name}`} + style={{ overflow: 'hidden', width: '100%' }} className="pb4" - onMouseOver={this.setAnchorVisibility.bind(this, true)} - onMouseOut={this.setAnchorVisibility.bind(this, false)} + onMouseOver={this._setAnchorVisibility.bind(this, true)} + onMouseOut={this._setAnchorVisibility.bind(this, false)} > - {!method.isConstructor && + {!method.isConstructor && ( <div className="flex"> - {(method as TypescriptMethod).isStatic && - this.renderChip('Static') - } - {(method as SolidityMethod).isConstant && - this.renderChip('Constant') - } - {(method as SolidityMethod).isPayable && - this.renderChip('Payable') - } + {(method as TypescriptMethod).isStatic && this._renderChip('Static')} + {(method as SolidityMethod).isConstant && this._renderChip('Constant')} + {(method as SolidityMethod).isPayable && this._renderChip('Payable')} <AnchorTitle headerSize={HeaderSizes.H3} title={method.name} - id={method.name} + id={`${this.props.sectionName}-${method.name}`} shouldShowAnchor={this.state.shouldShowAnchor} /> </div> - } + )} <code className="hljs"> <MethodSignature method={method} + sectionName={this.props.sectionName} typeDefinitionByName={this.props.typeDefinitionByName} docsInfo={this.props.docsInfo} /> </code> - {(method as TypescriptMethod).source && + {(method as TypescriptMethod).source && ( <SourceLink version={this.props.libraryVersion} source={(method as TypescriptMethod).source} baseUrl={this.props.docsInfo.packageUrl} subPackageName={this.props.docsInfo.subPackageName} /> - } - {method.comment && - <Comment - comment={method.comment} - className="py2" - /> - } - {method.parameters && !_.isEmpty(method.parameters) && - <div> - <h4 - className="pb1 thin" - style={{borderBottom: '1px solid #e1e8ed'}} - > - ARGUMENTS - </h4> - {this.renderParameterDescriptions(method.parameters)} - </div> - } - {method.returnComment && + )} + {method.comment && <Comment comment={method.comment} className="py2" />} + {method.parameters && + !_.isEmpty(method.parameters) && ( + <div> + <h4 className="pb1 thin" style={{ borderBottom: '1px solid #e1e8ed' }}> + ARGUMENTS + </h4> + {this._renderParameterDescriptions(method.parameters)} + </div> + )} + {method.returnComment && ( <div className="pt1 comment"> - <h4 - className="pb1 thin" - style={{borderBottom: '1px solid #e1e8ed'}} - > + <h4 className="pb1 thin" style={{ borderBottom: '1px solid #e1e8ed' }}> RETURNS </h4> - <Comment - comment={method.returnComment} - /> + <Comment comment={method.returnComment} /> </div> - } + )} </div> ); } - private renderChip(text: string) { + private _renderChip(text: string) { return ( - <div - className="p1 mr1" - style={styles.chip} - > + <div className="p1 mr1" style={styles.chip}> {text} </div> ); } - private renderParameterDescriptions(parameters: Parameter[]) { + private _renderParameterDescriptions(parameters: Parameter[]) { const descriptions = _.map(parameters, parameter => { const isOptional = parameter.isOptional; return ( <div key={`param-description-${parameter.name}`} className="flex pb1 mb2" - style={{borderBottom: '1px solid #f0f4f7'}} + style={{ borderBottom: '1px solid #f0f4f7' }} > <div className="pl2 col lg-col-4 md-col-4 sm-col-12 col-12"> - <div className="bold"> - {parameter.name} - </div> - <div className="pt1" style={{color: colors.grey500, fontSize: 14}}> + <div className="bold">{parameter.name}</div> + <div className="pt1" style={{ color: colors.grey, fontSize: 14 }}> {isOptional && 'optional'} </div> </div> <div className="col lg-col-8 md-col-8 sm-col-12 col-12"> - {parameter.comment && - <Comment - comment={parameter.comment} - /> - } + {parameter.comment && <Comment comment={parameter.comment} />} </div> </div> ); }); return descriptions; } - private setAnchorVisibility(shouldShowAnchor: boolean) { + private _setAnchorVisibility(shouldShowAnchor: boolean) { this.setState({ shouldShowAnchor, }); diff --git a/packages/website/ts/pages/documentation/method_signature.tsx b/packages/website/ts/pages/documentation/method_signature.tsx index 846c9fa4f..041dcd093 100644 --- a/packages/website/ts/pages/documentation/method_signature.tsx +++ b/packages/website/ts/pages/documentation/method_signature.tsx @@ -1,11 +1,13 @@ import * as _ from 'lodash'; import * as React from 'react'; -import {DocsInfo} from 'ts/pages/documentation/docs_info'; -import {Type} from 'ts/pages/documentation/type'; -import {Parameter, SolidityMethod, TypeDefinitionByName, TypescriptMethod} from 'ts/types'; +import { DocsInfo } from 'ts/pages/documentation/docs_info'; +import { Type } from 'ts/pages/documentation/type'; +import { Parameter, SolidityMethod, TypeDefinitionByName, TypescriptMethod } from 'ts/types'; +import { constants } from 'ts/utils/constants'; interface MethodSignatureProps { - method: TypescriptMethod|SolidityMethod; + method: TypescriptMethod | SolidityMethod; + sectionName: string; shouldHideMethodName?: boolean; shouldUseArrowSyntax?: boolean; typeDefinitionByName?: TypeDefinitionByName; @@ -18,32 +20,40 @@ const defaultProps = { }; export const MethodSignature: React.SFC<MethodSignatureProps> = (props: MethodSignatureProps) => { - const parameters = renderParameters(props.method, props.docsInfo, props.typeDefinitionByName); + const sectionName = constants.TYPES_SECTION_NAME; + const parameters = renderParameters(props.method, props.docsInfo, sectionName, props.typeDefinitionByName); const paramString = _.reduce(parameters, (prev: React.ReactNode, curr: React.ReactNode) => { return [prev, ', ', curr]; }); const methodName = props.shouldHideMethodName ? '' : props.method.name; - const typeParameterIfExists = _.isUndefined((props.method as TypescriptMethod).typeParameter) ? - undefined : - renderTypeParameter(props.method, props.docsInfo, props.typeDefinitionByName); + const typeParameterIfExists = _.isUndefined((props.method as TypescriptMethod).typeParameter) + ? undefined + : renderTypeParameter(props.method, props.docsInfo, sectionName, props.typeDefinitionByName); return ( <span> - {props.method.callPath}{methodName}{typeParameterIfExists}({paramString}) - {props.shouldUseArrowSyntax ? ' => ' : ': '} - {' '} - {props.method.returnType && + {props.method.callPath} + {methodName} + {typeParameterIfExists}({paramString}) + {props.shouldUseArrowSyntax ? ' => ' : ': '}{' '} + {props.method.returnType && ( <Type type={props.method.returnType} + sectionName={sectionName} typeDefinitionByName={props.typeDefinitionByName} docsInfo={props.docsInfo} /> - } + )} </span> ); }; +MethodSignature.defaultProps = defaultProps; + function renderParameters( - method: TypescriptMethod|SolidityMethod, docsInfo: DocsInfo, typeDefinitionByName?: TypeDefinitionByName, + method: TypescriptMethod | SolidityMethod, + docsInfo: DocsInfo, + sectionName: string, + typeDefinitionByName?: TypeDefinitionByName, ) { const parameters = method.parameters; const params = _.map(parameters, (p: Parameter) => { @@ -51,13 +61,15 @@ function renderParameters( const type = ( <Type type={p.type} + sectionName={sectionName} typeDefinitionByName={typeDefinitionByName} docsInfo={docsInfo} /> ); return ( <span key={`param-${p.type}-${p.name}`}> - {p.name}{isOptional && '?'}: {type} + {p.name} + {isOptional && '?'}: {type} </span> ); }); @@ -65,17 +77,21 @@ function renderParameters( } function renderTypeParameter( - method: TypescriptMethod, docsInfo: DocsInfo, typeDefinitionByName?: TypeDefinitionByName, + method: TypescriptMethod, + docsInfo: DocsInfo, + sectionName: string, + typeDefinitionByName?: TypeDefinitionByName, ) { const typeParameter = method.typeParameter; const typeParam = ( <span> {`<${typeParameter.name} extends `} - <Type - type={typeParameter.type} - typeDefinitionByName={typeDefinitionByName} - docsInfo={docsInfo} - /> + <Type + type={typeParameter.type} + sectionName={sectionName} + typeDefinitionByName={typeDefinitionByName} + docsInfo={docsInfo} + /> {`>`} </span> ); diff --git a/packages/website/ts/pages/documentation/source_link.tsx b/packages/website/ts/pages/documentation/source_link.tsx index 74fc6d4d5..6588ee39e 100644 --- a/packages/website/ts/pages/documentation/source_link.tsx +++ b/packages/website/ts/pages/documentation/source_link.tsx @@ -1,8 +1,7 @@ import * as _ from 'lodash'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; -import {Source} from 'ts/types'; -import {constants} from 'ts/utils/constants'; +import { Source } from 'ts/types'; +import { colors } from 'ts/utils/colors'; interface SourceLinkProps { source: Source; @@ -11,9 +10,7 @@ interface SourceLinkProps { subPackageName: string; } -const packagesWithNamespace = [ - 'connect', -]; +const packagesWithNamespace = ['connect']; export function SourceLink(props: SourceLinkProps) { const src = props.source; @@ -25,13 +22,8 @@ export function SourceLink(props: SourceLinkProps) { } const sourceCodeUrl = `${url}/blob/${tagPrefix}%40${props.version}/packages/${pkg}/${src.fileName}#L${src.line}`; return ( - <div className="pt2" style={{fontSize: 14}}> - <a - href={sourceCodeUrl} - target="_blank" - className="underline" - style={{color: colors.grey500}} - > + <div className="pt2" style={{ fontSize: 14 }}> + <a href={sourceCodeUrl} target="_blank" className="underline" style={{ color: colors.grey }}> Source </a> </div> diff --git a/packages/website/ts/pages/documentation/type.tsx b/packages/website/ts/pages/documentation/type.tsx index c564429d0..e989e7129 100644 --- a/packages/website/ts/pages/documentation/type.tsx +++ b/packages/website/ts/pages/documentation/type.tsx @@ -1,34 +1,30 @@ import * as _ from 'lodash'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; -import {Link as ScrollLink} from 'react-scroll'; +import { Link as ScrollLink } from 'react-scroll'; import * as ReactTooltip from 'react-tooltip'; -import {DocsInfo} from 'ts/pages/documentation/docs_info'; -import {TypeDefinition} from 'ts/pages/documentation/type_definition'; -import {Type as TypeDef, TypeDefinitionByName, TypeDocTypes} from 'ts/types'; -import {constants} from 'ts/utils/constants'; -import {typeDocUtils} from 'ts/utils/typedoc_utils'; -import {utils} from 'ts/utils/utils'; - -const BUILT_IN_TYPE_COLOR = '#e69d00'; -const STRING_LITERAL_COLOR = '#4da24b'; +import { DocsInfo } from 'ts/pages/documentation/docs_info'; +import { TypeDefinition } from 'ts/pages/documentation/type_definition'; +import { Type as TypeDef, TypeDefinitionByName, TypeDocTypes } from 'ts/types'; +import { colors } from 'ts/utils/colors'; +import { constants } from 'ts/utils/constants'; +import { utils } from 'ts/utils/utils'; // Some types reference other libraries. For these types, we want to link the user to the relevant documentation. -const typeToUrl: {[typeName: string]: string} = { - Web3: constants.WEB3_DOCS_URL, - Provider: constants.WEB3_PROVIDER_DOCS_URL, - BigNumber: constants.BIGNUMBERJS_GITHUB_URL, - DecodedLogEntryEvent: constants.WEB3_DECODED_LOG_ENTRY_EVENT_URL, - LogEntryEvent: constants.WEB3_LOG_ENTRY_EVENT_URL, +const typeToUrl: { [typeName: string]: string } = { + Web3: constants.URL_WEB3_DOCS, + Provider: constants.URL_WEB3_PROVIDER_DOCS, + BigNumber: constants.URL_BIGNUMBERJS_GITHUB, + DecodedLogEntryEvent: constants.URL_WEB3_DECODED_LOG_ENTRY_EVENT, + LogEntryEvent: constants.URL_WEB3_LOG_ENTRY_EVENT, }; -const typePrefix: {[typeName: string]: string} = { +const typePrefix: { [typeName: string]: string } = { Provider: 'Web3', DecodedLogEntryEvent: 'Web3', LogEntryEvent: 'Web3', }; -const typeToSection: {[typeName: string]: string} = { +const typeToSection: { [typeName: string]: string } = { ExchangeWrapper: 'exchange', TokenWrapper: 'token', TokenRegistryWrapper: 'tokenRegistry', @@ -41,6 +37,7 @@ const typeToSection: {[typeName: string]: string} = { interface TypeProps { type: TypeDef; docsInfo: DocsInfo; + sectionName: string; typeDefinitionByName?: TypeDefinitionByName; } @@ -48,18 +45,16 @@ interface TypeProps { // <Type /> components (e.g when rendering the union type). export function Type(props: TypeProps): any { const type = props.type; - const isIntrinsic = type.typeDocType === TypeDocTypes.Intrinsic; const isReference = type.typeDocType === TypeDocTypes.Reference; const isArray = type.typeDocType === TypeDocTypes.Array; - const isStringLiteral = type.typeDocType === TypeDocTypes.StringLiteral; let typeNameColor = 'inherit'; - let typeName: string|React.ReactNode; + let typeName: string | React.ReactNode; let typeArgs: React.ReactNode[] = []; switch (type.typeDocType) { case TypeDocTypes.Intrinsic: case TypeDocTypes.Unknown: typeName = type.name; - typeNameColor = BUILT_IN_TYPE_COLOR; + typeNameColor = colors.orange; break; case TypeDocTypes.Reference: @@ -72,6 +67,7 @@ export function Type(props: TypeProps): any { <Type key={key} type={arg.elementType} + sectionName={props.sectionName} typeDefinitionByName={props.typeDefinitionByName} docsInfo={props.docsInfo} />[] @@ -82,6 +78,7 @@ export function Type(props: TypeProps): any { <Type key={`type-${arg.name}-${arg.value}-${arg.typeDocType}`} type={arg} + sectionName={props.sectionName} typeDefinitionByName={props.typeDefinitionByName} docsInfo={props.docsInfo} /> @@ -93,7 +90,7 @@ export function Type(props: TypeProps): any { case TypeDocTypes.StringLiteral: typeName = `'${type.value}'`; - typeNameColor = STRING_LITERAL_COLOR; + typeNameColor = colors.green; break; case TypeDocTypes.Array: @@ -106,6 +103,7 @@ export function Type(props: TypeProps): any { <Type key={`type-${t.name}-${t.value}-${t.typeDocType}`} type={t} + sectionName={props.sectionName} typeDefinitionByName={props.typeDefinitionByName} docsInfo={props.docsInfo} /> @@ -132,25 +130,29 @@ export function Type(props: TypeProps): any { return [prev, ', ', curr]; }); - const typeNameUrlIfExists = typeToUrl[(typeName as string)]; - const typePrefixIfExists = typePrefix[(typeName as string)]; - const sectionNameIfExists = typeToSection[(typeName as string)]; + const typeNameUrlIfExists = typeToUrl[typeName as string]; + const typePrefixIfExists = typePrefix[typeName as string]; + const sectionNameIfExists = typeToSection[typeName as string]; if (!_.isUndefined(typeNameUrlIfExists)) { typeName = ( <a href={typeNameUrlIfExists} target="_blank" className="text-decoration-none" - style={{color: colors.lightBlueA700}} + style={{ color: colors.lightBlueA700 }} > - {!_.isUndefined(typePrefixIfExists) ? `${typePrefixIfExists}.` : ''}{typeName} + {!_.isUndefined(typePrefixIfExists) ? `${typePrefixIfExists}.` : ''} + {typeName} </a> ); - } else if ((isReference || isArray) && - (props.docsInfo.isPublicType(typeName as string) || - !_.isUndefined(sectionNameIfExists))) { + } else if ( + (isReference || isArray) && + (props.docsInfo.isPublicType(typeName as string) || !_.isUndefined(sectionNameIfExists)) + ) { const id = Math.random().toString(); - const typeDefinitionAnchorId = _.isUndefined(sectionNameIfExists) ? typeName : sectionNameIfExists; + const typeDefinitionAnchorId = _.isUndefined(sectionNameIfExists) + ? `${props.sectionName}-${typeName}` + : sectionNameIfExists; let typeDefinition; if (props.typeDefinitionByName) { typeDefinition = props.typeDefinitionByName[typeName as string]; @@ -162,45 +164,49 @@ export function Type(props: TypeProps): any { duration={constants.DOCS_SCROLL_DURATION_MS} containerId={constants.DOCS_CONTAINER_ID} > - {_.isUndefined(typeDefinition) || utils.isUserOnMobile() ? - <span - onClick={utils.setUrlHash.bind(null, typeDefinitionAnchorId)} - style={{color: colors.lightBlueA700, cursor: 'pointer'}} - > - {typeName} - </span> : - <span - data-tip={true} - data-for={id} - onClick={utils.setUrlHash.bind(null, typeDefinitionAnchorId)} - style={{color: colors.lightBlueA700, cursor: 'pointer', display: 'inline-block'}} - > - {typeName} - <ReactTooltip - type="light" - effect="solid" - id={id} - className="typeTooltip" + {_.isUndefined(typeDefinition) || utils.isUserOnMobile() ? ( + <span + onClick={utils.setUrlHash.bind(null, typeDefinitionAnchorId)} + style={{ color: colors.lightBlueA700, cursor: 'pointer' }} > - <TypeDefinition - customType={typeDefinition} - shouldAddId={false} - docsInfo={props.docsInfo} - /> - </ReactTooltip> - </span> - } + {typeName} + </span> + ) : ( + <span + data-tip={true} + data-for={id} + onClick={utils.setUrlHash.bind(null, typeDefinitionAnchorId)} + style={{ + color: colors.lightBlueA700, + cursor: 'pointer', + display: 'inline-block', + }} + > + {typeName} + <ReactTooltip type="light" effect="solid" id={id} className="typeTooltip"> + <TypeDefinition + sectionName={props.sectionName} + customType={typeDefinition} + shouldAddId={false} + docsInfo={props.docsInfo} + /> + </ReactTooltip> + </span> + )} </ScrollLink> ); } return ( <span> - <span style={{color: typeNameColor}}>{typeName}</span> - {isArray && '[]'}{!_.isEmpty(typeArgs) && + <span style={{ color: typeNameColor }}>{typeName}</span> + {isArray && '[]'} + {!_.isEmpty(typeArgs) && ( <span> - {'<'}{commaSeparatedTypeArgs}{'>'} + {'<'} + {commaSeparatedTypeArgs} + {'>'} </span> - } + )} </span> ); } diff --git a/packages/website/ts/pages/documentation/type_definition.tsx b/packages/website/ts/pages/documentation/type_definition.tsx index 17b182c70..d46eec76c 100644 --- a/packages/website/ts/pages/documentation/type_definition.tsx +++ b/packages/website/ts/pages/documentation/type_definition.tsx @@ -1,21 +1,19 @@ import * as _ from 'lodash'; import * as React from 'react'; -import {Comment} from 'ts/pages/documentation/comment'; -import {CustomEnum} from 'ts/pages/documentation/custom_enum'; -import {DocsInfo} from 'ts/pages/documentation/docs_info'; -import {Enum} from 'ts/pages/documentation/enum'; -import {Interface} from 'ts/pages/documentation/interface'; -import {MethodSignature} from 'ts/pages/documentation/method_signature'; -import {Type} from 'ts/pages/documentation/type'; -import {AnchorTitle} from 'ts/pages/shared/anchor_title'; -import {CustomType, CustomTypeChild, HeaderSizes, KindString, TypeDocTypes} from 'ts/types'; -import {constants} from 'ts/utils/constants'; -import {typeDocUtils} from 'ts/utils/typedoc_utils'; -import {utils} from 'ts/utils/utils'; - -const KEYWORD_COLOR = '#a81ca6'; +import { Comment } from 'ts/pages/documentation/comment'; +import { CustomEnum } from 'ts/pages/documentation/custom_enum'; +import { DocsInfo } from 'ts/pages/documentation/docs_info'; +import { Enum } from 'ts/pages/documentation/enum'; +import { Interface } from 'ts/pages/documentation/interface'; +import { MethodSignature } from 'ts/pages/documentation/method_signature'; +import { Type } from 'ts/pages/documentation/type'; +import { AnchorTitle } from 'ts/pages/shared/anchor_title'; +import { CustomType, CustomTypeChild, HeaderSizes, KindString, TypeDocTypes } from 'ts/types'; +import { colors } from 'ts/utils/colors'; +import { utils } from 'ts/utils/utils'; interface TypeDefinitionProps { + sectionName: string; customType: CustomType; shouldAddId?: boolean; docsInfo: DocsInfo; @@ -47,20 +45,13 @@ export class TypeDefinition extends React.Component<TypeDefinitionProps, TypeDef case KindString.Interface: typePrefix = 'Interface'; codeSnippet = ( - <Interface - type={customType} - docsInfo={this.props.docsInfo} - /> + <Interface type={customType} sectionName={this.props.sectionName} docsInfo={this.props.docsInfo} /> ); break; case KindString.Variable: typePrefix = 'Enum'; - codeSnippet = ( - <CustomEnum - type={customType} - /> - ); + codeSnippet = <CustomEnum type={customType} />; break; case KindString.Enumeration: @@ -71,27 +62,29 @@ export class TypeDefinition extends React.Component<TypeDefinitionProps, TypeDef defaultValue: c.defaultValue, }; }); - codeSnippet = ( - <Enum - values={enumValues} - /> - ); + codeSnippet = <Enum values={enumValues} />; break; - case KindString['Type alias']: + case KindString.TypeAlias: typePrefix = 'Type Alias'; codeSnippet = ( <span> - <span style={{color: KEYWORD_COLOR}}>type</span> {customType.name} ={' '} - {customType.type.typeDocType !== TypeDocTypes.Reflection ? - <Type type={customType.type} docsInfo={this.props.docsInfo} /> : + <span style={{ color: colors.lightPurple }}>type</span> {customType.name} ={' '} + {customType.type.typeDocType !== TypeDocTypes.Reflection ? ( + <Type + type={customType.type} + sectionName={this.props.sectionName} + docsInfo={this.props.docsInfo} + /> + ) : ( <MethodSignature method={customType.type.method} + sectionName={this.props.sectionName} shouldHideMethodName={true} shouldUseArrowSyntax={true} docsInfo={this.props.docsInfo} /> - } + )} </span> ); break; @@ -100,14 +93,14 @@ export class TypeDefinition extends React.Component<TypeDefinitionProps, TypeDef throw utils.spawnSwitchErr('type.kindString', customType.kindString); } - const typeDefinitionAnchorId = customType.name; + const typeDefinitionAnchorId = `${this.props.sectionName}-${customType.name}`; return ( <div id={this.props.shouldAddId ? typeDefinitionAnchorId : ''} className="pb2" - style={{overflow: 'hidden', width: '100%'}} - onMouseOver={this.setAnchorVisibility.bind(this, true)} - onMouseOut={this.setAnchorVisibility.bind(this, false)} + style={{ overflow: 'hidden', width: '100%' }} + onMouseOver={this._setAnchorVisibility.bind(this, true)} + onMouseOut={this._setAnchorVisibility.bind(this, false)} > <AnchorTitle headerSize={HeaderSizes.H3} @@ -115,23 +108,16 @@ export class TypeDefinition extends React.Component<TypeDefinitionProps, TypeDef id={this.props.shouldAddId ? typeDefinitionAnchorId : ''} shouldShowAnchor={this.state.shouldShowAnchor} /> - <div style={{fontSize: 16}}> + <div style={{ fontSize: 16 }}> <pre> - <code className="hljs"> - {codeSnippet} - </code> + <code className="hljs">{codeSnippet}</code> </pre> </div> - {customType.comment && - <Comment - comment={customType.comment} - className="py2" - /> - } + {customType.comment && <Comment comment={customType.comment} className="py2" />} </div> ); } - private setAnchorVisibility(shouldShowAnchor: boolean) { + private _setAnchorVisibility(shouldShowAnchor: boolean) { this.setState({ shouldShowAnchor, }); diff --git a/packages/website/ts/pages/faq/faq.tsx b/packages/website/ts/pages/faq/faq.tsx index c53ed28b8..b4b5214a2 100644 --- a/packages/website/ts/pages/faq/faq.tsx +++ b/packages/website/ts/pages/faq/faq.tsx @@ -1,15 +1,13 @@ import * as _ from 'lodash'; -import RaisedButton from 'material-ui/RaisedButton'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; import * as DocumentTitle from 'react-document-title'; -import {Link} from 'react-router-dom'; -import {Footer} from 'ts/components/footer'; -import {TopBar} from 'ts/components/top_bar'; -import {Question} from 'ts/pages/faq/question'; -import {FAQQuestion, FAQSection, Styles, WebsitePaths} from 'ts/types'; -import {configs} from 'ts/utils/configs'; -import {constants} from 'ts/utils/constants'; +import { Footer } from 'ts/components/footer'; +import { TopBar } from 'ts/components/top_bar'; +import { Question } from 'ts/pages/faq/question'; +import { FAQQuestion, FAQSection, Styles, WebsitePaths } from 'ts/types'; +import { colors } from 'ts/utils/colors'; +import { configs } from 'ts/utils/configs'; +import { constants } from 'ts/utils/constants'; export interface FAQProps { source: string; @@ -32,14 +30,19 @@ const sections: FAQSection[] = [ prompt: 'What is 0x?', answer: ( <div> - At its core, 0x is an open and non-rent seeking protocol that facilitates trustless, - low friction exchange of Ethereum-based assets. Developers can use 0x as a platform - to build exchange applications on top of{' '} - (<a href={`${configs.BASE_URL}${WebsitePaths.ZeroExJs}#introduction`} target="blank">0x.js</a> - {' '}is a Javascript library for interacting with the 0x protocol). For end users, 0x will be - the infrastructure of a wide variety of user-facing applications i.e.{' '} - <a href={`${configs.BASE_URL}${WebsitePaths.Portal}`} target="blank">0x Portal</a>, - a decentralized application that facilitates trustless trading of Ethereum-based tokens + At its core, 0x is an open and non-rent seeking protocol that facilitates trustless, low + friction exchange of Ethereum-based assets. Developers can use 0x as a platform to build + exchange applications on top of (<a + href={`${configs.BASE_URL}${WebsitePaths.ZeroExJs}#introduction`} + target="blank" + > + 0x.js + </a>{' '} + is a Javascript library for interacting with the 0x protocol). For end users, 0x will be the + infrastructure of a wide variety of user-facing applications i.e.{' '} + <a href={`${configs.BASE_URL}${WebsitePaths.Portal}`} target="blank"> + 0x Portal + </a>, a decentralized application that facilitates trustless trading of Ethereum-based tokens between known counterparties. </div> ), @@ -49,15 +52,14 @@ const sections: FAQSection[] = [ answer: ( <div> In the two years since the Ethereum blockchain’s genesis block, numerous decentralized - applications (dApps) have created Ethereum smart contracts for peer-to-peer exchange. - Rapid iteration and a lack of best practices have left the blockchain scattered with - proprietary and application-specific implementations. As a result, end users are - exposed to numerous smart contracts of varying quality and security, with unique - configuration processes and learning curves, all of which implement the same - functionality. This approach imposes unnecessary costs on the network by fragmenting - end users according to the particular dApp each user happens to be using, eliminating - valuable network effects around liquidity. 0x is the solution to this problem by - acting as modular, unopinionated building blocks that may be assembled and reconfigured. + applications (dApps) have created Ethereum smart contracts for peer-to-peer exchange. Rapid + iteration and a lack of best practices have left the blockchain scattered with proprietary and + application-specific implementations. As a result, end users are exposed to numerous smart + contracts of varying quality and security, with unique configuration processes and learning + curves, all of which implement the same functionality. This approach imposes unnecessary costs + on the network by fragmenting end users according to the particular dApp each user happens to be + using, eliminating valuable network effects around liquidity. 0x is the solution to this problem + by acting as modular, unopinionated building blocks that may be assembled and reconfigured. </div> ), }, @@ -66,20 +68,18 @@ const sections: FAQSection[] = [ answer: ( <div> <ul> + <li>0x is a protocol for exchange, not a user-facing exchange application.</li> <li> - 0x is a protocol for exchange, not a user-facing exchange application. - </li> - <li> - 0x is decentralized and trustless; there is no central party which can be - hacked, run away with customer funds or be subjected to government regulations. - Hacks of Mt. Gox, Shapeshift and Bitfinex have demonstrated that these types of - systemic risks are palpable. + 0x is decentralized and trustless; there is no central party which can be hacked, run + away with customer funds or be subjected to government regulations. Hacks of Mt. Gox, + Shapeshift and Bitfinex have demonstrated that these types of systemic risks are + palpable. </li> <li> - Rather than a proprietary system that exists to extract rent for its owners, - 0x is public infrastructure that is funded by a globally distributed community - of stakeholders. While the protocol is free to use, it enables for-profit - user-facing exchange applications to be built on top of the protocol. + Rather than a proprietary system that exists to extract rent for its owners, 0x is + public infrastructure that is funded by a globally distributed community of + stakeholders. While the protocol is free to use, it enables for-profit user-facing + exchange applications to be built on top of the protocol. </li> </ul> </div> @@ -89,13 +89,12 @@ const sections: FAQSection[] = [ prompt: 'If 0x protocol is free to use, where do transaction fees come in?', answer: ( <div> - 0x protocol uses off-chain order books to massively reduce friction costs for - market makers and ensure that the blockchain is only used for trade settlement. - Hosting and maintaining an off-chain order book is a service; to incent “Relayers” - to provide this service they must be able to charge transaction fees on trading - activity. Relayers are free to set their transaction fees to any value they desire. - We expect Relayers to be highly competitive and transaction fees to approach an - efficient economic equilibrium over time. + 0x protocol uses off-chain order books to massively reduce friction costs for market makers and + ensure that the blockchain is only used for trade settlement. Hosting and maintaining an + off-chain order book is a service; to incent “Relayers” to provide this service they must be + able to charge transaction fees on trading activity. Relayers are free to set their transaction + fees to any value they desire. We expect Relayers to be highly competitive and transaction fees + to approach an efficient economic equilibrium over time. </div> ), }, @@ -104,25 +103,23 @@ const sections: FAQSection[] = [ answer: ( <div> <div> - Participants in a state channel pass cryptographically signed messages back and - forth, accumulating intermediate state changes without publishing them to the - canonical chain until the channel is closed. State channels are ideal for “bar tab” - applications where numerous intermediate state changes may be accumulated off-chain - before being settled by a final on-chain transaction (i.e. day trading, poker, - turn-based games). + Participants in a state channel pass cryptographically signed messages back and forth, + accumulating intermediate state changes without publishing them to the canonical chain until + the channel is closed. State channels are ideal for “bar tab” applications where numerous + intermediate state changes may be accumulated off-chain before being settled by a final + on-chain transaction (i.e. day trading, poker, turn-based games). </div> <ul> <li> - While state channels drastically reduce the number of on-chain transactions - for specific use cases, numerous on-chain transactions and a security deposit - are required to open and safely close a state channel making them less efficient - than 0x for executing one-time trades. + While state channels drastically reduce the number of on-chain transactions for specific + use cases, numerous on-chain transactions and a security deposit are required to open + and safely close a state channel making them less efficient than 0x for executing + one-time trades. </li> <li> - State channels are isolated from the Ethereum blockchain meaning that - they cannot interact with smart contracts. 0x is designed to be integrated - directly into smart contracts so trades can be executed programmatically - in a single line of Solidity code. + State channels are isolated from the Ethereum blockchain meaning that they cannot + interact with smart contracts. 0x is designed to be integrated directly into smart + contracts so trades can be executed programmatically in a single line of Solidity code. </li> </ul> </div> @@ -132,16 +129,20 @@ const sections: FAQSection[] = [ prompt: 'What types of digital assets are supported by 0x?', answer: ( <div> - 0x supports all Ethereum-based assets that adhere to the ERC20 token standard. - There are many ERC20 tokens, worth a combined $2.2B, and more tokens are created - each month. We believe that, by 2020, thousands of assets will be tokenized and - moved onto the Ethereum blockchain including traditional securities such as equities, - bonds and derivatives, fiat currencies and scarce digital goods such as video game - items. In the future, cross-blockchain solutions such as{' '} - <a href="https://cosmos.network/" target="_blank">Cosmos</a> and{' '} - <a href="http://polkadot.io/" target="_blank">Polkadot</a> will allow cryptocurrencies - to freely move between blockchains and, naturally, currencies such as Bitcoin will - end up being represented as ERC20 tokens on the Ethereum blockchain. + 0x supports all Ethereum-based assets that adhere to the ERC20 token standard. There are many + ERC20 tokens, worth a combined $2.2B, and more tokens are created each month. We believe that, + by 2020, thousands of assets will be tokenized and moved onto the Ethereum blockchain including + traditional securities such as equities, bonds and derivatives, fiat currencies and scarce + digital goods such as video game items. In the future, cross-blockchain solutions such as{' '} + <a href="https://cosmos.network/" target="_blank"> + Cosmos + </a>{' '} + and{' '} + <a href="http://polkadot.io/" target="_blank"> + Polkadot + </a>{' '} + will allow cryptocurrencies to freely move between blockchains and, naturally, currencies such + as Bitcoin will end up being represented as ERC20 tokens on the Ethereum blockchain. </div> ), }, @@ -149,23 +150,19 @@ const sections: FAQSection[] = [ prompt: '0x is open source: what prevents someone from forking the protocol?', answer: ( <div> - Ethereum and Bitcoin are both open source protocols. Each protocol has been forked, - but the resulting clone networks have seen little adoption (as measured by transaction - count or market cap). This is because users have little to no incentive to switch - over to a clone network if the original has initial network effects and a talented - developer team behind it. - An exception is in the case that a protocol includes a controversial feature such as - a method of rent extraction or a monetary policy that favors one group of users over - another (Zcash developer subsidy - for better or worse - resulted in Zclassic). - Perceived inequality can provide a strong enough incentive that users will fork the - original protocol’s codebase and spin up a new network that eliminates the controversial - feature. In the case of 0x, there is no rent extraction and no users are given - special permissions. - - 0x protocol is upgradable. Cutting-edge technical capabilities can be integrated - into 0x via decentralized governance (see section below), eliminating incentives - to fork off of the original protocol and sacrifice the network effects surrounding - liquidity that result from the shared protocol and settlement layer. + Ethereum and Bitcoin are both open source protocols. Each protocol has been forked, but the + resulting clone networks have seen little adoption (as measured by transaction count or market + cap). This is because users have little to no incentive to switch over to a clone network if the + original has initial network effects and a talented developer team behind it. An exception is in + the case that a protocol includes a controversial feature such as a method of rent extraction or + a monetary policy that favors one group of users over another (Zcash developer subsidy - for + better or worse - resulted in Zclassic). Perceived inequality can provide a strong enough + incentive that users will fork the original protocol’s codebase and spin up a new network that + eliminates the controversial feature. In the case of 0x, there is no rent extraction and no + users are given special permissions. 0x protocol is upgradable. Cutting-edge technical + capabilities can be integrated into 0x via decentralized governance (see section below), + eliminating incentives to fork off of the original protocol and sacrifice the network effects + surrounding liquidity that result from the shared protocol and settlement layer. </div> ), }, @@ -182,26 +179,25 @@ const sections: FAQSection[] = [ 0x protocol token (ZRX) is utilized in two ways: 1) to solve the{' '} <a href="https://en.wikipedia.org/wiki/Coordination_game" target="_blank"> coordination problem - </a> and drive network effects around liquidity, creating a feedback loop - where early adopters of the protocol benefit from wider adoption and 2) to - be used for decentralized governance over 0x protocol's update mechanism. - In more detail: + </a>{' '} + and drive network effects around liquidity, creating a feedback loop where early adopters of + the protocol benefit from wider adoption and 2) to be used for decentralized governance over + 0x protocol's update mechanism. In more detail: </div> <ul> <li> - ZRX tokens are used by Makers and Takers (market participants that generate - and consume orders, respectively) to pay transaction fees to Relayers - (entities that host and maintain public order books). + ZRX tokens are used by Makers and Takers (market participants that generate and consume + orders, respectively) to pay transaction fees to Relayers (entities that host and + maintain public order books). </li> <li> - ZRX tokens are used for decentralized governance over 0x protocol’s update - mechanism which allows its underlying smart contracts to be replaced and - improved over time. An update mechanism is needed because 0x is built upon - Ethereum’s rapidly evolving technology stack, decentralized governance is - needed because 0x protocol’s smart contracts will have access to user funds - and numerous dApps will need to plug into 0x smart contracts. Decentralized - governance ensures that this update process is secure and minimizes disruption - to the network. + ZRX tokens are used for decentralized governance over 0x protocol’s update mechanism + which allows its underlying smart contracts to be replaced and improved over time. An + update mechanism is needed because 0x is built upon Ethereum’s rapidly evolving + technology stack, decentralized governance is needed because 0x protocol’s smart + contracts will have access to user funds and numerous dApps will need to plug into 0x + smart contracts. Decentralized governance ensures that this update process is secure and + minimizes disruption to the network. </li> </ul> </div> @@ -211,9 +207,9 @@ const sections: FAQSection[] = [ prompt: 'Why must transaction fees be denominated in 0x token (ZRX) rather than ETH?', answer: ( <div> - 0x protocol’s decentralized update mechanism is analogous to proof-of-stake. - To maximize the alignment of stakeholder and end user incentives, the staked - asset must provide utility within the protocol. + 0x protocol’s decentralized update mechanism is analogous to proof-of-stake. To maximize the + alignment of stakeholder and end user incentives, the staked asset must provide utility within + the protocol. </div> ), }, @@ -221,10 +217,10 @@ const sections: FAQSection[] = [ prompt: 'How will decentralized governance work?', answer: ( <div> - Decentralized governance is an ongoing focus of research; it will involve token - voting with ZRX. Ultimately the solution will maximize security while also maximizing - the protocol’s ability to absorb new innovations. Until the governance structure is - formalized and encoded within 0x DAO, a multi-sig will be used as a placeholder. + Decentralized governance is an ongoing focus of research; it will involve token voting with ZRX. + Ultimately the solution will maximize security while also maximizing the protocol’s ability to + absorb new innovations. Until the governance structure is formalized and encoded within 0x DAO, + a multi-sig will be used as a placeholder. </div> ), }, @@ -235,27 +231,19 @@ const sections: FAQSection[] = [ questions: [ { prompt: 'What is the total supply of ZRX tokens?', - answer: ( - <div> - 1,000,000,000 ZRX. Fixed supply. - </div> - ), + answer: <div>1,000,000,000 ZRX. Fixed supply.</div>, }, { prompt: 'When is the Token Launch? will there be a pre-sale?', - answer: ( - <div> - The token launch will be on August 15th, 2017. There will not be a pre-sale. - </div> - ), + answer: <div>The token launch will be on August 15th, 2017. There will not be a pre-sale.</div>, }, { prompt: 'What will the token launch proceeds be used for?', answer: ( <div> - 100% of the proceeds raised in the token launch will be used to fund the development - of free and open source software, tools and infrastructure that support the protocol - and surrounding ecosystem. Check out our{' '} + 100% of the proceeds raised in the token launch will be used to fund the development of free and + open source software, tools and infrastructure that support the protocol and surrounding + ecosystem. Check out our{' '} <a href="https://docs.google.com/document/d/1_RVa-_bkU92fWRsC8eNy4vYjcTt-WC8GtqyyjbTd-oY" target="_blank" @@ -269,66 +257,50 @@ const sections: FAQSection[] = [ prompt: 'What will be the initial distribution of ZRX tokens?', answer: ( <div> - <div className="center" style={{width: '100%'}}> - <img - style={{width: 350}} - src="/images/zrx_pie_chart.png" - /> + <div className="center" style={{ width: '100%' }}> + <img style={{ width: 350 }} src="/images/zrx_pie_chart.png" /> </div> <div className="py1"> - <div className="bold pb1"> - Token Launch (50%) - </div> + <div className="bold pb1">Token Launch (50%)</div> <div> - ZRX is inherently a governance token that plays a critical role in the - process of upgrading 0x protocol. We are fully committed to formulating - a functional and theoretically sound governance model and we plan to dedicate - significant resources to R&D. + ZRX is inherently a governance token that plays a critical role in the process of + upgrading 0x protocol. We are fully committed to formulating a functional and + theoretically sound governance model and we plan to dedicate significant resources to + R&D. </div> </div> <div className="py1"> - <div className="bold pb1"> - Retained by 0x (15%) - </div> + <div className="bold pb1">Retained by 0x (15%)</div> <div> - The 0x core development team will be able to sustain itself for approximately - five years using funds raised through the token launch. If 0x protocol - proves to be as foundational a technology as we believe it to be, the - retained ZRX tokens will allow the 0x core development team to sustain - operations beyond the first 5 years. + The 0x core development team will be able to sustain itself for approximately five years + using funds raised through the token launch. If 0x protocol proves to be as foundational + a technology as we believe it to be, the retained ZRX tokens will allow the 0x core + development team to sustain operations beyond the first 5 years. </div> </div> <div className="py1"> - <div className="bold pb1"> - Developer Fund (15%) - </div> + <div className="bold pb1">Developer Fund (15%)</div> <div> - The Developer Fund will be used to make targeted capital injections - into high potential projects and teams that are attempting to grow - the 0x ecosystem, strategic partnerships, hackathon prizes and community - development activities. + The Developer Fund will be used to make targeted capital injections into high potential + projects and teams that are attempting to grow the 0x ecosystem, strategic partnerships, + hackathon prizes and community development activities. </div> </div> <div className="py1"> - <div className="bold pb1"> - Founding Team (10%) - </div> + <div className="bold pb1">Founding Team (10%)</div> <div> - The founding team’s allocation of ZRX will vest over a traditional 4 - year vesting schedule with a one year cliff. We believe this should - be standard practice for any team that is committed to making their - project a long term success. + The founding team’s allocation of ZRX will vest over a traditional 4 year vesting + schedule with a one year cliff. We believe this should be standard practice for any team + that is committed to making their project a long term success. </div> </div> <div className="py1"> - <div className="bold pb1"> - Early Backers & Advisors (10%) - </div> + <div className="bold pb1">Early Backers & Advisors (10%)</div> <div> - Our backers and advisors have provided capital, resources and guidance - that have allowed us to fill out our team, setup a robust legal entity - and build a fully functional product before launching a token. As a result, - we have a proven track record and can offer a token that holds genuine utility. + Our backers and advisors have provided capital, resources and guidance that have allowed + us to fill out our team, setup a robust legal entity and build a fully functional + product before launching a token. As a result, we have a proven track record and can + offer a token that holds genuine utility. </div> </div> </div> @@ -338,47 +310,39 @@ const sections: FAQSection[] = [ prompt: 'Can I mine ZRX tokens?', answer: ( <div> - No, the total supply of ZRX tokens is fixed and there is no continuous issuance - model. Users that facilitate trading over 0x protocol by operating a Relayer - earn transaction fees denominated in ZRX; as more trading activity is generated, - more transaction fees are earned. + No, the total supply of ZRX tokens is fixed and there is no continuous issuance model. Users + that facilitate trading over 0x protocol by operating a Relayer earn transaction fees + denominated in ZRX; as more trading activity is generated, more transaction fees are earned. </div> ), }, { prompt: 'Will there be a lockup period for ZRX tokens sold in the token launch?', - answer: ( - <div> - No, ZRX tokens sold in the token launch will immediately be liquid. - </div> - ), + answer: <div>No, ZRX tokens sold in the token launch will immediately be liquid.</div>, }, { prompt: 'Will there be a lockup period for tokens allocated to the founding team?', answer: ( <div> - Yes. ZRX tokens allocated to founders, advisors and staff members will be released - over a 4 year vesting schedule with a 25% cliff upon completion of the initial - token launch and 25% released each subsequent year in monthly installments. Staff - members hired after the token launch will have a 4 year vesting schedule with a - one year cliff. + Yes. ZRX tokens allocated to founders, advisors and staff members will be released over a 4 year + vesting schedule with a 25% cliff upon completion of the initial token launch and 25% released + each subsequent year in monthly installments. Staff members hired after the token launch will + have a 4 year vesting schedule with a one year cliff. </div> ), }, { prompt: 'Which cryptocurrencies will be accepted in the token launch?', - answer: ( - <div>ETH.</div> - ), + answer: <div>ETH.</div>, }, { prompt: 'When will 0x be live?', answer: ( <div> - An alpha version of 0x has been live on our private test network since January - 2017. Version 1.0 of 0x protocol will be deployed to the canonical Ethereum - blockchain after a round of security audits and prior to the public token launch. - 0x will be using the 0x protocol during our token launch. + An alpha version of 0x has been live on our private test network since January 2017. Version 1.0 + of 0x protocol will be deployed to the canonical Ethereum blockchain after a round of security + audits and prior to the public token launch. 0x will be using the 0x protocol during our token + launch. </div> ), }, @@ -403,19 +367,17 @@ const sections: FAQSection[] = [ questions: [ { prompt: 'Where is 0x based?', - answer: ( - <div> - 0x was founded in SF and is driven by a diverse group of contributors. - </div> - ), + answer: <div>0x was founded in SF and is driven by a diverse group of contributors.</div>, }, { prompt: 'How can I get involved?', answer: ( <div> - Join our <a href={constants.ZEROEX_CHAT_URL} target="_blank">Rocket.chat</a>! - As an open source project, 0x will rely on a worldwide community of passionate - developers to contribute proposals, ideas and code. + Join our{' '} + <a href={constants.URL_ZEROEX_CHAT} target="_blank"> + Rocket.chat + </a>! As an open source project, 0x will rely on a worldwide community of passionate developers + to contribute proposals, ideas and code. </div> ), }, @@ -423,20 +385,15 @@ const sections: FAQSection[] = [ prompt: 'Why the name 0x?', answer: ( <div> - 0x is the prefix for hexadecimal numeric constants including Ethereum addresses. - In a more abstract context, as the first open protocol for exchange 0x represents - the beginning of the end for the exchange industry’s rent seeking oligopoly: - zero exchange. + 0x is the prefix for hexadecimal numeric constants including Ethereum addresses. In a more + abstract context, as the first open protocol for exchange 0x represents the beginning of the end + for the exchange industry’s rent seeking oligopoly: zero exchange. </div> ), }, { prompt: 'How do you pronounce 0x?', - answer: ( - <div> - We pronounce 0x as “zero-ex,” but you are free to pronounce it however you please. - </div> - ), + answer: <div>We pronounce 0x as “zero-ex,” but you are free to pronounce it however you please.</div>, }, ], }, @@ -449,38 +406,31 @@ export class FAQ extends React.Component<FAQProps, FAQState> { public render() { return ( <div> - <DocumentTitle title="0x FAQ"/> - <TopBar - blockchainIsLoaded={false} - location={this.props.location} - /> - <div - id="faq" - className="mx-auto max-width-4 pt4" - style={{color: colors.grey800}} - > - <h1 className="center" style={{...styles.thin}}>0x FAQ</h1> - <div className="sm-px2 md-px2 lg-px0 pb4"> - {this.renderSections()} - </div> + <DocumentTitle title="0x FAQ" /> + <TopBar blockchainIsLoaded={false} location={this.props.location} /> + <div id="faq" className="mx-auto max-width-4 pt4" style={{ color: colors.grey800 }}> + <h1 className="center" style={{ ...styles.thin }}> + 0x FAQ + </h1> + <div className="sm-px2 md-px2 lg-px0 pb4">{this._renderSections()}</div> </div> - <Footer location={this.props.location} /> + <Footer /> </div> ); } - private renderSections() { + private _renderSections() { const renderedSections = _.map(sections, (section: FAQSection, i: number) => { const isFirstSection = i === 0; return ( <div key={section.name}> <h3>{section.name}</h3> - {this.renderQuestions(section.questions, isFirstSection)} + {this._renderQuestions(section.questions, isFirstSection)} </div> ); }); return renderedSections; } - private renderQuestions(questions: FAQQuestion[], isFirstSection: boolean) { + private _renderQuestions(questions: FAQQuestion[], isFirstSection: boolean) { const renderedQuestions = _.map(questions, (question: FAQQuestion, i: number) => { const isFirstQuestion = i === 0; return ( diff --git a/packages/website/ts/pages/faq/question.tsx b/packages/website/ts/pages/faq/question.tsx index 917863e4a..988c04bc9 100644 --- a/packages/website/ts/pages/faq/question.tsx +++ b/packages/website/ts/pages/faq/question.tsx @@ -1,6 +1,7 @@ import * as _ from 'lodash'; -import {Card, CardHeader, CardText} from 'material-ui/Card'; +import { Card, CardHeader, CardText } from 'material-ui/Card'; import * as React from 'react'; +import { colors } from 'ts/utils/colors'; export interface QuestionProps { prompt: string; @@ -21,30 +22,28 @@ export class Question extends React.Component<QuestionProps, QuestionState> { } public render() { return ( - <div - className="py1" - > + <div className="py1"> <Card initiallyExpanded={this.props.shouldDisplayExpanded} - onExpandChange={this.onExchangeChange.bind(this)} + onExpandChange={this._onExchangeChange.bind(this)} > <CardHeader title={this.props.prompt} - style={{borderBottom: this.state.isExpanded ? '1px solid rgba(0, 0, 0, 0.19)' : 'none'}} - titleStyle={{color: 'rgb(66, 66, 66)'}} + style={{ + borderBottom: this.state.isExpanded ? '1px solid rgba(0, 0, 0, 0.19)' : 'none', + }} + titleStyle={{ color: colors.darkerGrey }} actAsExpander={true} showExpandableButton={true} /> <CardText expandable={true}> - <div style={{lineHeight: 1.4}}> - {this.props.answer} - </div> + <div style={{ lineHeight: 1.4 }}>{this.props.answer}</div> </CardText> </Card> </div> ); } - private onExchangeChange() { + private _onExchangeChange() { this.setState({ isExpanded: !this.state.isExpanded, }); diff --git a/packages/website/ts/pages/landing/landing.tsx b/packages/website/ts/pages/landing/landing.tsx index f3c46b8c7..ca76497df 100644 --- a/packages/website/ts/pages/landing/landing.tsx +++ b/packages/website/ts/pages/landing/landing.tsx @@ -1,15 +1,14 @@ import * as _ from 'lodash'; import RaisedButton from 'material-ui/RaisedButton'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; import DocumentTitle = require('react-document-title'); -import {Link} from 'react-router-dom'; -import {Footer} from 'ts/components/footer'; -import {TopBar} from 'ts/components/top_bar'; -import {ScreenWidths, Styles, WebsitePaths} from 'ts/types'; -import {configs} from 'ts/utils/configs'; -import {constants} from 'ts/utils/constants'; -import {utils} from 'ts/utils/utils'; +import { Link } from 'react-router-dom'; +import { Footer } from 'ts/components/footer'; +import { TopBar } from 'ts/components/top_bar'; +import { ScreenWidths, WebsitePaths } from 'ts/types'; +import { colors } from 'ts/utils/colors'; +import { constants } from 'ts/utils/constants'; +import { utils } from 'ts/utils/utils'; interface BoxContent { title: string; @@ -36,31 +35,29 @@ interface Project { } const THROTTLE_TIMEOUT = 100; -const CUSTOM_HERO_BACKGROUND_COLOR = '#404040'; -const CUSTOM_PROJECTS_BACKGROUND_COLOR = '#343333'; -const CUSTOM_WHITE_BACKGROUND = 'rgb(245, 245, 245)'; -const CUSTOM_WHITE_TEXT = '#E4E4E4'; -const CUSTOM_GRAY_TEXT = '#919191'; const boxContents: BoxContent[] = [ { title: 'Trustless exchange', - description: 'Built on Ethereum\'s distributed network with no centralized \ + description: + "Built on Ethereum's distributed network with no centralized \ point of failure and no down time, each trade is settled atomically \ - and without counterparty risk.', + and without counterparty risk.", imageUrl: '/images/landing/distributed_network.png', classNames: '', }, { title: 'Shared liquidity', - description: 'By sharing a standard API, relayers can easily aggregate liquidity pools, \ + description: + 'By sharing a standard API, relayers can easily aggregate liquidity pools, \ creating network effects around liquidity that compound as more relayers come online.', imageUrl: '/images/landing/liquidity.png', classNames: 'mx-auto', }, { title: 'Open source', - description: '0x is open source, permissionless and free to use. Trade directly with a known \ + description: + '0x is open source, permissionless and free to use. Trade directly with a known \ counterparty for free or pay a relayer some ZRX tokens to access their liquidity \ pool.', imageUrl: '/images/landing/open_source.png', @@ -71,67 +68,67 @@ const boxContents: BoxContent[] = [ const projects: Project[] = [ { logoFileName: 'ethfinex-top.png', - projectUrl: constants.ETHFINEX_URL, + projectUrl: constants.PROJECT_URL_ETHFINEX, }, { logoFileName: 'radar_relay_top.png', - projectUrl: constants.RADAR_RELAY_URL, + projectUrl: constants.PROJECT_URL_RADAR_RELAY, }, { logoFileName: 'paradex_top.png', - projectUrl: constants.PARADEX_URL, + projectUrl: constants.PROJECT_URL_PARADEX, }, { logoFileName: 'the_ocean.png', - projectUrl: constants.OCEAN_URL, + projectUrl: constants.PROJECT_URL_0CEAN, }, { logoFileName: 'dydx.png', - projectUrl: constants.DYDX_URL, + projectUrl: constants.PROJECT_URL_DYDX, }, { logoFileName: 'melonport.png', - projectUrl: constants.MELONPORT_URL, + projectUrl: constants.PROJECT_URL_MELONPORT, }, { logoFileName: 'maker.png', - projectUrl: constants.MAKER_URL, + projectUrl: constants.PROJECT_URL_MAKER, }, { logoFileName: 'dharma.png', - projectUrl: constants.DHARMA_URL, + projectUrl: constants.PROJECT_URL_DHARMA, }, { logoFileName: 'lendroid.png', - projectUrl: constants.LENDROID_URL, + projectUrl: constants.PROJECT_URL_LENDROID, }, { logoFileName: 'district0x.png', - projectUrl: constants.DISTRICT_0X_URL, + projectUrl: constants.PROJECT_URL_DISTRICT_0X, }, { logoFileName: 'aragon.png', - projectUrl: constants.ARAGON_URL, + projectUrl: constants.PROJECT_URL_ARAGON, }, { logoFileName: 'blocknet.png', - projectUrl: constants.BLOCKNET_URL, + projectUrl: constants.PROJECT_URL_BLOCKNET, }, { logoFileName: 'status.png', - projectUrl: constants.STATUS_URL, + projectUrl: constants.PROJECT_URL_STATUS, }, { logoFileName: 'augur.png', - projectUrl: constants.AUGUR_URL, + projectUrl: constants.PROJECT_URL_AUGUR, }, { logoFileName: 'anx.png', - projectUrl: constants.OPEN_ANX_URL, + projectUrl: constants.PROJECT_URL_OPEN_ANX, }, { logoFileName: 'auctus.png', - projectUrl: constants.AUCTUS_URL, + projectUrl: constants.PROJECT_URL_AUCTUS, }, ]; @@ -144,45 +141,45 @@ interface LandingState { } export class Landing extends React.Component<LandingProps, LandingState> { - private throttledScreenWidthUpdate: () => void; + private _throttledScreenWidthUpdate: () => void; constructor(props: LandingProps) { super(props); this.state = { screenWidth: utils.getScreenWidth(), }; - this.throttledScreenWidthUpdate = _.throttle(this.updateScreenWidth.bind(this), THROTTLE_TIMEOUT); + this._throttledScreenWidthUpdate = _.throttle(this._updateScreenWidth.bind(this), THROTTLE_TIMEOUT); } public componentDidMount() { - window.addEventListener('resize', this.throttledScreenWidthUpdate); + window.addEventListener('resize', this._throttledScreenWidthUpdate); window.scrollTo(0, 0); } public componentWillUnmount() { - window.removeEventListener('resize', this.throttledScreenWidthUpdate); + window.removeEventListener('resize', this._throttledScreenWidthUpdate); } public render() { return ( - <div id="landing" className="clearfix" style={{color: colors.grey800}}> - <DocumentTitle title="0x Protocol"/> + <div id="landing" className="clearfix" style={{ color: colors.grey500 }}> + <DocumentTitle title="0x Protocol" /> <TopBar blockchainIsLoaded={false} location={this.props.location} isNightVersion={true} - style={{backgroundColor: CUSTOM_HERO_BACKGROUND_COLOR, position: 'relative'}} + style={{ backgroundColor: colors.heroGrey, position: 'relative' }} /> - {this.renderHero()} - {this.renderProjects()} - {this.renderTokenizationSection()} - {this.renderProtocolSection()} - {this.renderInfoBoxes()} - {this.renderBuildingBlocksSection()} - {this.renderUseCases()} - {this.renderCallToAction()} - <Footer location={this.props.location} /> + {this._renderHero()} + {this._renderProjects()} + {this._renderTokenizationSection()} + {this._renderProtocolSection()} + {this._renderInfoBoxes()} + {this._renderBuildingBlocksSection()} + {this._renderUseCases()} + {this._renderCallToAction()} + <Footer /> </div> ); } - private renderHero() { - const isSmallScreen = this.state.screenWidth === ScreenWidths.SM; + private _renderHero() { + const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm; const buttonLabelStyle: React.CSSProperties = { textTransform: 'none', fontSize: isSmallScreen ? 12 : 14, @@ -194,46 +191,43 @@ export class Landing extends React.Component<LandingProps, LandingState> { lineHeight: '33px', height: 38, }; - const left = 'col lg-col-7 md-col-7 col-12 lg-pt4 md-pt4 sm-pt0 mt1 lg-pl4 md-pl4 sm-pl0 sm-px3 sm-center'; + const left = 'col lg-col-7 md-col-7 col-12 lg-pt4 md-pt4 sm-pt0 mt1 lg-pl4 md-pl4 sm-pl0 sm-px3 sm-center'; return ( - <div - className="clearfix py4" - style={{backgroundColor: CUSTOM_HERO_BACKGROUND_COLOR}} - > - <div - className="mx-auto max-width-4 clearfix" - > + <div className="clearfix py4" style={{ backgroundColor: colors.heroGrey }}> + <div className="mx-auto max-width-4 clearfix"> <div className="lg-pt4 md-pt4 sm-pt2 lg-pb4 md-pb4 lg-my4 md-my4 sm-mt2 sm-mb4 clearfix"> <div className="col lg-col-5 md-col-5 col-12 sm-center"> - <img - src="/images/landing/hero_chip_image.png" - height={isSmallScreen ? 300 : 395} - /> + <img src="/images/landing/hero_chip_image.png" height={isSmallScreen ? 300 : 395} /> </div> - <div - className={left} - style={{color: 'white'}} - > - <div style={{paddingLeft: isSmallScreen ? 0 : 12}}> + <div className={left} style={{ color: colors.white }}> + <div style={{ paddingLeft: isSmallScreen ? 0 : 12 }}> <div className="sm-pb2" - style={{fontFamily: 'Roboto Mono', fontSize: isSmallScreen ? 26 : 34}} + style={{ + fontFamily: 'Roboto Mono', + fontSize: isSmallScreen ? 26 : 34, + }} > Powering decentralized exchange </div> <div className="pt2 h5 sm-mx-auto" - style={{maxWidth: 446, fontFamily: 'Roboto Mono', lineHeight: 1.7, fontWeight: 300}} + style={{ + maxWidth: 446, + fontFamily: 'Roboto Mono', + lineHeight: 1.7, + fontWeight: 300, + }} > - 0x is an open, permissionless protocol allowing for ERC20 tokens to - be traded on the Ethereum blockchain. + 0x is an open, permissionless protocol allowing for ERC20 tokens to be traded on the + Ethereum blockchain. </div> - <div className="pt3 clearfix sm-mx-auto" style={{maxWidth: 342}}> + <div className="pt3 clearfix sm-mx-auto" style={{ maxWidth: 342 }}> <div className="lg-pr2 md-pr2 col col-6 sm-center"> <Link to={WebsitePaths.ZeroExJs} className="text-decoration-none"> <RaisedButton - style={{borderRadius: 6, minWidth: 157.36}} - buttonStyle={{borderRadius: 6}} + style={{ borderRadius: 6, minWidth: 157.36 }} + buttonStyle={{ borderRadius: 6 }} labelStyle={buttonLabelStyle} label="Build on 0x" onClick={_.noop} @@ -242,15 +236,15 @@ export class Landing extends React.Component<LandingProps, LandingState> { </div> <div className="col col-6 sm-center"> <a - href={constants.ZEROEX_CHAT_URL} + href={constants.URL_ZEROEX_CHAT} target="_blank" className="text-decoration-none" > <RaisedButton - style={{borderRadius: 6, minWidth: 150}} + style={{ borderRadius: 6, minWidth: 150 }} buttonStyle={lightButtonStyle} labelColor="white" - backgroundColor={CUSTOM_HERO_BACKGROUND_COLOR} + backgroundColor={colors.heroGrey} labelStyle={buttonLabelStyle} label="Join the community" onClick={_.noop} @@ -265,22 +259,15 @@ export class Landing extends React.Component<LandingProps, LandingState> { </div> ); } - private renderProjects() { - const isSmallScreen = this.state.screenWidth === ScreenWidths.SM; - const isMediumScreen = this.state.screenWidth === ScreenWidths.MD; + private _renderProjects() { + const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm; + const isMediumScreen = this.state.screenWidth === ScreenWidths.Md; const projectList = _.map(projects, (project: Project, i: number) => { - const colWidth = isSmallScreen ? 3 : isMediumScreen ? 4 : 2 - (i % 2); + const colWidth = isSmallScreen ? 3 : isMediumScreen ? 4 : 2 - i % 2; return ( - <div - key={`project-${project.logoFileName}`} - className={`col col-${colWidth} center`} - > + <div key={`project-${project.logoFileName}`} className={`col col-${colWidth} center`}> <div> - <a - href={project.projectUrl} - target="_blank" - className="text-decoration-none" - > + <a href={project.projectUrl} target="_blank" className="text-decoration-none"> <img src={`/images/landing/project_logos/${project.logoFileName}`} height={isSmallScreen ? 60 : 92} @@ -292,35 +279,32 @@ export class Landing extends React.Component<LandingProps, LandingState> { }); const titleStyle: React.CSSProperties = { fontFamily: 'Roboto Mono', - color: '#A4A4A4', + color: colors.grey, textTransform: 'uppercase', fontWeight: 300, letterSpacing: 3, }; return ( - <div - className="clearfix py4" - style={{backgroundColor: CUSTOM_PROJECTS_BACKGROUND_COLOR}} - > + <div className="clearfix py4" style={{ backgroundColor: colors.projectsGrey }}> <div className="mx-auto max-width-4 clearfix sm-px3"> - <div - className="h4 pb3 md-pl3 sm-pl2" - style={titleStyle} - > + <div className="h4 pb3 md-pl3 sm-pl2" style={titleStyle}> Projects building on 0x </div> - <div className="clearfix"> - {projectList} - </div> + <div className="clearfix">{projectList}</div> <div className="pt3 mx-auto center" - style={{color: CUSTOM_GRAY_TEXT, fontFamily: 'Roboto Mono', maxWidth: 300, fontSize: 14}} + style={{ + color: colors.landingLinkGrey, + fontFamily: 'Roboto Mono', + maxWidth: 300, + fontSize: 14, + }} > view the{' '} <Link to={`${WebsitePaths.Wiki}#List-of-Projects-Using-0x-Protocol`} className="text-decoration-none underline" - style={{color: CUSTOM_GRAY_TEXT}} + style={{ color: colors.landingLinkGrey }} > full list </Link> @@ -329,137 +313,129 @@ export class Landing extends React.Component<LandingProps, LandingState> { </div> ); } - private renderTokenizationSection() { - const isSmallScreen = this.state.screenWidth === ScreenWidths.SM; + private _renderTokenizationSection() { + const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm; return ( - <div - className="clearfix lg-py4 md-py4 sm-pb4 sm-pt2" - style={{backgroundColor: CUSTOM_WHITE_BACKGROUND}} - > + <div className="clearfix lg-py4 md-py4 sm-pb4 sm-pt2" style={{ backgroundColor: colors.grey100 }}> <div className="mx-auto max-width-4 py4 clearfix"> - {isSmallScreen && - this.renderTokenCloud() - } + {isSmallScreen && this._renderTokenCloud()} <div className="col lg-col-6 md-col-6 col-12"> - <div className="mx-auto" style={{maxWidth: 385, paddingTop: 7}}> - <div - className="lg-h1 md-h1 sm-h2 sm-center sm-pt3" - style={{fontFamily: 'Roboto Mono'}} - > + <div className="mx-auto" style={{ maxWidth: 385, paddingTop: 7 }}> + <div className="lg-h1 md-h1 sm-h2 sm-center sm-pt3" style={{ fontFamily: 'Roboto Mono' }}> The world's value is becoming tokenized </div> <div className="pb2 lg-pt2 md-pt2 sm-pt3 sm-px3 h5 sm-center" - style={{fontFamily: 'Roboto Mono', lineHeight: 1.7}} + style={{ fontFamily: 'Roboto Mono', lineHeight: 1.7 }} > - {isSmallScreen ? + {isSmallScreen ? ( <span> The Ethereum blockchain is an open, borderless financial system that represents a wide variety of assets as cryptographic tokens. In the future, most digital assets and goods will be tokenized. - </span> : + </span> + ) : ( <div> <div> - The Ethereum blockchain is an open, borderless - financial system that represents + The Ethereum blockchain is an open, borderless financial system that + represents </div> <div> - a wide variety of assets as cryptographic tokens. - In the future, most digital assets and goods will be tokenized. + a wide variety of assets as cryptographic tokens. In the future, most + digital assets and goods will be tokenized. </div> </div> - } - </div> - <div className="flex pt1 sm-px3"> - {this.renderAssetTypes()} + )} </div> + <div className="flex pt1 sm-px3">{this._renderAssetTypes()}</div> </div> </div> - {!isSmallScreen && - this.renderTokenCloud() - } + {!isSmallScreen && this._renderTokenCloud()} </div> </div> ); } - private renderProtocolSection() { - const isSmallScreen = this.state.screenWidth === ScreenWidths.SM; + private _renderProtocolSection() { + const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm; return ( - <div - className="clearfix lg-py4 md-py4 sm-pt4" - style={{backgroundColor: CUSTOM_HERO_BACKGROUND_COLOR}} - > + <div className="clearfix lg-py4 md-py4 sm-pt4" style={{ backgroundColor: colors.heroGrey }}> <div className="mx-auto max-width-4 lg-py4 md-py4 sm-pt4 clearfix"> <div className="col lg-col-6 md-col-6 col-12 sm-center"> - <img - src="/images/landing/relayer_diagram.png" - height={isSmallScreen ? 326 : 426} - /> + <img src="/images/landing/relayer_diagram.png" height={isSmallScreen ? 326 : 426} /> </div> <div className="col lg-col-6 md-col-6 col-12 lg-pr3 md-pr3 sm-mx-auto" - style={{color: CUSTOM_WHITE_TEXT, paddingTop: 8, maxWidth: isSmallScreen ? 'none' : 445}} + style={{ + color: colors.beigeWhite, + paddingTop: 8, + maxWidth: isSmallScreen ? 'none' : 445, + }} > - <div - className="lg-h1 md-h1 sm-h2 pb1 sm-pt3 sm-center" - style={{fontFamily: 'Roboto Mono'}} - > - <div> - Off-chain order relay - </div> - <div> - On-chain settlement - </div> + <div className="lg-h1 md-h1 sm-h2 pb1 sm-pt3 sm-center" style={{ fontFamily: 'Roboto Mono' }}> + <div>Off-chain order relay</div> + <div>On-chain settlement</div> </div> <div className="pb2 pt2 h5 sm-center sm-px3 sm-mx-auto" - style={{fontFamily: 'Roboto Mono', lineHeight: 1.7, fontWeight: 300, maxWidth: 445}} + style={{ + fontFamily: 'Roboto Mono', + lineHeight: 1.7, + fontWeight: 300, + maxWidth: 445, + }} > - In 0x protocol, orders are transported off-chain, massively reducing gas - costs and eliminating blockchain bloat. Relayers help broadcast orders and - collect a fee each time they facilitate a trade. Anyone can build a relayer. + In 0x protocol, orders are transported off-chain, massively reducing gas costs and + eliminating blockchain bloat. Relayers help broadcast orders and collect a fee each time + they facilitate a trade. Anyone can build a relayer. </div> <div className="pt3 sm-mx-auto sm-px3" - style={{color: CUSTOM_GRAY_TEXT, maxWidth: isSmallScreen ? 412 : 'none'}} + style={{ + color: colors.landingLinkGrey, + maxWidth: isSmallScreen ? 412 : 'none', + }} > - <div className="flex" style={{fontSize: 18}}> + <div className="flex" style={{ fontSize: 18 }}> <div className="lg-h4 md-h4 sm-h5" - style={{letterSpacing: isSmallScreen ? 1 : 3, fontFamily: 'Roboto Mono'}} + style={{ + letterSpacing: isSmallScreen ? 1 : 3, + fontFamily: 'Roboto Mono', + }} > RELAYERS BUILDING ON 0X </div> - <div className="h5" style={{marginLeft: isSmallScreen ? 26 : 49}}> + <div className="h5" style={{ marginLeft: isSmallScreen ? 26 : 49 }}> <Link to={`${WebsitePaths.Wiki}#List-of-Projects-Using-0x-Protocol`} className="text-decoration-none underline" - style={{color: CUSTOM_GRAY_TEXT, fontFamily: 'Roboto Mono'}} + style={{ + color: colors.landingLinkGrey, + fontFamily: 'Roboto Mono', + }} > view all </Link> </div> </div> - <div className="lg-flex md-flex sm-clearfix pt3" style={{opacity: 0.4}}> + <div className="lg-flex md-flex sm-clearfix pt3" style={{ opacity: 0.4 }}> <div className="col col-4 sm-center"> - <img - src="/images/landing/ethfinex.png" - style={{height: isSmallScreen ? 85 : 107}} - /> + <img + src="/images/landing/ethfinex.png" + style={{ height: isSmallScreen ? 85 : 107 }} + /> </div> - <div - className="col col-4 center" - > - <img - src="/images/landing/radar_relay.png" - style={{height: isSmallScreen ? 85 : 107}} - /> + <div className="col col-4 center"> + <img + src="/images/landing/radar_relay.png" + style={{ height: isSmallScreen ? 85 : 107 }} + /> </div> - <div className="col col-4 sm-center" style={{textAlign: 'right'}}> - <img - src="/images/landing/paradex.png" - style={{height: isSmallScreen ? 85 : 107}} - /> + <div className="col col-4 sm-center" style={{ textAlign: 'right' }}> + <img + src="/images/landing/paradex.png" + style={{ height: isSmallScreen ? 85 : 107 }} + /> </div> </div> </div> @@ -468,13 +444,8 @@ export class Landing extends React.Component<LandingProps, LandingState> { </div> ); } - private renderBuildingBlocksSection() { - const isSmallScreen = this.state.screenWidth === ScreenWidths.SM; - const underlineStyle: React.CSSProperties = { - height: isSmallScreen ? 18 : 23, - lineHeight: 'none', - borderBottom: '2px solid #979797', - }; + private _renderBuildingBlocksSection() { + const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm; const descriptionStyle: React.CSSProperties = { fontFamily: 'Roboto Mono', lineHeight: isSmallScreen ? 1.5 : 2, @@ -489,86 +460,67 @@ export class Landing extends React.Component<LandingProps, LandingState> { maxWidth: isSmallScreen ? 375 : 441, }; return ( - <div - className="clearfix lg-pt4 md-pt4" - style={{backgroundColor: CUSTOM_HERO_BACKGROUND_COLOR}} - > + <div className="clearfix lg-pt4 md-pt4" style={{ backgroundColor: colors.heroGrey }}> <div className="mx-auto max-width-4 lg-pt4 md-pt4 lg-mb4 md-mb4 sm-mb2 clearfix"> - {isSmallScreen && - this.renderBlockChipImage() - } + {isSmallScreen && this._renderBlockChipImage()} <div className="col lg-col-6 md-col-6 col-12 lg-pr3 md-pr3 sm-px3" - style={{color: CUSTOM_WHITE_TEXT}} + style={{ color: colors.beigeWhite }} > <div className="pb1 lg-pt4 md-pt4 sm-pt3 lg-h1 md-h1 sm-h2 sm-px3 sm-center" - style={{fontFamily: 'Roboto Mono'}} + style={{ fontFamily: 'Roboto Mono' }} > A building block for dApps </div> - <div - className="pb3 pt2 sm-mx-auto sm-center" - style={descriptionStyle} - > + <div className="pb3 pt2 sm-mx-auto sm-center" style={descriptionStyle}> 0x protocol is a pluggable building block for dApps that require exchange functionality. Join the many developers that are already using 0x in their web applications and smart contracts. </div> - <div - className="sm-mx-auto sm-center" - style={callToActionStyle} - > + <div className="sm-mx-auto sm-center" style={callToActionStyle}> Learn how in our{' '} <Link to={WebsitePaths.ZeroExJs} className="text-decoration-none underline" - style={{color: CUSTOM_WHITE_TEXT, fontFamily: 'Roboto Mono'}} + style={{ color: colors.beigeWhite, fontFamily: 'Roboto Mono' }} > 0x.js - </Link> - {' '}and{' '} + </Link>{' '} + and{' '} <Link to={WebsitePaths.SmartContracts} className="text-decoration-none underline" - style={{color: CUSTOM_WHITE_TEXT, fontFamily: 'Roboto Mono'}} + style={{ color: colors.beigeWhite, fontFamily: 'Roboto Mono' }} > smart contract - </Link> - {' '}docs + </Link>{' '} + docs </div> </div> - {!isSmallScreen && - this.renderBlockChipImage() - } + {!isSmallScreen && this._renderBlockChipImage()} </div> </div> ); } - private renderBlockChipImage() { - const isSmallScreen = this.state.screenWidth === ScreenWidths.SM; + private _renderBlockChipImage() { + const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm; return ( <div className="col lg-col-6 md-col-6 col-12 sm-center"> - <img - src="/images/landing/0x_chips.png" - height={isSmallScreen ? 240 : 368} - /> + <img src="/images/landing/0x_chips.png" height={isSmallScreen ? 240 : 368} /> </div> ); } - private renderTokenCloud() { - const isSmallScreen = this.state.screenWidth === ScreenWidths.SM; + private _renderTokenCloud() { + const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm; return ( <div className="col lg-col-6 md-col-6 col-12 center"> - <img - src="/images/landing/tokenized_world.png" - height={isSmallScreen ? 280 : 364.5} - /> + <img src="/images/landing/tokenized_world.png" height={isSmallScreen ? 280 : 364.5} /> </div> ); } - private renderAssetTypes() { - const isSmallScreen = this.state.screenWidth === ScreenWidths.SM; + private _renderAssetTypes() { + const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm; const assetTypes: AssetType[] = [ { title: 'Currency', @@ -577,7 +529,10 @@ export class Landing extends React.Component<LandingProps, LandingState> { { title: 'Traditional assets', imageUrl: '/images/landing/stocks.png', - style: {paddingLeft: isSmallScreen ? 41 : 56, paddingRight: isSmallScreen ? 41 : 56}, + style: { + paddingLeft: isSmallScreen ? 41 : 56, + paddingRight: isSmallScreen ? 41 : 56, + }, }, { title: 'Digital goods', @@ -587,18 +542,18 @@ export class Landing extends React.Component<LandingProps, LandingState> { const assets = _.map(assetTypes, (assetType: AssetType) => { const style = _.isUndefined(assetType.style) ? {} : assetType.style; return ( - <div - key={`asset-${assetType.title}`} - className="center" - style={{opacity: 0.8, ...style}} - > + <div key={`asset-${assetType.title}`} className="center" style={{ opacity: 0.8, ...style }}> <div> - <img - src={assetType.imageUrl} - height="80" - /> + <img src={assetType.imageUrl} height="80" /> </div> - <div style={{fontFamily: 'Roboto Mono', fontSize: 13.5, fontWeight: 400, opacity: 0.75}}> + <div + style={{ + fontFamily: 'Roboto Mono', + fontSize: 13.5, + fontWeight: 400, + opacity: 0.75, + }} + > {assetType.title} </div> </div> @@ -606,83 +561,49 @@ export class Landing extends React.Component<LandingProps, LandingState> { }); return assets; } - private renderLink(label: string, path: string, color: string, style?: React.CSSProperties) { - return ( - <div - style={{borderBottom: `1px solid ${color}`, paddingBottom: 1, height: 20, lineHeight: 1.7, ...style}} - > - <Link - to={path} - className="text-decoration-none" - style={{color, fontFamily: 'Roboto Mono'}} - > - {label} - </Link> - </div> - ); - } - private renderInfoBoxes() { - const isSmallScreen = this.state.screenWidth === ScreenWidths.SM; + private _renderInfoBoxes() { + const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm; const boxStyle: React.CSSProperties = { maxWidth: 252, height: 386, - backgroundColor: '#F9F9F9', + backgroundColor: colors.grey50, borderRadius: 5, padding: '10px 24px 24px', }; const boxes = _.map(boxContents, (boxContent: BoxContent) => { return ( - <div - key={`box-${boxContent.title}`} - className="col lg-col-4 md-col-4 col-12 sm-pb4" - > - <div - className={`center sm-mx-auto ${!isSmallScreen && boxContent.classNames}`} - style={boxStyle} - > + <div key={`box-${boxContent.title}`} className="col lg-col-4 md-col-4 col-12 sm-pb4"> + <div className={`center sm-mx-auto ${!isSmallScreen && boxContent.classNames}`} style={boxStyle}> <div> - <img src={boxContent.imageUrl} style={{height: 210}} /> + <img src={boxContent.imageUrl} style={{ height: 210 }} /> </div> - <div - className="h3" - style={{color: 'black', fontFamily: 'Roboto Mono'}} - > + <div className="h3" style={{ color: 'black', fontFamily: 'Roboto Mono' }}> {boxContent.title} </div> - <div - className="pt2 pb2" - style={{fontFamily: 'Roboto Mono', fontSize: 14}} - > + <div className="pt2 pb2" style={{ fontFamily: 'Roboto Mono', fontSize: 14 }}> {boxContent.description} </div> </div> </div> ); - }); return ( - <div - className="clearfix" - style={{backgroundColor: CUSTOM_HERO_BACKGROUND_COLOR}} - > - <div - className="mx-auto py4 sm-mt2 clearfix" - style={{maxWidth: '60em'}} - > + <div className="clearfix" style={{ backgroundColor: colors.heroGrey }}> + <div className="mx-auto py4 sm-mt2 clearfix" style={{ maxWidth: '60em' }}> {boxes} </div> </div> ); } - private renderUseCases() { - const isSmallScreen = this.state.screenWidth === ScreenWidths.SM; - const isMediumScreen = this.state.screenWidth === ScreenWidths.MD; + private _renderUseCases() { + const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm; const useCases: UseCase[] = [ { imageUrl: '/images/landing/governance_icon.png', type: 'Decentralized governance', - description: 'Decentralized organizations use tokens to represent ownership and \ + description: + 'Decentralized organizations use tokens to represent ownership and \ guide their governance logic. 0x allows decentralized organizations \ to seamlessly and safely trade ownership for startup capital.', projectIconUrls: ['/images/landing/aragon.png'], @@ -691,7 +612,8 @@ export class Landing extends React.Component<LandingProps, LandingState> { { imageUrl: '/images/landing/prediction_market_icon.png', type: 'Prediction markets', - description: 'Decentralized prediction market platforms generate sets of tokens that \ + description: + 'Decentralized prediction market platforms generate sets of tokens that \ represent a financial stake in the outcomes of real-world events. 0x allows \ these tokens to be instantly tradable.', projectIconUrls: ['/images/landing/augur.png'], @@ -700,7 +622,8 @@ export class Landing extends React.Component<LandingProps, LandingState> { { imageUrl: '/images/landing/stable_tokens_icon.png', type: 'Stable tokens', - description: 'Novel economic constructs such as stable coins require efficient, liquid \ + description: + 'Novel economic constructs such as stable coins require efficient, liquid \ markets to succeed. 0x will facilitate the underlying economic mechanisms \ that allow these tokens to remain stable.', projectIconUrls: ['/images/landing/maker.png'], @@ -709,36 +632,42 @@ export class Landing extends React.Component<LandingProps, LandingState> { { imageUrl: '/images/landing/loans_icon.png', type: 'Decentralized loans', - description: 'Efficient lending requires liquid markets where investors can buy and re-sell loans. \ + description: + 'Efficient lending requires liquid markets where investors can buy and re-sell loans. \ 0x enables an ecosystem of lenders to self-organize and efficiently determine \ market prices for all outstanding loans.', projectIconUrls: ['/images/landing/dharma.png', '/images/landing/lendroid.png'], classNames: 'lg-pr2 md-pr2 lg-col-6 md-col-6', - style: {width: 291, float: 'right', marginTop: !isSmallScreen ? 38 : 0}, + style: { + width: 291, + float: 'right', + marginTop: !isSmallScreen ? 38 : 0, + }, }, { imageUrl: '/images/landing/fund_management_icon.png', type: 'Fund management', - description: 'Decentralized fund management limits fund managers to investing in pre-agreed \ + description: + 'Decentralized fund management limits fund managers to investing in pre-agreed \ upon asset classes. Embedding 0x into fund management smart contracts enables \ them to enforce these security constraints.', projectIconUrls: ['/images/landing/melonport.png'], classNames: 'lg-pl2 md-pl2 lg-col-6 md-col-6', - style: {width: 291, marginTop: !isSmallScreen ? 38 : 0}, + style: { width: 291, marginTop: !isSmallScreen ? 38 : 0 }, }, ]; const cases = _.map(useCases, (useCase: UseCase) => { const style = _.isUndefined(useCase.style) || isSmallScreen ? {} : useCase.style; const useCaseBoxStyle = { - color: '#A2A2A2', + color: colors.grey, border: '1px solid #565656', borderRadius: 4, maxWidth: isSmallScreen ? 375 : 'none', ...style, }; const typeStyle: React.CSSProperties = { - color: '#EBEBEB', + color: colors.lightGrey, fontSize: 13, textTransform: 'uppercase', fontFamily: 'Roboto Mono', @@ -749,22 +678,21 @@ export class Landing extends React.Component<LandingProps, LandingState> { key={`useCase-${useCase.type}`} className={`col lg-col-4 md-col-4 col-12 sm-pt3 sm-px3 sm-pb3 ${useCase.classNames}`} > - <div - className="relative p2 pb2 sm-mx-auto" - style={useCaseBoxStyle} - > - <div - className="absolute center" - style={{top: -35, width: 'calc(100% - 32px)'}} - > - <img src={useCase.imageUrl} style={{height: 50}} /> + <div className="relative p2 pb2 sm-mx-auto" style={useCaseBoxStyle}> + <div className="absolute center" style={{ top: -35, width: 'calc(100% - 32px)' }}> + <img src={useCase.imageUrl} style={{ height: 50 }} /> </div> <div className="pt2 center" style={typeStyle}> {useCase.type} </div> <div className="pt2" - style={{lineHeight: 1.5, fontSize: 14, overflow: 'hidden', height: 104}} + style={{ + lineHeight: 1.5, + fontSize: 14, + overflow: 'hidden', + height: 104, + }} > {useCase.description} </div> @@ -773,21 +701,15 @@ export class Landing extends React.Component<LandingProps, LandingState> { ); }); return ( - <div - className="clearfix pb4 lg-pt2 md-pt2 sm-pt4" - style={{backgroundColor: CUSTOM_HERO_BACKGROUND_COLOR}} - > - <div - className="mx-auto pb4 pt3 mt1 sm-mt2 clearfix" - style={{maxWidth: '67em'}} - > + <div className="clearfix pb4 lg-pt2 md-pt2 sm-pt4" style={{ backgroundColor: colors.heroGrey }}> + <div className="mx-auto pb4 pt3 mt1 sm-mt2 clearfix" style={{ maxWidth: '67em' }}> {cases} </div> </div> ); } - private renderCallToAction() { - const isSmallScreen = this.state.screenWidth === ScreenWidths.SM; + private _renderCallToAction() { + const isSmallScreen = this.state.screenWidth === ScreenWidths.Sm; const buttonLabelStyle: React.CSSProperties = { textTransform: 'none', fontSize: 15, @@ -799,29 +721,29 @@ export class Landing extends React.Component<LandingProps, LandingState> { lineHeight: '33px', height: 49, }; - const callToActionClassNames = 'col lg-col-8 md-col-8 col-12 lg-pr3 md-pr3 \ + const callToActionClassNames = + 'col lg-col-8 md-col-8 col-12 lg-pr3 md-pr3 \ lg-right-align md-right-align sm-center sm-px3 h4'; return ( - <div - className="clearfix pb4" - style={{backgroundColor: CUSTOM_HERO_BACKGROUND_COLOR}} - > - <div - className="mx-auto max-width-4 pb4 mb3 clearfix" - > + <div className="clearfix pb4" style={{ backgroundColor: colors.heroGrey }}> + <div className="mx-auto max-width-4 pb4 mb3 clearfix"> <div className={callToActionClassNames} - style={{fontFamily: 'Roboto Mono', color: 'white', lineHeight: isSmallScreen ? 1.7 : 3}} + style={{ + fontFamily: 'Roboto Mono', + color: colors.white, + lineHeight: isSmallScreen ? 1.7 : 3, + }} > Get started on building the decentralized future </div> <div className="col lg-col-4 md-col-4 col-12 sm-center sm-pt2"> <Link to={WebsitePaths.ZeroExJs} className="text-decoration-none"> <RaisedButton - style={{borderRadius: 6, minWidth: 150}} + style={{ borderRadius: 6, minWidth: 150 }} buttonStyle={lightButtonStyle} labelColor={colors.white} - backgroundColor={CUSTOM_HERO_BACKGROUND_COLOR} + backgroundColor={colors.heroGrey} labelStyle={buttonLabelStyle} label="Build on 0x" onClick={_.noop} @@ -832,7 +754,7 @@ export class Landing extends React.Component<LandingProps, LandingState> { </div> ); } - private updateScreenWidth() { + private _updateScreenWidth() { const newScreenWidth = utils.getScreenWidth(); if (newScreenWidth !== this.state.screenWidth) { this.setState({ diff --git a/packages/website/ts/pages/not_found.tsx b/packages/website/ts/pages/not_found.tsx index 075bcf91e..ff277c377 100644 --- a/packages/website/ts/pages/not_found.tsx +++ b/packages/website/ts/pages/not_found.tsx @@ -1,9 +1,8 @@ import * as _ from 'lodash'; import * as React from 'react'; -import {Link} from 'react-router-dom'; -import {Footer} from 'ts/components/footer'; -import {TopBar} from 'ts/components/top_bar'; -import {Styles} from 'ts/types'; +import { Footer } from 'ts/components/footer'; +import { TopBar } from 'ts/components/top_bar'; +import { Styles } from 'ts/types'; export interface NotFoundProps { location: Location; @@ -21,15 +20,12 @@ export class NotFound extends React.Component<NotFoundProps, NotFoundState> { public render() { return ( <div> - <TopBar - blockchainIsLoaded={false} - location={this.props.location} - /> + <TopBar blockchainIsLoaded={false} location={this.props.location} /> <div className="mx-auto max-width-4 py4"> <div className="center py4"> <div className="py4"> <div className="py4"> - <h1 style={{...styles.thin}}>404 Not Found</h1> + <h1 style={{ ...styles.thin }}>404 Not Found</h1> <div className="py1"> <div className="py3"> Hm... looks like we couldn't find what you are looking for. @@ -39,7 +35,7 @@ export class NotFound extends React.Component<NotFoundProps, NotFoundState> { </div> </div> </div> - <Footer location={this.props.location} /> + <Footer /> </div> ); } diff --git a/packages/website/ts/pages/shared/anchor_title.tsx b/packages/website/ts/pages/shared/anchor_title.tsx index 0a3674fd9..db5be1f59 100644 --- a/packages/website/ts/pages/shared/anchor_title.tsx +++ b/packages/website/ts/pages/shared/anchor_title.tsx @@ -1,16 +1,16 @@ import * as React from 'react'; -import {Link as ScrollLink} from 'react-scroll'; -import {HeaderSizes, Styles} from 'ts/types'; -import {constants} from 'ts/utils/constants'; -import {utils} from 'ts/utils/utils'; +import { Link as ScrollLink } from 'react-scroll'; +import { HeaderSizes, Styles } from 'ts/types'; +import { constants } from 'ts/utils/constants'; +import { utils } from 'ts/utils/utils'; -const headerSizeToScrollOffset: {[headerSize: string]: number} = { +const headerSizeToScrollOffset: { [headerSize: string]: number } = { h2: -20, h3: 0, }; interface AnchorTitleProps { - title: string|React.ReactNode; + title: string | React.ReactNode; id: string; headerSize: HeaderSizes; shouldShowAnchor: boolean; @@ -62,11 +62,8 @@ export class AnchorTitle extends React.Component<AnchorTitleProps, AnchorTitleSt opacity = this.state.isHovering ? 0.6 : 1; } return ( - <div className="relative flex" style={{...styles[this.props.headerSize], ...styles.headers}}> - <div - className="inline-block" - style={{paddingRight: 4}} - > + <div className="relative flex" style={{ ...styles[this.props.headerSize], ...styles.headers }}> + <div className="inline-block" style={{ paddingRight: 4 }}> {this.props.title} </div> <ScrollLink @@ -78,15 +75,15 @@ export class AnchorTitle extends React.Component<AnchorTitleProps, AnchorTitleSt <i className="zmdi zmdi-link" onClick={utils.setUrlHash.bind(utils, this.props.id)} - style={{...styles.anchor, opacity}} - onMouseOver={this.setHoverState.bind(this, true)} - onMouseOut={this.setHoverState.bind(this, false)} + style={{ ...styles.anchor, opacity }} + onMouseOver={this._setHoverState.bind(this, true)} + onMouseOut={this._setHoverState.bind(this, false)} /> </ScrollLink> </div> ); } - private setHoverState(isHovering: boolean) { + private _setHoverState(isHovering: boolean) { this.setState({ isHovering, }); diff --git a/packages/website/ts/pages/shared/markdown_code_block.tsx b/packages/website/ts/pages/shared/markdown_code_block.tsx index 621e5b606..be96fda16 100644 --- a/packages/website/ts/pages/shared/markdown_code_block.tsx +++ b/packages/website/ts/pages/shared/markdown_code_block.tsx @@ -7,14 +7,19 @@ interface MarkdownCodeBlockProps { language: string; } -export function MarkdownCodeBlock(props: MarkdownCodeBlockProps) { - return ( - <span style={{fontSize: 16}}> - <HighLight - className={props.language || 'js'} - > - {props.literal} - </HighLight> - </span> - ); +interface MarkdownCodeBlockState {} + +export class MarkdownCodeBlock extends React.Component<MarkdownCodeBlockProps, MarkdownCodeBlockState> { + // Re-rendering a codeblock causes any use selection to become de-selected. This is annoying when trying + // to copy-paste code examples. We therefore noop re-renders on this component if it's props haven't changed. + public shouldComponentUpdate(nextProps: MarkdownCodeBlockProps, nextState: MarkdownCodeBlockState) { + return nextProps.literal !== this.props.literal || nextProps.language !== this.props.language; + } + public render() { + return ( + <span style={{ fontSize: 16 }}> + <HighLight className={this.props.language || 'javascript'}>{this.props.literal}</HighLight> + </span> + ); + } } diff --git a/packages/website/ts/pages/shared/markdown_section.tsx b/packages/website/ts/pages/shared/markdown_section.tsx index 8686e80b6..5487dc8cc 100644 --- a/packages/website/ts/pages/shared/markdown_section.tsx +++ b/packages/website/ts/pages/shared/markdown_section.tsx @@ -2,11 +2,11 @@ import * as _ from 'lodash'; import RaisedButton from 'material-ui/RaisedButton'; import * as React from 'react'; import * as ReactMarkdown from 'react-markdown'; -import {Element as ScrollElement} from 'react-scroll'; -import {AnchorTitle} from 'ts/pages/shared/anchor_title'; -import {MarkdownCodeBlock} from 'ts/pages/shared/markdown_code_block'; -import {HeaderSizes} from 'ts/types'; -import {utils} from 'ts/utils/utils'; +import { Element as ScrollElement } from 'react-scroll'; +import { AnchorTitle } from 'ts/pages/shared/anchor_title'; +import { MarkdownCodeBlock } from 'ts/pages/shared/markdown_code_block'; +import { HeaderSizes } from 'ts/types'; +import { utils } from 'ts/utils/utils'; interface MarkdownSectionProps { sectionName: string; @@ -35,13 +35,13 @@ export class MarkdownSection extends React.Component<MarkdownSectionProps, Markd return ( <div className="pt2 pr3 md-pl2 sm-pl3 overflow-hidden" - onMouseOver={this.setAnchorVisibility.bind(this, true)} - onMouseOut={this.setAnchorVisibility.bind(this, false)} + onMouseOver={this._setAnchorVisibility.bind(this, true)} + onMouseOut={this._setAnchorVisibility.bind(this, false)} > <ScrollElement name={id}> <div className="clearfix"> <div className="col lg-col-8 md-col-8 sm-col-12"> - <span style={{textTransform: 'capitalize'}}> + <span style={{ textTransform: 'capitalize' }}> <AnchorTitle headerSize={this.props.headerSize} title={sectionName} @@ -51,25 +51,22 @@ export class MarkdownSection extends React.Component<MarkdownSectionProps, Markd </span> </div> <div className="col col-4 sm-hide xs-hide py2 right-align"> - {!_.isUndefined(this.props.githubLink) && + {!_.isUndefined(this.props.githubLink) && ( <RaisedButton href={this.props.githubLink} target="_blank" label="Edit on Github" - icon={<i className="zmdi zmdi-github" style={{fontSize: 23}} />} + icon={<i className="zmdi zmdi-github" style={{ fontSize: 23 }} />} /> - } + )} </div> </div> - <ReactMarkdown - source={this.props.markdownContent} - renderers={{CodeBlock: MarkdownCodeBlock}} - /> + <ReactMarkdown source={this.props.markdownContent} renderers={{ CodeBlock: MarkdownCodeBlock }} /> </ScrollElement> </div> ); } - private setAnchorVisibility(shouldShowAnchor: boolean) { + private _setAnchorVisibility(shouldShowAnchor: boolean) { this.setState({ shouldShowAnchor, }); diff --git a/packages/website/ts/pages/shared/nested_sidebar_menu.tsx b/packages/website/ts/pages/shared/nested_sidebar_menu.tsx index cbb863f3e..849c33504 100644 --- a/packages/website/ts/pages/shared/nested_sidebar_menu.tsx +++ b/packages/website/ts/pages/shared/nested_sidebar_menu.tsx @@ -1,16 +1,15 @@ import * as _ from 'lodash'; import MenuItem from 'material-ui/MenuItem'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; -import {Link as ScrollLink} from 'react-scroll'; -import {VersionDropDown} from 'ts/pages/shared/version_drop_down'; -import {Docs, MenuSubsectionsBySection, Styles} from 'ts/types'; -import {constants} from 'ts/utils/constants'; -import {typeDocUtils} from 'ts/utils/typedoc_utils'; -import {utils} from 'ts/utils/utils'; +import { Link as ScrollLink } from 'react-scroll'; +import { VersionDropDown } from 'ts/pages/shared/version_drop_down'; +import { MenuSubsectionsBySection, Styles } from 'ts/types'; +import { colors } from 'ts/utils/colors'; +import { constants } from 'ts/utils/constants'; +import { utils } from 'ts/utils/utils'; interface NestedSidebarMenuProps { - topLevelMenu: {[topLevel: string]: string[]}; + topLevelMenu: { [topLevel: string]: string[] }; menuSubsectionsBySection: MenuSubsectionsBySection; shouldDisplaySectionHeaders?: boolean; onMenuItemClick?: () => void; @@ -45,55 +44,44 @@ export class NestedSidebarMenu extends React.Component<NestedSidebarMenuProps, N if (this.props.shouldDisplaySectionHeaders) { const id = utils.getIdFromName(sectionName); return ( - <div - key={`section-${sectionName}`} - className="py1" - > + <div key={`section-${sectionName}`} className="py1"> <ScrollLink to={id} offset={-20} duration={constants.DOCS_SCROLL_DURATION_MS} containerId={constants.DOCS_CONTAINER_ID} > - <div - style={{color: colors.grey500, cursor: 'pointer'}} - className="pb1" - > + <div style={{ color: colors.grey, cursor: 'pointer' }} className="pb1"> {finalSectionName.toUpperCase()} </div> </ScrollLink> - {this.renderMenuItems(menuItems)} + {this._renderMenuItems(menuItems)} </div> ); } else { - return ( - <div key={`section-${sectionName}`} > - {this.renderMenuItems(menuItems)} - </div> - ); + return <div key={`section-${sectionName}`}>{this._renderMenuItems(menuItems)}</div>; } }); return ( <div> {!_.isUndefined(this.props.versions) && - !_.isUndefined(this.props.selectedVersion) && - !_.isUndefined(this.props.docPath) && - <VersionDropDown - selectedVersion={this.props.selectedVersion} - versions={this.props.versions} - docPath={this.props.docPath} - /> - } + !_.isUndefined(this.props.selectedVersion) && + !_.isUndefined(this.props.docPath) && ( + <VersionDropDown + selectedVersion={this.props.selectedVersion} + versions={this.props.versions} + docPath={this.props.docPath} + /> + )} {navigation} </div> ); } - private renderMenuItems(menuItemNames: string[]): React.ReactNode[] { - const menuItemStyles = this.props.shouldDisplaySectionHeaders ? - styles.menuItemWithHeaders : - styles.menuItemWithoutHeaders; - const menuItemInnerDivStyles = this.props.shouldDisplaySectionHeaders ? - styles.menuItemInnerDivWithHeaders : {}; + private _renderMenuItems(menuItemNames: string[]): React.ReactNode[] { + const menuItemStyles = this.props.shouldDisplaySectionHeaders + ? styles.menuItemWithHeaders + : styles.menuItemWithoutHeaders; + const menuItemInnerDivStyles = this.props.shouldDisplaySectionHeaders ? styles.menuItemInnerDivWithHeaders : {}; const menuItems = _.map(menuItemNames, menuItemName => { const id = utils.getIdFromName(menuItemName); return ( @@ -106,57 +94,60 @@ export class NestedSidebarMenu extends React.Component<NestedSidebarMenuProps, N containerId={constants.DOCS_CONTAINER_ID} > <MenuItem - onTouchTap={this.onMenuItemClick.bind(this, menuItemName)} + onTouchTap={this._onMenuItemClick.bind(this, menuItemName)} style={menuItemStyles} innerDivStyle={menuItemInnerDivStyles} > - <span style={{textTransform: 'capitalize'}}> - {menuItemName} - </span> + <span style={{ textTransform: 'capitalize' }}>{menuItemName}</span> </MenuItem> </ScrollLink> - {this.renderMenuItemSubsections(menuItemName)} + {this._renderMenuItemSubsections(menuItemName)} </div> ); }); return menuItems; } - private renderMenuItemSubsections(menuItemName: string): React.ReactNode { + private _renderMenuItemSubsections(menuItemName: string): React.ReactNode { if (_.isUndefined(this.props.menuSubsectionsBySection[menuItemName])) { return null; } - return this.renderMenuSubsectionsBySection(menuItemName, this.props.menuSubsectionsBySection[menuItemName]); + return this._renderMenuSubsectionsBySection(menuItemName, this.props.menuSubsectionsBySection[menuItemName]); } - private renderMenuSubsectionsBySection(menuItemName: string, entityNames: string[]): React.ReactNode { + private _renderMenuSubsectionsBySection(menuItemName: string, entityNames: string[]): React.ReactNode { return ( - <ul style={{margin: 0, listStyleType: 'none', paddingLeft: 0}} key={menuItemName}> - {_.map(entityNames, entityName => { - const id = utils.getIdFromName(entityName); - return ( - <li key={`menuItem-${entityName}`}> - <ScrollLink - to={id} - offset={0} - duration={constants.DOCS_SCROLL_DURATION_MS} - containerId={constants.DOCS_CONTAINER_ID} - onTouchTap={this.onMenuItemClick.bind(this, entityName)} - > - <MenuItem - onTouchTap={this.onMenuItemClick.bind(this, menuItemName)} - style={{minHeight: 35}} - innerDivStyle={{paddingLeft: 36, fontSize: 14, lineHeight: '35px'}} + <ul style={{ margin: 0, listStyleType: 'none', paddingLeft: 0 }} key={menuItemName}> + {_.map(entityNames, entityName => { + const name = `${menuItemName}-${entityName}`; + const id = utils.getIdFromName(name); + return ( + <li key={`menuItem-${entityName}`}> + <ScrollLink + to={id} + offset={0} + duration={constants.DOCS_SCROLL_DURATION_MS} + containerId={constants.DOCS_CONTAINER_ID} + onTouchTap={this._onMenuItemClick.bind(this, name)} > - {entityName} - </MenuItem> - </ScrollLink> - </li> - ); - })} + <MenuItem + onTouchTap={this._onMenuItemClick.bind(this, name)} + style={{ minHeight: 35 }} + innerDivStyle={{ + paddingLeft: 36, + fontSize: 14, + lineHeight: '35px', + }} + > + {entityName} + </MenuItem> + </ScrollLink> + </li> + ); + })} </ul> ); } - private onMenuItemClick(menuItemName: string): void { - const id = utils.getIdFromName(menuItemName); + private _onMenuItemClick(name: string): void { + const id = utils.getIdFromName(name); utils.setUrlHash(id); this.props.onMenuItemClick(); } diff --git a/packages/website/ts/pages/shared/section_header.tsx b/packages/website/ts/pages/shared/section_header.tsx index b5119b128..a5f5f52cf 100644 --- a/packages/website/ts/pages/shared/section_header.tsx +++ b/packages/website/ts/pages/shared/section_header.tsx @@ -1,8 +1,8 @@ import * as React from 'react'; -import {Element as ScrollElement} from 'react-scroll'; -import {AnchorTitle} from 'ts/pages/shared/anchor_title'; -import {HeaderSizes} from 'ts/types'; -import {utils} from 'ts/utils/utils'; +import { Element as ScrollElement } from 'react-scroll'; +import { AnchorTitle } from 'ts/pages/shared/anchor_title'; +import { HeaderSizes } from 'ts/types'; +import { utils } from 'ts/utils/utils'; interface SectionHeaderProps { sectionName: string; @@ -28,13 +28,13 @@ export class SectionHeader extends React.Component<SectionHeaderProps, SectionHe const id = utils.getIdFromName(sectionName); return ( <div - onMouseOver={this.setAnchorVisibility.bind(this, true)} - onMouseOut={this.setAnchorVisibility.bind(this, false)} + onMouseOver={this._setAnchorVisibility.bind(this, true)} + onMouseOut={this._setAnchorVisibility.bind(this, false)} > <ScrollElement name={id}> <AnchorTitle headerSize={this.props.headerSize} - title={<span style={{textTransform: 'capitalize'}}>{sectionName}</span>} + title={<span style={{ textTransform: 'capitalize' }}>{sectionName}</span>} id={id} shouldShowAnchor={this.state.shouldShowAnchor} /> @@ -42,7 +42,7 @@ export class SectionHeader extends React.Component<SectionHeaderProps, SectionHe </div> ); } - private setAnchorVisibility(shouldShowAnchor: boolean) { + private _setAnchorVisibility(shouldShowAnchor: boolean) { this.setState({ shouldShowAnchor, }); diff --git a/packages/website/ts/pages/shared/version_drop_down.tsx b/packages/website/ts/pages/shared/version_drop_down.tsx index 4af9a834f..b922e1048 100644 --- a/packages/website/ts/pages/shared/version_drop_down.tsx +++ b/packages/website/ts/pages/shared/version_drop_down.tsx @@ -2,8 +2,6 @@ import * as _ from 'lodash'; import DropDownMenu from 'material-ui/DropDownMenu'; import MenuItem from 'material-ui/MenuItem'; import * as React from 'react'; -import {Docs} from 'ts/types'; -import {constants} from 'ts/utils/constants'; interface VersionDropDownProps { selectedVersion: string; @@ -16,30 +14,24 @@ interface VersionDropDownState {} export class VersionDropDown extends React.Component<VersionDropDownProps, VersionDropDownState> { public render() { return ( - <div className="mx-auto" style={{width: 120}}> + <div className="mx-auto" style={{ width: 120 }}> <DropDownMenu maxHeight={300} value={this.props.selectedVersion} - onChange={this.updateSelectedVersion.bind(this)} + onChange={this._updateSelectedVersion.bind(this)} > - {this.renderDropDownItems()} + {this._renderDropDownItems()} </DropDownMenu> </div> ); } - private renderDropDownItems() { + private _renderDropDownItems() { const items = _.map(this.props.versions, version => { - return ( - <MenuItem - key={version} - value={version} - primaryText={`v${version}`} - /> - ); + return <MenuItem key={version} value={version} primaryText={`v${version}`} />; }); return items; } - private updateSelectedVersion(e: any, index: number, value: string) { + private _updateSelectedVersion(e: any, index: number, value: string) { window.location.href = `${this.props.docPath}/${value}${window.location.hash}`; } } diff --git a/packages/website/ts/pages/wiki/wiki.tsx b/packages/website/ts/pages/wiki/wiki.tsx index 2447a24a2..d065614ba 100644 --- a/packages/website/ts/pages/wiki/wiki.tsx +++ b/packages/website/ts/pages/wiki/wiki.tsx @@ -1,19 +1,17 @@ import * as _ from 'lodash'; import CircularProgress from 'material-ui/CircularProgress'; -import {colors} from 'material-ui/styles'; import * as React from 'react'; import DocumentTitle = require('react-document-title'); -import { - scroller, -} from 'react-scroll'; -import {TopBar} from 'ts/components/top_bar'; -import {MarkdownSection} from 'ts/pages/shared/markdown_section'; -import {NestedSidebarMenu} from 'ts/pages/shared/nested_sidebar_menu'; -import {SectionHeader} from 'ts/pages/shared/section_header'; -import {Article, ArticlesBySection, HeaderSizes, Styles, WebsitePaths} from 'ts/types'; -import {configs} from 'ts/utils/configs'; -import {constants} from 'ts/utils/constants'; -import {utils} from 'ts/utils/utils'; +import { scroller } from 'react-scroll'; +import { TopBar } from 'ts/components/top_bar'; +import { MarkdownSection } from 'ts/pages/shared/markdown_section'; +import { NestedSidebarMenu } from 'ts/pages/shared/nested_sidebar_menu'; +import { SectionHeader } from 'ts/pages/shared/section_header'; +import { Article, ArticlesBySection, HeaderSizes, Styles, WebsitePaths } from 'ts/types'; +import { colors } from 'ts/utils/colors'; +import { configs } from 'ts/utils/configs'; +import { constants } from 'ts/utils/constants'; +import { utils } from 'ts/utils/utils'; const WIKI_NOT_READY_BACKOUT_TIMEOUT_MS = 5000; @@ -29,13 +27,13 @@ interface WikiState { const styles: Styles = { mainContainers: { position: 'absolute', - top: 60, + top: 1, left: 0, bottom: 0, right: 0, overflowZ: 'hidden', overflowY: 'scroll', - minHeight: 'calc(100vh - 60px)', + minHeight: 'calc(100vh - 1px)', WebkitOverflowScrolling: 'touch', }, menuContainer: { @@ -46,7 +44,7 @@ const styles: Styles = { }; export class Wiki extends React.Component<WikiProps, WikiState> { - private wikiBackoffTimeoutId: number; + private _wikiBackoffTimeoutId: number; constructor(props: WikiProps) { super(props); this.state = { @@ -55,47 +53,44 @@ export class Wiki extends React.Component<WikiProps, WikiState> { } public componentWillMount() { // tslint:disable-next-line:no-floating-promises - this.fetchArticlesBySectionAsync(); + this._fetchArticlesBySectionAsync(); } public componentWillUnmount() { - clearTimeout(this.wikiBackoffTimeoutId); + clearTimeout(this._wikiBackoffTimeoutId); } public render() { const menuSubsectionsBySection = _.isUndefined(this.state.articlesBySection) - ? {} - : this.getMenuSubsectionsBySection(this.state.articlesBySection); + ? {} + : this._getMenuSubsectionsBySection(this.state.articlesBySection); return ( <div> - <DocumentTitle title="0x Protocol Wiki"/> + <DocumentTitle title="0x Protocol Wiki" /> <TopBar blockchainIsLoaded={false} location={this.props.location} menuSubsectionsBySection={menuSubsectionsBySection} shouldFullWidth={true} /> - {_.isUndefined(this.state.articlesBySection) ? - <div - className="col col-12" - style={styles.mainContainers} - > + {_.isUndefined(this.state.articlesBySection) ? ( + <div className="col col-12" style={styles.mainContainers}> <div className="relative sm-px2 sm-pt2 sm-m1" - style={{height: 122, top: '50%', transform: 'translateY(-50%)'}} + style={{ height: 122, top: '50%', transform: 'translateY(-50%)' }} > <div className="center pb2"> <CircularProgress size={40} thickness={5} /> </div> - <div className="center pt2" style={{paddingBottom: 11}}>Loading wiki...</div> + <div className="center pt2" style={{ paddingBottom: 11 }}> + Loading wiki... + </div> </div> - </div> : - <div - className="mx-auto flex" - style={{color: colors.grey800, height: 43}} - > + </div> + ) : ( + <div className="mx-auto flex" style={{ color: colors.grey800, height: 43 }}> <div className="relative col md-col-3 lg-col-3 lg-pl0 md-pl1 sm-hide xs-hide"> <div className="border-right absolute pt2" - style={{...styles.menuContainer, ...styles.mainContainers}} + style={{ ...styles.menuContainer, ...styles.mainContainers }} > <NestedSidebarMenu topLevelMenu={menuSubsectionsBySection} @@ -105,36 +100,30 @@ export class Wiki extends React.Component<WikiProps, WikiState> { </div> </div> <div className="relative col lg-col-9 md-col-9 sm-col-12 col-12"> - <div - id="documentation" - style={styles.mainContainers} - className="absolute" - > + <div id="documentation" style={styles.mainContainers} className="absolute"> <div id="0xProtocolWiki" /> <h1 className="md-pl2 sm-pl3"> - <a href={constants.GITHUB_WIKI_URL} target="_blank"> + <a href={constants.URL_GITHUB_WIKI} target="_blank"> 0x Protocol Wiki </a> </h1> - <div id="wiki"> - {this.renderWikiArticles()} - </div> + <div id="wiki">{this._renderWikiArticles()}</div> </div> </div> </div> - } + )} </div> ); } - private renderWikiArticles(): React.ReactNode { + private _renderWikiArticles(): React.ReactNode { const sectionNames = _.keys(this.state.articlesBySection); - const sections = _.map(sectionNames, sectionName => this.renderSection(sectionName)); + const sections = _.map(sectionNames, sectionName => this._renderSection(sectionName)); return sections; } - private renderSection(sectionName: string) { + private _renderSection(sectionName: string) { const articles = this.state.articlesBySection[sectionName]; const renderedArticles = _.map(articles, (article: Article) => { - const githubLink = `${constants.GITHUB_WIKI_URL}/edit/master/${sectionName}/${article.fileName}`; + const githubLink = `${constants.URL_GITHUB_WIKI}/edit/master/${sectionName}/${article.fileName}`; return ( <div key={`markdown-section-${article.title}`}> <MarkdownSection @@ -143,12 +132,9 @@ export class Wiki extends React.Component<WikiProps, WikiState> { headerSize={HeaderSizes.H2} githubLink={githubLink} /> - <div className="mb4 mt3 p3 center" style={{backgroundColor: '#f9f5ef'}}> + <div className="mb4 mt3 p3 center" style={{ backgroundColor: colors.lightestGrey }}> See a way to make this article better?{' '} - <a - href={githubLink} - target="_blank" - > + <a href={githubLink} target="_blank"> Edit here → </a> </div> @@ -156,32 +142,33 @@ export class Wiki extends React.Component<WikiProps, WikiState> { ); }); return ( - <div - key={`section-${sectionName}`} - className="py2 pr3 md-pl2 sm-pl3" - > + <div key={`section-${sectionName}`} className="py2 pr3 md-pl2 sm-pl3"> <SectionHeader sectionName={sectionName} headerSize={HeaderSizes.H1} /> {renderedArticles} </div> ); } - private scrollToHash(): void { + private _scrollToHash(): void { const hashWithPrefix = this.props.location.hash; let hash = hashWithPrefix.slice(1); if (_.isEmpty(hash)) { hash = '0xProtocolWiki'; // scroll to the top } - scroller.scrollTo(hash, {duration: 0, offset: 0, containerId: 'documentation'}); + scroller.scrollTo(hash, { + duration: 0, + offset: 0, + containerId: 'documentation', + }); } - private async fetchArticlesBySectionAsync(): Promise<void> { + private async _fetchArticlesBySectionAsync(): Promise<void> { const endpoint = `${configs.BACKEND_BASE_URL}${WebsitePaths.Wiki}`; const response = await fetch(endpoint); if (response.status === constants.HTTP_NO_CONTENT_STATUS_CODE) { // We need to backoff and try fetching again later - this.wikiBackoffTimeoutId = window.setTimeout(() => { + this._wikiBackoffTimeoutId = window.setTimeout(() => { // tslint:disable-next-line:no-floating-promises - this.fetchArticlesBySectionAsync(); + this._fetchArticlesBySectionAsync(); }, WIKI_NOT_READY_BACKOUT_TIMEOUT_MS); return; } @@ -192,15 +179,18 @@ export class Wiki extends React.Component<WikiProps, WikiState> { return; } const articlesBySection = await response.json(); - this.setState({ - articlesBySection, - }, () => { - this.scrollToHash(); - }); + this.setState( + { + articlesBySection, + }, + () => { + this._scrollToHash(); + }, + ); } - private getMenuSubsectionsBySection(articlesBySection: ArticlesBySection) { + private _getMenuSubsectionsBySection(articlesBySection: ArticlesBySection) { const sectionNames = _.keys(articlesBySection); - const menuSubsectionsBySection: {[section: string]: string[]} = {}; + const menuSubsectionsBySection: { [section: string]: string[] } = {}; for (const sectionName of sectionNames) { const articles = articlesBySection[sectionName]; const articleNames = _.map(articles, article => article.title); diff --git a/packages/website/ts/redux/dispatcher.ts b/packages/website/ts/redux/dispatcher.ts index a0a1da21b..42989e5e1 100644 --- a/packages/website/ts/redux/dispatcher.ts +++ b/packages/website/ts/redux/dispatcher.ts @@ -1,12 +1,10 @@ -import BigNumber from 'bignumber.js'; -import {Dispatch} from 'redux'; -import {State} from 'ts/redux/reducer'; +import { BigNumber } from '@0xproject/utils'; +import { Dispatch } from 'redux'; +import { State } from 'ts/redux/reducer'; import { ActionTypes, AssetToken, BlockchainErrs, - Direction, - Fill, Order, ProviderType, ScreenWidths, @@ -17,227 +15,221 @@ import { } from 'ts/types'; export class Dispatcher { - private dispatch: Dispatch<State>; + private _dispatch: Dispatch<State>; constructor(dispatch: Dispatch<State>) { - this.dispatch = dispatch; + this._dispatch = dispatch; } // Portal public resetState() { - this.dispatch({ - type: ActionTypes.RESET_STATE, + this._dispatch({ + type: ActionTypes.ResetState, }); } public updateNodeVersion(nodeVersion: string) { - this.dispatch({ + this._dispatch({ data: nodeVersion, - type: ActionTypes.UPDATE_NODE_VERSION, + type: ActionTypes.UpdateNodeVersion, }); } public updateScreenWidth(screenWidth: ScreenWidths) { - this.dispatch({ + this._dispatch({ data: screenWidth, - type: ActionTypes.UPDATE_SCREEN_WIDTH, + type: ActionTypes.UpdateScreenWidth, }); } public swapAssetTokenSymbols() { - this.dispatch({ - type: ActionTypes.SWAP_ASSET_TOKENS, - }); - } - public updateGenerateOrderStep(direction: Direction) { - this.dispatch({ - data: direction, - type: ActionTypes.UPDATE_GENERATE_ORDER_STEP, + this._dispatch({ + type: ActionTypes.SwapAssetTokens, }); } public updateOrderSalt(salt: BigNumber) { - this.dispatch({ + this._dispatch({ data: salt, - type: ActionTypes.UPDATE_ORDER_SALT, + type: ActionTypes.UpdateOrderSalt, }); } public updateUserSuppliedOrderCache(order: Order) { - this.dispatch({ + this._dispatch({ data: order, - type: ActionTypes.UPDATE_USER_SUPPLIED_ORDER_CACHE, + type: ActionTypes.UpdateUserSuppliedOrderCache, }); } public updateShouldBlockchainErrDialogBeOpen(shouldBeOpen: boolean) { - this.dispatch({ + this._dispatch({ data: shouldBeOpen, - type: ActionTypes.UPDATE_SHOULD_BLOCKCHAIN_ERR_DIALOG_BE_OPEN, + type: ActionTypes.UpdateShouldBlockchainErrDialogBeOpen, }); } public updateChosenAssetToken(side: Side, token: AssetToken) { - this.dispatch({ + this._dispatch({ data: { side, token, }, - type: ActionTypes.UPDATE_CHOSEN_ASSET_TOKEN, + type: ActionTypes.UpdateChosenAssetToken, }); } public updateChosenAssetTokenAddress(side: Side, address: string) { - this.dispatch({ + this._dispatch({ data: { address, side, }, - type: ActionTypes.UPDATE_CHOSEN_ASSET_TOKEN_ADDRESS, + type: ActionTypes.UpdateChosenAssetTokenAddress, }); } public updateOrderTakerAddress(address: string) { - this.dispatch({ + this._dispatch({ data: address, - type: ActionTypes.UPDATE_ORDER_TAKER_ADDRESS, + type: ActionTypes.UpdateOrderTakerAddress, }); } public updateUserAddress(address: string) { - this.dispatch({ + this._dispatch({ data: address, - type: ActionTypes.UPDATE_USER_ADDRESS, + type: ActionTypes.UpdateUserAddress, }); } public updateOrderExpiry(unixTimestampSec: BigNumber) { - this.dispatch({ + this._dispatch({ data: unixTimestampSec, - type: ActionTypes.UPDATE_ORDER_EXPIRY, + type: ActionTypes.UpdateOrderExpiry, }); } public encounteredBlockchainError(err: BlockchainErrs) { - this.dispatch({ - data: err, - type: ActionTypes.BLOCKCHAIN_ERR_ENCOUNTERED, - }); + this._dispatch({ + data: err, + type: ActionTypes.BlockchainErrEncountered, + }); } public updateBlockchainIsLoaded(isLoaded: boolean) { - this.dispatch({ - data: isLoaded, - type: ActionTypes.UPDATE_BLOCKCHAIN_IS_LOADED, - }); + this._dispatch({ + data: isLoaded, + type: ActionTypes.UpdateBlockchainIsLoaded, + }); } public addTokenToTokenByAddress(token: Token) { - this.dispatch({ - data: token, - type: ActionTypes.ADD_TOKEN_TO_TOKEN_BY_ADDRESS, - }); + this._dispatch({ + data: token, + type: ActionTypes.AddTokenToTokenByAddress, + }); } public removeTokenToTokenByAddress(token: Token) { - this.dispatch({ - data: token, - type: ActionTypes.REMOVE_TOKEN_TO_TOKEN_BY_ADDRESS, - }); + this._dispatch({ + data: token, + type: ActionTypes.RemoveTokenFromTokenByAddress, + }); } public clearTokenByAddress() { - this.dispatch({ - type: ActionTypes.CLEAR_TOKEN_BY_ADDRESS, - }); + this._dispatch({ + type: ActionTypes.ClearTokenByAddress, + }); } public updateTokenByAddress(tokens: Token[]) { - this.dispatch({ - data: tokens, - type: ActionTypes.UPDATE_TOKEN_BY_ADDRESS, - }); + this._dispatch({ + data: tokens, + type: ActionTypes.UpdateTokenByAddress, + }); } public updateTokenStateByAddress(tokenStateByAddress: TokenStateByAddress) { - this.dispatch({ - data: tokenStateByAddress, - type: ActionTypes.UPDATE_TOKEN_STATE_BY_ADDRESS, - }); + this._dispatch({ + data: tokenStateByAddress, + type: ActionTypes.UpdateTokenStateByAddress, + }); } public removeFromTokenStateByAddress(tokenAddress: string) { - this.dispatch({ + this._dispatch({ data: tokenAddress, - type: ActionTypes.REMOVE_FROM_TOKEN_STATE_BY_ADDRESS, + type: ActionTypes.RemoveFromTokenStateByAddress, }); } public replaceTokenAllowanceByAddress(address: string, allowance: BigNumber) { - this.dispatch({ + this._dispatch({ data: { - address, - allowance, + address, + allowance, }, - type: ActionTypes.REPLACE_TOKEN_ALLOWANCE_BY_ADDRESS, + type: ActionTypes.ReplaceTokenAllowanceByAddress, }); } public replaceTokenBalanceByAddress(address: string, balance: BigNumber) { - this.dispatch({ + this._dispatch({ data: { address, balance, }, - type: ActionTypes.REPLACE_TOKEN_BALANCE_BY_ADDRESS, + type: ActionTypes.ReplaceTokenBalanceByAddress, }); } public updateTokenBalanceByAddress(address: string, balanceDelta: BigNumber) { - this.dispatch({ + this._dispatch({ data: { address, balanceDelta, }, - type: ActionTypes.UPDATE_TOKEN_BALANCE_BY_ADDRESS, + type: ActionTypes.UpdateTokenBalanceByAddress, }); } public updateSignatureData(signatureData: SignatureData) { - this.dispatch({ - data: signatureData, - type: ActionTypes.UPDATE_ORDER_SIGNATURE_DATA, - }); + this._dispatch({ + data: signatureData, + type: ActionTypes.UpdateOrderSignatureData, + }); } public updateUserEtherBalance(balance: BigNumber) { - this.dispatch({ - data: balance, - type: ActionTypes.UPDATE_USER_ETHER_BALANCE, - }); + this._dispatch({ + data: balance, + type: ActionTypes.UpdateUserEtherBalance, + }); } public updateNetworkId(networkId: number) { - this.dispatch({ - data: networkId, - type: ActionTypes.UPDATE_NETWORK_ID, - }); + this._dispatch({ + data: networkId, + type: ActionTypes.UpdateNetworkId, + }); } public updateOrderFillAmount(amount: BigNumber) { - this.dispatch({ + this._dispatch({ data: amount, - type: ActionTypes.UPDATE_ORDER_FILL_AMOUNT, + type: ActionTypes.UpdateOrderFillAmount, }); } // Docs public updateCurrentDocsVersion(version: string) { - this.dispatch({ + this._dispatch({ data: version, - type: ActionTypes.UPDATE_LIBRARY_VERSION, + type: ActionTypes.UpdateLibraryVersion, }); } public updateAvailableDocVersions(versions: string[]) { - this.dispatch({ + this._dispatch({ data: versions, - type: ActionTypes.UPDATE_AVAILABLE_LIBRARY_VERSIONS, + type: ActionTypes.UpdateAvailableLibraryVersions, }); } // Shared - public showFlashMessage(msg: string|React.ReactNode) { - this.dispatch({ + public showFlashMessage(msg: string | React.ReactNode) { + this._dispatch({ data: msg, - type: ActionTypes.SHOW_FLASH_MESSAGE, + type: ActionTypes.ShowFlashMessage, }); } public hideFlashMessage() { - this.dispatch({ - type: ActionTypes.HIDE_FLASH_MESSAGE, + this._dispatch({ + type: ActionTypes.HideFlashMessage, }); } public updateProviderType(providerType: ProviderType) { - this.dispatch({ - type: ActionTypes.UPDATE_PROVIDER_TYPE, + this._dispatch({ + type: ActionTypes.UpdateProviderType, data: providerType, }); } public updateInjectedProviderName(injectedProviderName: string) { - this.dispatch({ - type: ActionTypes.UPDATE_INJECTED_PROVIDER_NAME, + this._dispatch({ + type: ActionTypes.UpdateInjectedProviderName, data: injectedProviderName, }); } diff --git a/packages/website/ts/redux/reducer.ts b/packages/website/ts/redux/reducer.ts index da69a9d00..06ac8b670 100644 --- a/packages/website/ts/redux/reducer.ts +++ b/packages/website/ts/redux/reducer.ts @@ -1,12 +1,10 @@ -import {ZeroEx} from '0x.js'; -import BigNumber from 'bignumber.js'; +import { ZeroEx } from '0x.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; import { Action, ActionTypes, BlockchainErrs, - Direction, - GenerateOrderSteps, Order, ProviderType, ScreenWidths, @@ -17,7 +15,7 @@ import { TokenState, TokenStateByAddress, } from 'ts/types'; -import {utils} from 'ts/utils/utils'; +import { utils } from 'ts/utils/utils'; // Instead of defaulting the docs version to an empty string, we pre-populate it with // a valid version value. This does not need to be updated however, since onLoad, it @@ -28,7 +26,6 @@ export interface State { // Portal blockchainErr: BlockchainErrs; blockchainIsLoaded: boolean; - generateOrderStep: GenerateOrderSteps; networkId: number; orderExpiryTimestamp: BigNumber; orderFillAmount: BigNumber; @@ -51,16 +48,15 @@ export interface State { availableDocVersions: string[]; // Shared - flashMessage: string|React.ReactNode; + flashMessage: string | React.ReactNode; providerType: ProviderType; injectedProviderName: string; } const INITIAL_STATE: State = { // Portal - blockchainErr: '', + blockchainErr: BlockchainErrs.NoError, blockchainIsLoaded: false, - generateOrderStep: GenerateOrderSteps.ChooseAssets, networkId: undefined, orderExpiryTimestamp: utils.initialOrderExpiryUnixTimestampSec(), orderFillAmount: undefined, @@ -76,8 +72,8 @@ const INITIAL_STATE: State = { screenWidth: utils.getScreenWidth(), shouldBlockchainErrDialogBeOpen: false, sideToAssetToken: { - [Side.deposit]: {}, - [Side.receive]: {}, + [Side.Deposit]: {}, + [Side.Receive]: {}, }, tokenByAddress: {}, tokenStateByAddress: {}, @@ -91,270 +87,300 @@ const INITIAL_STATE: State = { // Shared flashMessage: undefined, - providerType: ProviderType.INJECTED, + providerType: ProviderType.Injected, injectedProviderName: '', }; export function reducer(state: State = INITIAL_STATE, action: Action) { switch (action.type) { // Portal - case ActionTypes.RESET_STATE: + case ActionTypes.ResetState: return INITIAL_STATE; - case ActionTypes.UPDATE_ORDER_SALT: { - return _.assign({}, state, { + case ActionTypes.UpdateOrderSalt: { + return { + ...state, orderSalt: action.data, - }); + }; } - case ActionTypes.UPDATE_NODE_VERSION: { - return _.assign({}, state, { + case ActionTypes.UpdateNodeVersion: { + return { + ...state, nodeVersion: action.data, - }); + }; } - case ActionTypes.UPDATE_ORDER_FILL_AMOUNT: { - return _.assign({}, state, { + case ActionTypes.UpdateOrderFillAmount: { + return { + ...state, orderFillAmount: action.data, - }); + }; } - case ActionTypes.UPDATE_SHOULD_BLOCKCHAIN_ERR_DIALOG_BE_OPEN: { - return _.assign({}, state, { + case ActionTypes.UpdateShouldBlockchainErrDialogBeOpen: { + return { + ...state, shouldBlockchainErrDialogBeOpen: action.data, - }); + }; } - case ActionTypes.UPDATE_USER_ETHER_BALANCE: { - return _.assign({}, state, { + case ActionTypes.UpdateUserEtherBalance: { + return { + ...state, userEtherBalance: action.data, - }); + }; } - case ActionTypes.UPDATE_USER_SUPPLIED_ORDER_CACHE: { - return _.assign({}, state, { + case ActionTypes.UpdateUserSuppliedOrderCache: { + return { + ...state, userSuppliedOrderCache: action.data, - }); + }; } - case ActionTypes.CLEAR_TOKEN_BY_ADDRESS: { - return _.assign({}, state, { + case ActionTypes.ClearTokenByAddress: { + return { + ...state, tokenByAddress: {}, - }); + }; } - case ActionTypes.ADD_TOKEN_TO_TOKEN_BY_ADDRESS: { + case ActionTypes.AddTokenToTokenByAddress: { const newTokenByAddress = state.tokenByAddress; newTokenByAddress[action.data.address] = action.data; - return _.assign({}, state, { + return { + ...state, tokenByAddress: newTokenByAddress, - }); + }; } - case ActionTypes.REMOVE_TOKEN_TO_TOKEN_BY_ADDRESS: { + case ActionTypes.RemoveTokenFromTokenByAddress: { const newTokenByAddress = state.tokenByAddress; delete newTokenByAddress[action.data.address]; - return _.assign({}, state, { + return { + ...state, tokenByAddress: newTokenByAddress, - }); + }; } - case ActionTypes.UPDATE_TOKEN_BY_ADDRESS: { + case ActionTypes.UpdateTokenByAddress: { const tokenByAddress = state.tokenByAddress; const tokens = action.data; _.each(tokens, token => { - const updatedToken = _.assign({}, tokenByAddress[token.address], token); + const updatedToken = { + ...tokenByAddress[token.address], + ...token, + }; tokenByAddress[token.address] = updatedToken; }); - return _.assign({}, state, { + return { + ...state, tokenByAddress, - }); + }; } - case ActionTypes.UPDATE_TOKEN_STATE_BY_ADDRESS: { + case ActionTypes.UpdateTokenStateByAddress: { const tokenStateByAddress = state.tokenStateByAddress; const updatedTokenStateByAddress = action.data; _.each(updatedTokenStateByAddress, (tokenState: TokenState, address: string) => { - const updatedTokenState = _.assign({}, tokenStateByAddress[address], tokenState); + const updatedTokenState = { + ...tokenStateByAddress[address], + ...tokenState, + }; tokenStateByAddress[address] = updatedTokenState; }); - return _.assign({}, state, { + return { + ...state, tokenStateByAddress, - }); + }; } - case ActionTypes.REMOVE_FROM_TOKEN_STATE_BY_ADDRESS: { + case ActionTypes.RemoveFromTokenStateByAddress: { const tokenStateByAddress = state.tokenStateByAddress; const tokenAddress = action.data; delete tokenStateByAddress[tokenAddress]; - return _.assign({}, state, { + return { + ...state, tokenStateByAddress, - }); + }; } - case ActionTypes.REPLACE_TOKEN_ALLOWANCE_BY_ADDRESS: { + case ActionTypes.ReplaceTokenAllowanceByAddress: { const tokenStateByAddress = state.tokenStateByAddress; const allowance = action.data.allowance; const tokenAddress = action.data.address; - tokenStateByAddress[tokenAddress] = _.assign({}, tokenStateByAddress[tokenAddress], { + tokenStateByAddress[tokenAddress] = { + ...tokenStateByAddress[tokenAddress], allowance, - }); - return _.assign({}, state, { + }; + return { + ...state, tokenStateByAddress, - }); + }; } - case ActionTypes.REPLACE_TOKEN_BALANCE_BY_ADDRESS: { + case ActionTypes.ReplaceTokenBalanceByAddress: { const tokenStateByAddress = state.tokenStateByAddress; const balance = action.data.balance; const tokenAddress = action.data.address; - tokenStateByAddress[tokenAddress] = _.assign({}, tokenStateByAddress[tokenAddress], { + tokenStateByAddress[tokenAddress] = { + ...tokenStateByAddress[tokenAddress], balance, - }); - return _.assign({}, state, { + }; + return { + ...state, tokenStateByAddress, - }); + }; } - case ActionTypes.UPDATE_TOKEN_BALANCE_BY_ADDRESS: { + case ActionTypes.UpdateTokenBalanceByAddress: { const tokenStateByAddress = state.tokenStateByAddress; const balanceDelta = action.data.balanceDelta; const tokenAddress = action.data.address; const currBalance = tokenStateByAddress[tokenAddress].balance; - tokenStateByAddress[tokenAddress] = _.assign({}, tokenStateByAddress[tokenAddress], { + tokenStateByAddress[tokenAddress] = { + ...tokenStateByAddress[tokenAddress], balance: currBalance.plus(balanceDelta), - }); - return _.assign({}, state, { + }; + return { + ...state, tokenStateByAddress, - }); + }; } - case ActionTypes.UPDATE_ORDER_SIGNATURE_DATA: { - return _.assign({}, state, { + case ActionTypes.UpdateOrderSignatureData: { + return { + ...state, orderSignatureData: action.data, - }); + }; } - case ActionTypes.UPDATE_SCREEN_WIDTH: { - return _.assign({}, state, { + case ActionTypes.UpdateScreenWidth: { + return { + ...state, screenWidth: action.data, - }); + }; } - case ActionTypes.UPDATE_BLOCKCHAIN_IS_LOADED: { - return _.assign({}, state, { + case ActionTypes.UpdateBlockchainIsLoaded: { + return { + ...state, blockchainIsLoaded: action.data, - }); + }; } - case ActionTypes.BLOCKCHAIN_ERR_ENCOUNTERED: { - return _.assign({}, state, { + case ActionTypes.BlockchainErrEncountered: { + return { + ...state, blockchainErr: action.data, - }); + }; } - case ActionTypes.UPDATE_NETWORK_ID: { - return _.assign({}, state, { + case ActionTypes.UpdateNetworkId: { + return { + ...state, networkId: action.data, - }); - } - - case ActionTypes.UPDATE_GENERATE_ORDER_STEP: { - const direction = action.data; - let nextGenerateOrderStep = state.generateOrderStep; - if (direction === Direction.forward) { - nextGenerateOrderStep += 1; - } else if (state.generateOrderStep !== 0) { - nextGenerateOrderStep -= 1; - } - return _.assign({}, state, { - generateOrderStep: nextGenerateOrderStep, - }); + }; } - case ActionTypes.UPDATE_CHOSEN_ASSET_TOKEN: { - const newSideToAssetToken = _.assign({}, state.sideToAssetToken, { + case ActionTypes.UpdateChosenAssetToken: { + const newSideToAssetToken = { + ...state.sideToAssetToken, [action.data.side]: action.data.token, - }); - return _.assign({}, state, { + }; + return { + ...state, sideToAssetToken: newSideToAssetToken, - }); + }; } - case ActionTypes.UPDATE_CHOSEN_ASSET_TOKEN_ADDRESS: { + case ActionTypes.UpdateChosenAssetTokenAddress: { const newAssetToken = state.sideToAssetToken[action.data.side]; newAssetToken.address = action.data.address; - const newSideToAssetToken = _.assign({}, state.sideToAssetToken, { + const newSideToAssetToken = { + ...state.sideToAssetToken, [action.data.side]: newAssetToken, - }); - return _.assign({}, state, { + }; + return { + ...state, sideToAssetToken: newSideToAssetToken, - }); + }; } - case ActionTypes.SWAP_ASSET_TOKENS: { - const newSideToAssetToken = _.assign({}, state.sideToAssetToken, { - [Side.deposit]: state.sideToAssetToken[Side.receive], - [Side.receive]: state.sideToAssetToken[Side.deposit], - }); - return _.assign({}, state, { + case ActionTypes.SwapAssetTokens: { + const newSideToAssetToken = { + [Side.Deposit]: state.sideToAssetToken[Side.Receive], + [Side.Receive]: state.sideToAssetToken[Side.Deposit], + }; + return { + ...state, sideToAssetToken: newSideToAssetToken, - }); + }; } - case ActionTypes.UPDATE_ORDER_EXPIRY: { - return _.assign({}, state, { + case ActionTypes.UpdateOrderExpiry: { + return { + ...state, orderExpiryTimestamp: action.data, - }); + }; } - case ActionTypes.UPDATE_ORDER_TAKER_ADDRESS: { - return _.assign({}, state, { + case ActionTypes.UpdateOrderTakerAddress: { + return { + ...state, orderTakerAddress: action.data, - }); + }; } - case ActionTypes.UPDATE_USER_ADDRESS: { - return _.assign({}, state, { + case ActionTypes.UpdateUserAddress: { + return { + ...state, userAddress: action.data, - }); + }; } // Docs - case ActionTypes.UPDATE_LIBRARY_VERSION: { - return _.assign({}, state, { + case ActionTypes.UpdateLibraryVersion: { + return { + ...state, docsVersion: action.data, - }); + }; } - case ActionTypes.UPDATE_AVAILABLE_LIBRARY_VERSIONS: { - return _.assign({}, state, { + case ActionTypes.UpdateAvailableLibraryVersions: { + return { + ...state, availableDocVersions: action.data, - }); + }; } // Shared - case ActionTypes.SHOW_FLASH_MESSAGE: { - return _.assign({}, state, { + case ActionTypes.ShowFlashMessage: { + return { + ...state, flashMessage: action.data, - }); + }; } - case ActionTypes.HIDE_FLASH_MESSAGE: { - return _.assign({}, state, { + case ActionTypes.HideFlashMessage: { + return { + ...state, flashMessage: undefined, - }); + }; } - case ActionTypes.UPDATE_PROVIDER_TYPE: { - return _.assign({}, state, { + case ActionTypes.UpdateProviderType: { + return { + ...state, providerType: action.data, - }); + }; } - case ActionTypes.UPDATE_INJECTED_PROVIDER_NAME: { - return _.assign({}, state, { + case ActionTypes.UpdateInjectedProviderName: { + return { + ...state, injectedProviderName: action.data, - }); + }; } default: diff --git a/packages/website/ts/schemas/order_schema.ts b/packages/website/ts/schemas/order_schema.ts index 61b93d273..bfbf9eb8b 100644 --- a/packages/website/ts/schemas/order_schema.ts +++ b/packages/website/ts/schemas/order_schema.ts @@ -1,24 +1,15 @@ export const orderSchema = { id: '/Order', properties: { - maker: {$ref: '/OrderTaker'}, - taker: {$ref: '/OrderTaker'}, - salt: {type: 'string'}, - signature: {$ref: '/SignatureData'}, - expiration: {type: 'string'}, - feeRecipient: {type: 'string'}, - exchangeContract: {type: 'string'}, - networkId: {type: 'number'}, + maker: { $ref: '/OrderTaker' }, + taker: { $ref: '/OrderTaker' }, + salt: { type: 'string' }, + signature: { $ref: '/SignatureData' }, + expiration: { type: 'string' }, + feeRecipient: { type: 'string' }, + exchangeContract: { type: 'string' }, + networkId: { type: 'number' }, }, - required: [ - 'maker', - 'taker', - 'salt', - 'signature', - 'expiration', - 'feeRecipient', - 'exchangeContract', - 'networkId', - ], + required: ['maker', 'taker', 'salt', 'signature', 'expiration', 'feeRecipient', 'exchangeContract', 'networkId'], type: 'object', }; diff --git a/packages/website/ts/schemas/order_taker_schema.ts b/packages/website/ts/schemas/order_taker_schema.ts index 6b484a60d..c784c29c5 100644 --- a/packages/website/ts/schemas/order_taker_schema.ts +++ b/packages/website/ts/schemas/order_taker_schema.ts @@ -1,10 +1,10 @@ export const orderTakerSchema = { id: '/OrderTaker', properties: { - address: {type: 'string'}, - token: {$ref: '/Token'}, - amount: {type: 'string'}, - feeAmount: {type: 'string'}, + address: { type: 'string' }, + token: { $ref: '/Token' }, + amount: { type: 'string' }, + feeAmount: { type: 'string' }, }, required: ['address', 'token', 'amount', 'feeAmount'], type: 'object', diff --git a/packages/website/ts/schemas/signature_data_schema.ts b/packages/website/ts/schemas/signature_data_schema.ts index d208cc438..8d3f15926 100644 --- a/packages/website/ts/schemas/signature_data_schema.ts +++ b/packages/website/ts/schemas/signature_data_schema.ts @@ -1,10 +1,10 @@ export const signatureDataSchema = { id: '/SignatureData', properties: { - hash: {type: 'string'}, - r: {type: 'string'}, - s: {type: 'string'}, - v: {type: 'number'}, + hash: { type: 'string' }, + r: { type: 'string' }, + s: { type: 'string' }, + v: { type: 'number' }, }, required: ['hash', 'r', 's', 'v'], type: 'object', diff --git a/packages/website/ts/schemas/token_schema.ts b/packages/website/ts/schemas/token_schema.ts index c15f57429..92b53a463 100644 --- a/packages/website/ts/schemas/token_schema.ts +++ b/packages/website/ts/schemas/token_schema.ts @@ -1,10 +1,10 @@ export const tokenSchema = { id: '/Token', properties: { - name: {type: 'string'}, - symbol: {type: 'string'}, - decimals: {type: 'number'}, - address: {type: 'string'}, + name: { type: 'string' }, + symbol: { type: 'string' }, + decimals: { type: 'number' }, + address: { type: 'string' }, }, required: ['name', 'symbol', 'decimals', 'address'], type: 'object', diff --git a/packages/website/ts/schemas/validator.ts b/packages/website/ts/schemas/validator.ts index e8eb4aaf2..5177501c6 100644 --- a/packages/website/ts/schemas/validator.ts +++ b/packages/website/ts/schemas/validator.ts @@ -1,19 +1,19 @@ -import {Schema as JSONSchema, Validator} from 'jsonschema'; -import {orderSchema} from 'ts/schemas/order_schema'; -import {orderTakerSchema} from 'ts/schemas/order_taker_schema'; -import {signatureDataSchema} from 'ts/schemas/signature_data_schema'; -import {tokenSchema} from 'ts/schemas/token_schema'; +import { Schema as JSONSchema, Validator } from 'jsonschema'; +import { orderSchema } from 'ts/schemas/order_schema'; +import { orderTakerSchema } from 'ts/schemas/order_taker_schema'; +import { signatureDataSchema } from 'ts/schemas/signature_data_schema'; +import { tokenSchema } from 'ts/schemas/token_schema'; export class SchemaValidator { - private validator: Validator; + private _validator: Validator; constructor() { - this.validator = new Validator(); - this.validator.addSchema(signatureDataSchema as JSONSchema, signatureDataSchema.id); - this.validator.addSchema(tokenSchema as JSONSchema, tokenSchema.id); - this.validator.addSchema(orderTakerSchema as JSONSchema, orderTakerSchema.id); - this.validator.addSchema(orderSchema as JSONSchema, orderSchema.id); + this._validator = new Validator(); + this._validator.addSchema(signatureDataSchema as JSONSchema, signatureDataSchema.id); + this._validator.addSchema(tokenSchema as JSONSchema, tokenSchema.id); + this._validator.addSchema(orderTakerSchema as JSONSchema, orderTakerSchema.id); + this._validator.addSchema(orderSchema as JSONSchema, orderSchema.id); } public validate(instance: object, schema: Schema) { - return this.validator.validate(instance, schema); + return this._validator.validate(instance, schema); } } diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts index d225e7784..f873f95fa 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -1,41 +1,10 @@ -import BigNumber from 'bignumber.js'; +import { BigNumber } from '@0xproject/utils'; import * as _ from 'lodash'; -// Utility function to create a K:V from a list of strings -// Adapted from: https://basarat.gitbooks.io/typescript/content/docs/types/literal-types.html -function strEnum(values: string[]): {[key: string]: string} { - return _.reduce(values, (result, key) => { - result[key] = key; - return result; - }, Object.create(null)); -} - -export enum GenerateOrderSteps { - ChooseAssets, - GrantAllowance, - RemainingConfigs, - SignTransaction, - CopyAndShare, -} - -export const Side = strEnum([ - 'receive', - 'deposit', -]); -export type Side = keyof typeof Side; - -export const BlockchainErrs = strEnum([ - 'A_CONTRACT_NOT_DEPLOYED_ON_NETWORK', - 'DISCONNECTED_FROM_ETHEREUM_NODE', - 'UNHANDLED_ERROR', -]); -export type BlockchainErrs = keyof typeof BlockchainErrs; - -export const Direction = strEnum([ - 'forward', - 'backward', -]); -export type Direction = keyof typeof Direction; +export enum Side { + Receive = 'RECEIVE', + Deposit = 'DEPOSIT', +} export interface Token { iconUrl?: string; @@ -135,53 +104,50 @@ export enum BalanceErrs { faucetRequestFailed, faucetQueueIsFull, mintingFailed, - wethConversionFailed, sendFailed, allowanceSettingFailed, } -export const ActionTypes = strEnum([ +export enum ActionTypes { // Portal - 'UPDATE_SCREEN_WIDTH', - 'UPDATE_NODE_VERSION', - 'RESET_STATE', - 'ADD_TOKEN_TO_TOKEN_BY_ADDRESS', - 'BLOCKCHAIN_ERR_ENCOUNTERED', - 'CLEAR_TOKEN_BY_ADDRESS', - 'UPDATE_BLOCKCHAIN_IS_LOADED', - 'UPDATE_NETWORK_ID', - 'UPDATE_GENERATE_ORDER_STEP', - 'UPDATE_CHOSEN_ASSET_TOKEN', - 'UPDATE_CHOSEN_ASSET_TOKEN_ADDRESS', - 'UPDATE_ORDER_TAKER_ADDRESS', - 'UPDATE_ORDER_SALT', - 'UPDATE_ORDER_SIGNATURE_DATA', - 'UPDATE_TOKEN_BY_ADDRESS', - 'REMOVE_TOKEN_TO_TOKEN_BY_ADDRESS', - 'UPDATE_TOKEN_STATE_BY_ADDRESS', - 'REMOVE_FROM_TOKEN_STATE_BY_ADDRESS', - 'REPLACE_TOKEN_ALLOWANCE_BY_ADDRESS', - 'REPLACE_TOKEN_BALANCE_BY_ADDRESS', - 'UPDATE_TOKEN_BALANCE_BY_ADDRESS', - 'UPDATE_ORDER_EXPIRY', - 'SWAP_ASSET_TOKENS', - 'UPDATE_USER_ADDRESS', - 'UPDATE_USER_ETHER_BALANCE', - 'UPDATE_USER_SUPPLIED_ORDER_CACHE', - 'UPDATE_ORDER_FILL_AMOUNT', - 'UPDATE_SHOULD_BLOCKCHAIN_ERR_DIALOG_BE_OPEN', + UpdateScreenWidth = 'UPDATE_SCREEN_WIDTH', + UpdateNodeVersion = 'UPDATE_NODE_VERSION', + ResetState = 'RESET_STATE', + AddTokenToTokenByAddress = 'ADD_TOKEN_TO_TOKEN_BY_ADDRESS', + BlockchainErrEncountered = 'BLOCKCHAIN_ERR_ENCOUNTERED', + ClearTokenByAddress = 'CLEAR_TOKEN_BY_ADDRESS', + UpdateBlockchainIsLoaded = 'UPDATE_BLOCKCHAIN_IS_LOADED', + UpdateNetworkId = 'UPDATE_NETWORK_ID', + UpdateChosenAssetToken = 'UPDATE_CHOSEN_ASSET_TOKEN', + UpdateChosenAssetTokenAddress = 'UPDATE_CHOSEN_ASSET_TOKEN_ADDRESS', + UpdateOrderTakerAddress = 'UPDATE_ORDER_TAKER_ADDRESS', + UpdateOrderSalt = 'UPDATE_ORDER_SALT', + UpdateOrderSignatureData = 'UPDATE_ORDER_SIGNATURE_DATA', + UpdateTokenByAddress = 'UPDATE_TOKEN_BY_ADDRESS', + RemoveTokenFromTokenByAddress = 'REMOVE_TOKEN_FROM_TOKEN_BY_ADDRESS', + UpdateTokenStateByAddress = 'UPDATE_TOKEN_STATE_BY_ADDRESS', + RemoveFromTokenStateByAddress = 'REMOVE_FROM_TOKEN_STATE_BY_ADDRESS', + ReplaceTokenAllowanceByAddress = 'REPLACE_TOKEN_ALLOWANCE_BY_ADDRESS', + ReplaceTokenBalanceByAddress = 'REPLACE_TOKEN_BALANCE_BY_ADDRESS', + UpdateTokenBalanceByAddress = 'UPDATE_TOKEN_BALANCE_BY_ADDRESS', + UpdateOrderExpiry = 'UPDATE_ORDER_EXPIRY', + SwapAssetTokens = 'SWAP_ASSET_TOKENS', + UpdateUserAddress = 'UPDATE_USER_ADDRESS', + UpdateUserEtherBalance = 'UPDATE_USER_ETHER_BALANCE', + UpdateUserSuppliedOrderCache = 'UPDATE_USER_SUPPLIED_ORDER_CACHE', + UpdateOrderFillAmount = 'UPDATE_ORDER_FILL_AMOUNT', + UpdateShouldBlockchainErrDialogBeOpen = 'UPDATE_SHOULD_BLOCKCHAIN_ERR_DIALOG_BE_OPEN', // Docs - 'UPDATE_LIBRARY_VERSION', - 'UPDATE_AVAILABLE_LIBRARY_VERSIONS', + UpdateLibraryVersion = 'UPDATE_LIBRARY_VERSION', + UpdateAvailableLibraryVersions = 'UPDATE_AVAILABLE_LIBRARY_VERSIONS', // Shared - 'SHOW_FLASH_MESSAGE', - 'HIDE_FLASH_MESSAGE', - 'UPDATE_PROVIDER_TYPE', - 'UPDATE_INJECTED_PROVIDER_NAME', -]); -export type ActionTypes = keyof typeof ActionTypes; + ShowFlashMessage = 'SHOW_FLASH_MESSAGE', + HideFlashMessage = 'HIDE_FLASH_MESSAGE', + UpdateProviderType = 'UPDATE_PROVIDER_TYPE', + UpdateInjectedProviderName = 'UPDATE_INJECTED_PROVIDER_NAME', +} export interface Action { type: ActionTypes; @@ -189,7 +155,11 @@ export interface Action { } export interface TrackedTokensByNetworkId { - [networkId: number]: Token; + [networkId: number]: Token[]; +} + +export interface TrackedTokensByUserAddress { + [userAddress: string]: TrackedTokensByNetworkId; } export interface Styles { @@ -254,44 +224,47 @@ export interface ContractEvent { export type InputErrMsg = React.ReactNode | string | undefined; export type ValidatedBigNumberCallback = (isValid: boolean, amount?: BigNumber) => void; -export const ScreenWidths = strEnum([ - 'SM', - 'MD', - 'LG', -]); -export type ScreenWidths = keyof typeof ScreenWidths; +export enum ScreenWidths { + Sm = 'SM', + Md = 'MD', + Lg = 'LG', +} export enum AlertTypes { ERROR, SUCCESS, } -export const EtherscanLinkSuffixes = strEnum([ - 'address', - 'tx', -]); -export type EtherscanLinkSuffixes = keyof typeof EtherscanLinkSuffixes; - -export const BlockchainCallErrs = strEnum([ - 'CONTRACT_DOES_NOT_EXIST', - 'USER_HAS_NO_ASSOCIATED_ADDRESSES', - 'UNHANDLED_ERROR', - 'TOKEN_ADDRESS_IS_INVALID', - 'INVALID_SIGNATURE', -]); -export type BlockchainCallErrs = keyof typeof BlockchainCallErrs; - -export const KindString = strEnum([ - 'Constructor', - 'Property', - 'Method', - 'Interface', - 'Type alias', - 'Variable', - 'Function', - 'Enumeration', -]); -export type KindString = keyof typeof KindString; +export enum EtherscanLinkSuffixes { + Address = 'address', + Tx = 'tx', +} + +export enum BlockchainErrs { + AContractNotDeployedOnNetwork = 'A_CONTRACT_NOT_DEPLOYED_ON_NETWORK', + DisconnectedFromEthereumNode = 'DISCONNECTED_FROM_ETHEREUM_NODE', + NoError = 'NO_ERROR', +} + +export enum BlockchainCallErrs { + ContractDoesNotExist = 'CONTRACT_DOES_NOT_EXIST', + UserHasNoAssociatedAddresses = 'USER_HAS_NO_ASSOCIATED_ADDRESSES', + UnhandledError = 'UNHANDLED_ERROR', + TokenAddressIsInvalid = 'TOKEN_ADDRESS_IS_INVALID', +} + +// Exception: We don't make the values uppercase because these KindString's need to +// match up those returned by TypeDoc +export enum KindString { + Constructor = 'Constructor', + Property = 'Property', + Method = 'Method', + Interface = 'Interface', + TypeAlias = 'Type alias', + Variable = 'Variable', + Function = 'Function', + Enumeration = 'Enumeration', +} export interface EnumValue { name: string; @@ -367,8 +340,8 @@ export interface DocAgnosticFormat { export interface DocSection { comment: string; - constructors: Array<TypescriptMethod|SolidityMethod>; - methods: Array<TypescriptMethod|SolidityMethod>; + constructors: Array<TypescriptMethod | SolidityMethod>; + methods: Array<TypescriptMethod | SolidityMethod>; properties: Property[]; types: CustomType[]; events?: Event[]; @@ -395,7 +368,7 @@ export interface Property { export interface BaseMethod { isConstructor: boolean; name: string; - returnComment?: string|undefined; + returnComment?: string | undefined; callPath: string; parameters: Parameter[]; returnType: Type; @@ -487,11 +460,10 @@ export interface MenuSubsectionsBySection { [section: string]: string[]; } -export const ProviderType = strEnum([ - 'INJECTED', - 'LEDGER', -]); -export type ProviderType = keyof typeof ProviderType; +export enum ProviderType { + Injected = 'INJECTED', + Ledger = 'LEDGER', +} export interface Fact { title: string; @@ -511,8 +483,11 @@ interface LedgerCommunication { close_async: () => Promise<void>; } export interface LedgerEthConnection { - getAddress_async: (derivationPath: string, askForDeviceConfirmation: boolean, - shouldGetChainCode: boolean) => Promise<LedgerGetAddressResult>; + getAddress_async: ( + derivationPath: string, + askForDeviceConfirmation: boolean, + shouldGetChainCode: boolean, + ) => Promise<LedgerGetAddressResult>; signPersonalMessage_async: (derivationPath: string, messageHex: string) => Promise<LedgerSignResult>; signTransaction_async: (derivationPath: string, txHex: string) => Promise<LedgerSignResult>; comm: LedgerCommunication; @@ -668,19 +643,39 @@ export interface SectionsMap { } export interface DocsInfoConfig { - displayName: string; - packageUrl: string; - websitePath: string; - docsJsonRoot: string; - menu: DocsMenu; - sections: SectionsMap; - sectionNameToMarkdown: {[sectionName: string]: string}; - visibleConstructors: string[]; - convertToDocAgnosticFormatFn: (docObj: DoxityDocObj|TypeDocNode, docsInfo?: any) => DocAgnosticFormat; - subPackageName?: string; - publicTypes?: string[]; - sectionNameToModulePath?: {[sectionName: string]: string[]}; - menuSubsectionToVersionWhenIntroduced?: {[sectionName: string]: string}; + displayName: string; + packageUrl: string; + websitePath: string; + docsJsonRoot: string; + menu: DocsMenu; + sections: SectionsMap; + sectionNameToMarkdown: { [sectionName: string]: string }; + visibleConstructors: string[]; + convertToDocAgnosticFormatFn: (docObj: DoxityDocObj | TypeDocNode, docsInfo?: any) => DocAgnosticFormat; + subPackageName?: string; + publicTypes?: string[]; + sectionNameToModulePath?: { [sectionName: string]: string[] }; + menuSubsectionToVersionWhenIntroduced?: { [sectionName: string]: string }; +} + +export interface TimestampMsRange { + startTimestampMs: number; + endTimestampMs: number; +} + +export interface OutdatedWrappedEtherByNetworkId { + [networkId: number]: { + address: string; + timestampMsRange: TimestampMsRange; + }; +} + +export enum SmartContractDocSections { + Introduction = 'Introduction', + Exchange = 'Exchange', + TokenTransferProxy = 'TokenTransferProxy', + TokenRegistry = 'TokenRegistry', + ZRXToken = 'ZRXToken', } // tslint:disable:max-file-line-count diff --git a/packages/website/ts/utils/colors.ts b/packages/website/ts/utils/colors.ts new file mode 100644 index 000000000..58ce667e3 --- /dev/null +++ b/packages/website/ts/utils/colors.ts @@ -0,0 +1,43 @@ +import { colors as materialUiColors } from 'material-ui/styles'; + +export const colors = { + ...materialUiColors, + grey50: '#FAFAFA', + grey100: '#F5F5F5', + lightestGrey: '#F0F0F0', + greyishPink: '#E6E5E5', + grey300: '#E0E0E0', + beigeWhite: '#E4E4E4', + grey400: '#BDBDBD', + lightGrey: '#BBBBBB', + grey500: '#9E9E9E', + grey: '#A5A5A5', + darkGrey: '#818181', + landingLinkGrey: '#919191', + grey700: '#616161', + grey800: '#424242', + darkerGrey: '#393939', + heroGrey: '#404040', + projectsGrey: '#343333', + darkestGrey: '#272727', + dharmaDarkGrey: '#252525', + lightBlue: '#60A4F4', + lightBlueA700: '#0091EA', + darkBlue: '#4D5481', + turquois: '#058789', + lightPurple: '#A81CA6', + purple: '#690596', + red200: '#EF9A9A', + red: '#E91751', + red500: '#F44336', + red600: '#E53935', + limeGreen: '#66DE75', + lightGreen: '#4DC55C', + lightestGreen: '#89C774', + brightGreen: '#00C33E', + green400: '#66BB6A', + green: '#4DA24B', + amber600: '#FFB300', + orange: '#E69D00', + amber800: '#FF8F00', +}; diff --git a/packages/website/ts/utils/configs.ts b/packages/website/ts/utils/configs.ts index 63fcd27b6..3d37a89ab 100644 --- a/packages/website/ts/utils/configs.ts +++ b/packages/website/ts/utils/configs.ts @@ -1,18 +1,126 @@ import * as _ from 'lodash'; -import {Environments} from 'ts/types'; +import { + ContractAddresses, + Environments, + Networks, + OutdatedWrappedEtherByNetworkId, + PublicNodeUrlsByNetworkId, + SmartContractDocSections, +} from 'ts/types'; const BASE_URL = window.location.origin; -const isDevelopment = _.includes(BASE_URL, 'https://0xproject.dev:3572') || - _.includes(BASE_URL, 'https://localhost:3572') || - _.includes(BASE_URL, 'https://127.0.0.1'); +const isDevelopment = _.includes( + ['https://0xproject.localhost:3572', 'https://localhost:3572', 'https://127.0.0.1'], + BASE_URL, +); +const INFURA_API_KEY = 'T5WSC8cautR4KXyYgsRs'; export const configs = { - BASE_URL, - ENVIRONMENT: isDevelopment ? Environments.DEVELOPMENT : Environments.PRODUCTION, BACKEND_BASE_URL: isDevelopment ? 'https://localhost:3001' : 'https://website-api.0xproject.com', - symbolsOfMintableTokens: ['MKR', 'MLN', 'GNT', 'DGD', 'REP'], + BASE_URL, + BITLY_ACCESS_TOKEN: 'ffc4c1a31e5143848fb7c523b39f91b9b213d208', + CONTRACT_ADDRESS: { + '1.0.0': { + [Networks.mainnet]: { + [SmartContractDocSections.Exchange]: '0x12459c951127e0c374ff9105dda097662a027093', + [SmartContractDocSections.TokenTransferProxy]: '0x8da0d80f5007ef1e431dd2127178d224e32c2ef4', + [SmartContractDocSections.ZRXToken]: '0xe41d2489571d322189246dafa5ebde1f4699f498', + [SmartContractDocSections.TokenRegistry]: '0x926a74c5c36adf004c87399e65f75628b0f98d2c', + }, + [Networks.ropsten]: { + [SmartContractDocSections.Exchange]: '0x479cc461fecd078f766ecc58533d6f69580cf3ac', + [SmartContractDocSections.TokenTransferProxy]: '0x4e9aad8184de8833365fea970cd9149372fdf1e6', + [SmartContractDocSections.ZRXToken]: '0xa8e9fa8f91e5ae138c74648c9c304f1c75003a8d', + [SmartContractDocSections.TokenRegistry]: '0x6b1a50f0bb5a7995444bd3877b22dc89c62843ed', + }, + [Networks.kovan]: { + [SmartContractDocSections.Exchange]: '0x90fe2af704b34e0224bf2299c838e04d4dcf1364', + [SmartContractDocSections.TokenTransferProxy]: '0x087Eed4Bc1ee3DE49BeFbd66C662B434B15d49d4', + [SmartContractDocSections.ZRXToken]: '0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570', + [SmartContractDocSections.TokenRegistry]: '0xf18e504561f4347bea557f3d4558f559dddbae7f', + }, + }, + } as ContractAddresses, + DEFAULT_DERIVATION_PATH: `44'/60'/0'`, // WARNING: ZRX & WETH MUST always be default trackedTokens - defaultTrackedTokenSymbols: ['WETH', 'ZRX'], - lastLocalStorageFillClearanceDate: '2017-11-22', - isMainnetEnabled: true, + DEFAULT_TRACKED_TOKEN_SYMBOLS: ['WETH', 'ZRX'], + DOMAIN_STAGING: 'staging-0xproject.s3-website-us-east-1.amazonaws.com', + DOMAIN_DEVELOPMENT: '0xproject.localhost:3572', + DOMAIN_PRODUCTION: '0xproject.com', + ENVIRONMENT: isDevelopment ? Environments.DEVELOPMENT : Environments.PRODUCTION, + ICON_URL_BY_SYMBOL: { + REP: '/images/token_icons/augur.png', + DGD: '/images/token_icons/digixdao.png', + WETH: '/images/token_icons/ether_erc20.png', + MLN: '/images/token_icons/melon.png', + GNT: '/images/token_icons/golem.png', + MKR: '/images/token_icons/makerdao.png', + ZRX: '/images/token_icons/zero_ex.png', + ANT: '/images/token_icons/aragon.png', + BNT: '/images/token_icons/bancor.png', + BAT: '/images/token_icons/basicattentiontoken.png', + CVC: '/images/token_icons/civic.png', + EOS: '/images/token_icons/eos.png', + FUN: '/images/token_icons/funfair.png', + GNO: '/images/token_icons/gnosis.png', + ICN: '/images/token_icons/iconomi.png', + OMG: '/images/token_icons/omisego.png', + SNT: '/images/token_icons/status.png', + STORJ: '/images/token_icons/storjcoinx.png', + PAY: '/images/token_icons/tenx.png', + QTUM: '/images/token_icons/qtum.png', + DNT: '/images/token_icons/district0x.png', + SNGLS: '/images/token_icons/singularity.png', + EDG: '/images/token_icons/edgeless.png', + '1ST': '/images/token_icons/firstblood.jpg', + WINGS: '/images/token_icons/wings.png', + BQX: '/images/token_icons/bitquence.png', + LUN: '/images/token_icons/lunyr.png', + RLC: '/images/token_icons/iexec.png', + MCO: '/images/token_icons/monaco.png', + ADT: '/images/token_icons/adtoken.png', + CFI: '/images/token_icons/cofound-it.png', + ROL: '/images/token_icons/etheroll.png', + WGNT: '/images/token_icons/golem.png', + MTL: '/images/token_icons/metal.png', + NMR: '/images/token_icons/numeraire.png', + SAN: '/images/token_icons/santiment.png', + TAAS: '/images/token_icons/taas.png', + TKN: '/images/token_icons/tokencard.png', + TRST: '/images/token_icons/trust.png', + } as { [symbol: string]: string }, + IS_MAINNET_ENABLED: true, + LAST_LOCAL_STORAGE_FILL_CLEARANCE_DATE: '2017-11-22', + LAST_LOCAL_STORAGE_TRACKED_TOKEN_CLEARANCE_DATE: '2017-12-19', + // NEW_WRAPPED_ETHERS is temporary until we remove the SHOULD_DEPRECATE_OLD_WETH_TOKEN flag + // and add the new WETHs to the tokenRegistry + NEW_WRAPPED_ETHERS: { + 1: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + 42: '0xd0a1e359811322d97991e03f863a0c30c2cf029c', + } as { [networkId: string]: string }, + OUTDATED_WRAPPED_ETHERS: [ + { + 42: { + address: '0x05d090b51c40b020eab3bfcb6a2dff130df22e9c', + timestampMsRange: { + startTimestampMs: 1502455607000, + endTimestampMs: 1513790926000, + }, + }, + 1: { + address: '0x2956356cd2a2bf3202f771f50d3d14a367b48070', + timestampMsRange: { + startTimestampMs: 1502455607000, + endTimestampMs: 1513790926000, + }, + }, + }, + ] as OutdatedWrappedEtherByNetworkId[], + // The order matters. We first try first node and only then fall back to others. + PUBLIC_NODE_URLS_BY_NETWORK_ID: { + [1]: [`https://mainnet.infura.io/${INFURA_API_KEY}`, 'https://mainnet.0xproject.com'], + [42]: [`https://kovan.infura.io/${INFURA_API_KEY}`, 'https://kovan.0xproject.com'], + } as PublicNodeUrlsByNetworkId, + SHOULD_DEPRECATE_OLD_WETH_TOKEN: true, + SYMBOLS_OF_MINTABLE_TOKENS: ['MKR', 'MLN', 'GNT', 'DGD', 'REP'], }; diff --git a/packages/website/ts/utils/constants.ts b/packages/website/ts/utils/constants.ts index cae59af5f..dded82114 100644 --- a/packages/website/ts/utils/constants.ts +++ b/packages/website/ts/utils/constants.ts @@ -1,189 +1,87 @@ -import BigNumber from 'bignumber.js'; -import { - ContractAddresses, - Docs, - ExchangeContractErrs, - Networks, - PublicNodeUrlsByNetworkId, - WebsitePaths, -} from 'ts/types'; - -const INFURA_API_KEY = 'T5WSC8cautR4KXyYgsRs'; -const smartContractDocSections = { - Introduction: 'Introduction', - Exchange: 'Exchange', - TokenTransferProxy: 'TokenTransferProxy', - TokenRegistry: 'TokenRegistry', - ZRXToken: 'ZRXToken', - EtherToken: 'EtherToken', -}; +import { BigNumber } from '@0xproject/utils'; +import { Networks } from 'ts/types'; export const constants = { - ANGELLIST_URL: 'https://angel.co/0xproject/jobs', - STAGING_DOMAIN: 'staging-0xproject.s3-website-us-east-1.amazonaws.com', - PRODUCTION_DOMAIN: '0xproject.com', - DEVELOPMENT_DOMAIN: '0xproject.dev:3572', - BIGNUMBERJS_GITHUB_URL: 'http://mikemcl.github.io/bignumber.js', - BITLY_ACCESS_TOKEN: 'ffc4c1a31e5143848fb7c523b39f91b9b213d208', - BITLY_ENDPOINT: 'https://api-ssl.bitly.com', - BLOG_URL: 'https://blog.0xproject.com/latest', - CUSTOM_BLUE: '#60a4f4', - DEFAULT_DERIVATION_PATH: `44'/60'/0'`, - ETHER_FAUCET_ENDPOINT: 'https://faucet.0xproject.com', - FEE_RECIPIENT_ADDRESS: '0x0000000000000000000000000000000000000000', - FIREFOX_U2F_ADDON: 'https://addons.mozilla.org/en-US/firefox/addon/u2f-support-add-on/', - GITHUB_URL: 'https://github.com/0xProject', - GITHUB_WIKI_URL: 'https://github.com/0xProject/wiki', - HTTP_NO_CONTENT_STATUS_CODE: 204, - ACCEPT_DISCLAIMER_LOCAL_STORAGE_KEY: 'didAcceptPortalDisclaimer', - LINKEDIN_0X_URL: 'https://www.linkedin.com/company/0x', - LEDGER_PROVIDER_NAME: 'Ledger', - METAMASK_PROVIDER_NAME: 'Metamask', + DECIMAL_PLACES_ETH: 18, + DECIMAL_PLACES_ZRX: 18, + DOCS_SCROLL_DURATION_MS: 0, + DOCS_CONTAINER_ID: 'documentation', GENESIS_ORDER_BLOCK_BY_NETWORK_ID: { 1: 4145578, 42: 3117574, 50: 0, - } as {[networkId: number]: number}, - PUBLIC_PROVIDER_NAME: '0x Public', - // The order matters. We first try first node and only then fall back to others. - PUBLIC_NODE_URLS_BY_NETWORK_ID: { - [1]: [ - `https://mainnet.infura.io/${INFURA_API_KEY}`, - ], - [42]: [ - `https://kovan.infura.io/${INFURA_API_KEY}`, - ], - } as PublicNodeUrlsByNetworkId, - PARITY_SIGNER_PROVIDER_NAME: 'Parity Signer', - GENERIC_PROVIDER_NAME: 'Injected Web3', + } as { [networkId: number]: number }, + HOME_SCROLL_DURATION_MS: 500, + HTTP_NO_CONTENT_STATUS_CODE: 204, + LOCAL_STORAGE_KEY_ACCEPT_DISCLAIMER: 'didAcceptPortalDisclaimer', + LOCAL_STORAGE_KEY_DISMISS_WETH_NOTICE: 'hasDismissedWethNotice', MAKER_FEE: new BigNumber(0), MAINNET_NAME: 'Main network', - MAINNET_NETWORK_ID: 1, - METAMASK_CHROME_STORE_URL: 'https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn', - // tslint:disable-next-line:max-line-length - PARITY_CHROME_STORE_URL: 'https://chrome.google.com/webstore/detail/parity-ethereum-integrati/himekenlppkgeaoeddcliojfddemadig', - MIST_DOWNLOAD_URL: 'https://github.com/ethereum/mist/releases', - NULL_ADDRESS: '0x0000000000000000000000000000000000000000', - ROLLBAR_ACCESS_TOKEN: 'a6619002b51c4464928201e6ea94de65', - DOCS_SCROLL_DURATION_MS: 0, - DOCS_CONTAINER_ID: 'documentation', - HOME_SCROLL_DURATION_MS: 500, - REDDIT_URL: 'https://reddit.com/r/0xproject', - STANDARD_RELAYER_API_GITHUB: 'https://github.com/0xProject/standard-relayer-api/blob/master/README.md', - SUCCESS_STATUS: 200, - UNAVAILABLE_STATUS: 503, - TAKER_FEE: new BigNumber(0), - TESTNET_NAME: 'Kovan', - TESTNET_NETWORK_ID: 42, - TESTRPC_NETWORK_ID: 50, - TWITTER_URL: 'https://twitter.com/0xproject', - ETH_DECIMAL_PLACES: 18, MINT_AMOUNT: new BigNumber('100000000000000000000'), - WEB3_DOCS_URL: 'https://github.com/ethereum/wiki/wiki/JavaScript-API', - WEB3_PROVIDER_DOCS_URL: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L150', - WEB3_DECODED_LOG_ENTRY_EVENT_URL: - 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L123', - WEB3_LOG_ENTRY_EVENT_URL: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L127', - ZEROEX_CHAT_URL: 'https://chat.0xproject.com', - // Projects - ETHFINEX_URL: 'https://www.bitfinex.com/ethfinex', - RADAR_RELAY_URL: 'https://radarrelay.com', - PARADEX_URL: 'https://paradex.io', - DYDX_URL: 'https://dydx.exchange', - MELONPORT_URL: 'https://melonport.com', - DISTRICT_0X_URL: 'https://district0x.io', - DHARMA_URL: 'https://dharma.io', - LENDROID_URL: 'https://lendroid.com', - MAKER_URL: 'https://makerdao.com', - ARAGON_URL: 'https://aragon.one', - BLOCKNET_URL: 'https://blocknet.co', - OCEAN_URL: 'http://the0cean.com', - STATUS_URL: 'https://status.im', - AUGUR_URL: 'https://augur.net', - AUCTUS_URL: 'https://auctus.org', - OPEN_ANX_URL: 'https://www.openanx.org', - - iconUrlBySymbol: { - 'REP': '/images/token_icons/augur.png', - 'DGD': '/images/token_icons/digixdao.png', - 'WETH': '/images/token_icons/ether_erc20.png', - 'MLN': '/images/token_icons/melon.png', - 'GNT': '/images/token_icons/golem.png', - 'MKR': '/images/token_icons/makerdao.png', - 'ZRX': '/images/token_icons/zero_ex.png', - 'ANT': '/images/token_icons/aragon.png', - 'BNT': '/images/token_icons/bancor.png', - 'BAT': '/images/token_icons/basicattentiontoken.png', - 'CVC': '/images/token_icons/civic.png', - 'EOS': '/images/token_icons/eos.png', - 'FUN': '/images/token_icons/funfair.png', - 'GNO': '/images/token_icons/gnosis.png', - 'ICN': '/images/token_icons/iconomi.png', - 'OMG': '/images/token_icons/omisego.png', - 'SNT': '/images/token_icons/status.png', - 'STORJ': '/images/token_icons/storjcoinx.png', - 'PAY': '/images/token_icons/tenx.png', - 'QTUM': '/images/token_icons/qtum.png', - 'DNT': '/images/token_icons/district0x.png', - 'SNGLS': '/images/token_icons/singularity.png', - 'EDG': '/images/token_icons/edgeless.png', - '1ST': '/images/token_icons/firstblood.jpg', - 'WINGS': '/images/token_icons/wings.png', - 'BQX': '/images/token_icons/bitquence.png', - 'LUN': '/images/token_icons/lunyr.png', - 'RLC': '/images/token_icons/iexec.png', - 'MCO': '/images/token_icons/monaco.png', - 'ADT': '/images/token_icons/adtoken.png', - 'CFI': '/images/token_icons/cofound-it.png', - 'ROL': '/images/token_icons/etheroll.png', - 'WGNT': '/images/token_icons/golem.png', - 'MTL': '/images/token_icons/metal.png', - 'NMR': '/images/token_icons/numeraire.png', - 'SAN': '/images/token_icons/santiment.png', - 'TAAS': '/images/token_icons/taas.png', - 'TKN': '/images/token_icons/tokencard.png', - 'TRST': '/images/token_icons/trust.png', - } as {[symbol: string]: string}, - networkNameById: { + NETWORK_ID_MAINNET: 1, + NETWORK_ID_TESTNET: 42, + NETWORK_ID_TESTRPC: 50, + NETWORK_NAME_BY_ID: { 1: Networks.mainnet, 3: Networks.ropsten, 4: Networks.rinkeby, 42: Networks.kovan, - } as {[symbol: number]: string}, - networkIdByName: { + } as { [symbol: number]: string }, + NETWORK_ID_BY_NAME: { [Networks.mainnet]: 1, [Networks.ropsten]: 3, [Networks.rinkeby]: 4, [Networks.kovan]: 42, - } as {[networkName: string]: number}, - docToPath: { - [Docs.ZeroExJs]: WebsitePaths.ZeroExJs, - [Docs.SmartContracts]: WebsitePaths.SmartContracts, - }, - smartContractDocSections, - contractAddresses: { - '1.0.0': { - [Networks.mainnet]: { - [smartContractDocSections.Exchange]: '0x12459c951127e0c374ff9105dda097662a027093', - [smartContractDocSections.TokenTransferProxy]: '0x8da0d80f5007ef1e431dd2127178d224e32c2ef4', - [smartContractDocSections.ZRXToken]: '0xe41d2489571d322189246dafa5ebde1f4699f498', - [smartContractDocSections.EtherToken]: '0x2956356cd2a2bf3202f771f50d3d14a367b48070', - [smartContractDocSections.TokenRegistry]: '0x926a74c5c36adf004c87399e65f75628b0f98d2c', - }, - [Networks.ropsten]: { - [smartContractDocSections.Exchange]: '0x479cc461fecd078f766ecc58533d6f69580cf3ac', - [smartContractDocSections.TokenTransferProxy]: '0x4e9aad8184de8833365fea970cd9149372fdf1e6', - [smartContractDocSections.ZRXToken]: '0xa8e9fa8f91e5ae138c74648c9c304f1c75003a8d', - [smartContractDocSections.EtherToken]: '0xc00fd9820cd2898cc4c054b7bf142de637ad129a', - [smartContractDocSections.TokenRegistry]: '0x6b1a50f0bb5a7995444bd3877b22dc89c62843ed', - }, - [Networks.kovan]: { - [smartContractDocSections.Exchange]: '0x90fe2af704b34e0224bf2299c838e04d4dcf1364', - [smartContractDocSections.TokenTransferProxy]: '0x087Eed4Bc1ee3DE49BeFbd66C662B434B15d49d4', - [smartContractDocSections.ZRXToken]: '0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570', - [smartContractDocSections.EtherToken]: '0x05d090b51c40b020eab3bfcb6a2dff130df22e9c', - [smartContractDocSections.TokenRegistry]: '0xf18e504561f4347bea557f3d4558f559dddbae7f', - }, - }, - } as ContractAddresses, + } as { [networkName: string]: number }, + NULL_ADDRESS: '0x0000000000000000000000000000000000000000', + PROVIDER_NAME_LEDGER: 'Ledger', + PROVIDER_NAME_METAMASK: 'Metamask', + PROVIDER_NAME_PARITY_SIGNER: 'Parity Signer', + PROVIDER_NAME_GENERIC: 'Injected Web3', + PROVIDER_NAME_PUBLIC: '0x Public', + ROLLBAR_ACCESS_TOKEN: 'a6619002b51c4464928201e6ea94de65', + SUCCESS_STATUS: 200, + UNAVAILABLE_STATUS: 503, + TAKER_FEE: new BigNumber(0), + TESTNET_NAME: 'Kovan', + TYPES_SECTION_NAME: 'types', + PROJECT_URL_ETHFINEX: 'https://www.bitfinex.com/ethfinex', + PROJECT_URL_RADAR_RELAY: 'https://radarrelay.com', + PROJECT_URL_PARADEX: 'https://paradex.io', + PROJECT_URL_DYDX: 'https://dydx.exchange', + PROJECT_URL_MELONPORT: 'https://melonport.com', + PROJECT_URL_DISTRICT_0X: 'https://district0x.io', + PROJECT_URL_DHARMA: 'https://dharma.io', + PROJECT_URL_LENDROID: 'https://lendroid.com', + PROJECT_URL_MAKER: 'https://makerdao.com', + PROJECT_URL_ARAGON: 'https://aragon.one', + PROJECT_URL_BLOCKNET: 'https://blocknet.co', + PROJECT_URL_0CEAN: 'http://the0cean.com', + PROJECT_URL_STATUS: 'https://status.im', + PROJECT_URL_AUGUR: 'https://augur.net', + PROJECT_URL_AUCTUS: 'https://auctus.org', + PROJECT_URL_OPEN_ANX: 'https://www.openanx.org', + URL_ANGELLIST: 'https://angel.co/0xproject/jobs', + URL_BIGNUMBERJS_GITHUB: 'http://mikemcl.github.io/bignumber.js', + URL_BITLY_API: 'https://api-ssl.bitly.com', + URL_BLOG: 'https://blog.0xproject.com/latest', + URL_DISCOURSE_FORUM: 'https://forum.0xproject.com', + URL_FIREFOX_U2F_ADDON: 'https://addons.mozilla.org/en-US/firefox/addon/u2f-support-add-on/', + URL_ETHER_FAUCET: 'https://faucet.0xproject.com', + URL_GITHUB_ORG: 'https://github.com/0xProject', + URL_GITHUB_WIKI: 'https://github.com/0xProject/wiki', + URL_METAMASK_CHROME_STORE: 'https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn', + URL_MIST_DOWNLOAD: 'https://github.com/ethereum/mist/releases', + URL_PARITY_CHROME_STORE: + 'https://chrome.google.com/webstore/detail/parity-ethereum-integrati/himekenlppkgeaoeddcliojfddemadig', + URL_REDDIT: 'https://reddit.com/r/0xproject', + URL_STANDARD_RELAYER_API_GITHUB: 'https://github.com/0xProject/standard-relayer-api/blob/master/README.md', + URL_TWITTER: 'https://twitter.com/0xproject', + URL_WEB3_DOCS: 'https://github.com/ethereum/wiki/wiki/JavaScript-API', + URL_WEB3_DECODED_LOG_ENTRY_EVENT: + 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L123', + URL_WEB3_LOG_ENTRY_EVENT: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L127', + URL_WEB3_PROVIDER_DOCS: 'https://github.com/0xProject/web3-typescript-typings/blob/f5bcb96/index.d.ts#L150', + URL_WETH_IO: 'https://weth.io/', + URL_ZEROEX_CHAT: 'https://chat.0xproject.com', }; diff --git a/packages/website/ts/utils/doc_utils.ts b/packages/website/ts/utils/doc_utils.ts index 594e3bae6..1f5f75ee2 100644 --- a/packages/website/ts/utils/doc_utils.ts +++ b/packages/website/ts/utils/doc_utils.ts @@ -1,13 +1,11 @@ import findVersions = require('find-versions'); import * as _ from 'lodash'; -import {DoxityDocObj, S3FileObject, TypeDocNode, VersionToFileName} from 'ts/types'; -import {constants} from 'ts/utils/constants'; -import {utils} from 'ts/utils/utils'; +import { DoxityDocObj, S3FileObject, TypeDocNode, VersionToFileName } from 'ts/types'; +import { utils } from 'ts/utils/utils'; import convert = require('xml-js'); export const docUtils = { - async getVersionToFileNameAsync(s3DocJsonRoot: string): - Promise<VersionToFileName> { + async getVersionToFileNameAsync(s3DocJsonRoot: string): Promise<VersionToFileName> { const versionFileNames = await this.getVersionFileNamesAsync(s3DocJsonRoot); const versionToFileName: VersionToFileName = {}; _.each(versionFileNames, fileName => { @@ -22,30 +20,30 @@ export const docUtils = { // TODO: Show the user an error message when the docs fail to load const errMsg = await response.text(); utils.consoleLog(`Failed to load JSON file list: ${response.status} ${errMsg}`); - return; + throw new Error(errMsg); } const responseXML = await response.text(); const responseJSONString = convert.xml2json(responseXML, { compact: true, }); const responseObj = JSON.parse(responseJSONString); - const fileObjs: S3FileObject[] = (_.isArray(responseObj.ListBucketResult.Contents)) ? - responseObj.ListBucketResult.Contents as S3FileObject[] : - [responseObj.ListBucketResult.Contents]; + const fileObjs: S3FileObject[] = _.isArray(responseObj.ListBucketResult.Contents) + ? (responseObj.ListBucketResult.Contents as S3FileObject[]) + : [responseObj.ListBucketResult.Contents]; const versionFileNames = _.map(fileObjs, fileObj => { return fileObj.Key._text; }); return versionFileNames; }, - async getJSONDocFileAsync(fileName: string, s3DocJsonRoot: string): Promise<TypeDocNode|DoxityDocObj> { + async getJSONDocFileAsync(fileName: string, s3DocJsonRoot: string): Promise<TypeDocNode | DoxityDocObj> { const endpoint = `${s3DocJsonRoot}/${fileName}`; const response = await fetch(endpoint); if (response.status !== 200) { // TODO: Show the user an error message when the docs fail to load const errMsg = await response.text(); utils.consoleLog(`Failed to load Doc JSON: ${response.status} ${errMsg}`); - return; + throw new Error(errMsg); } const jsonDocObj = await response.json(); return jsonDocObj; diff --git a/packages/website/ts/utils/doxity_utils.ts b/packages/website/ts/utils/doxity_utils.ts index 26e555b16..5f1d02132 100644 --- a/packages/website/ts/utils/doxity_utils.ts +++ b/packages/website/ts/utils/doxity_utils.ts @@ -36,41 +36,46 @@ export const doxityUtils = { constructors.push(constructor); } - const doxityMethods: DoxityAbiDoc[] = _.filter<DoxityAbiDoc> - (doxityContractObj.abiDocs, (abiDoc: DoxityAbiDoc) => { - return this._isMethod(abiDoc); - }); - const methods: SolidityMethod[] = _.map<DoxityAbiDoc, SolidityMethod>(doxityMethods, + const doxityMethods: DoxityAbiDoc[] = _.filter<DoxityAbiDoc>( + doxityContractObj.abiDocs, + (abiDoc: DoxityAbiDoc) => { + return this._isMethod(abiDoc); + }, + ); + const methods: SolidityMethod[] = _.map<DoxityAbiDoc, SolidityMethod>( + doxityMethods, (doxityMethod: DoxityAbiDoc) => { - // We assume that none of our functions returns more then a single value - const outputIfExists = !_.isUndefined(doxityMethod.outputs) ? - doxityMethod.outputs[0] : - undefined; - const returnTypeIfExists = !_.isUndefined(outputIfExists) ? - this._convertType(outputIfExists.type) : - undefined; - // For ZRXToken, we want to convert it to zrxToken, rather then simply zRXToken - const callPath = contractName !== 'ZRXToken' ? - `${contractName[0].toLowerCase()}${contractName.slice(1)}.` : - `${contractName.slice(0, 3).toLowerCase()}${contractName.slice(3)}.`; - const method = { - isConstructor: false, - isConstant: doxityMethod.constant, - isPayable: doxityMethod.payable, - name: doxityMethod.name, - comment: doxityMethod.details, - returnComment: doxityMethod.return, - callPath, - parameters: this._convertParameters(doxityMethod.inputs), - returnType: returnTypeIfExists, - }; - return method; - }); + // We assume that none of our functions returns more then a single value + const outputIfExists = !_.isUndefined(doxityMethod.outputs) ? doxityMethod.outputs[0] : undefined; + const returnTypeIfExists = !_.isUndefined(outputIfExists) + ? this._convertType(outputIfExists.type) + : undefined; + // For ZRXToken, we want to convert it to zrxToken, rather then simply zRXToken + const callPath = + contractName !== 'ZRXToken' + ? `${contractName[0].toLowerCase()}${contractName.slice(1)}.` + : `${contractName.slice(0, 3).toLowerCase()}${contractName.slice(3)}.`; + const method = { + isConstructor: false, + isConstant: doxityMethod.constant, + isPayable: doxityMethod.payable, + name: doxityMethod.name, + comment: doxityMethod.details, + returnComment: doxityMethod.return, + callPath, + parameters: this._convertParameters(doxityMethod.inputs), + returnType: returnTypeIfExists, + }; + return method; + }, + ); - const doxityProperties: DoxityAbiDoc[] = _.filter<DoxityAbiDoc> - (doxityContractObj.abiDocs, (abiDoc: DoxityAbiDoc) => { - return this._isProperty(abiDoc); - }); + const doxityProperties: DoxityAbiDoc[] = _.filter<DoxityAbiDoc>( + doxityContractObj.abiDocs, + (abiDoc: DoxityAbiDoc) => { + return this._isProperty(abiDoc); + }, + ); const properties = _.map<DoxityAbiDoc, Property>(doxityProperties, (doxityProperty: DoxityAbiDoc) => { // We assume that none of our functions return more then a single return value let typeName = doxityProperty.outputs[0].type; @@ -87,7 +92,8 @@ export const doxityUtils = { }); const doxityEvents = _.filter( - doxityContractObj.abiDocs, (abiDoc: DoxityAbiDoc) => abiDoc.type === AbiTypes.Event, + doxityContractObj.abiDocs, + (abiDoc: DoxityAbiDoc) => abiDoc.type === AbiTypes.Event, ); const events = _.map(doxityEvents, doxityEvent => { const event = { diff --git a/packages/website/ts/utils/error_reporter.ts b/packages/website/ts/utils/error_reporter.ts index 40991afbf..0bd247c5b 100644 --- a/packages/website/ts/utils/error_reporter.ts +++ b/packages/website/ts/utils/error_reporter.ts @@ -1,7 +1,7 @@ -import {Environments} from 'ts/types'; -import {configs} from 'ts/utils/configs'; -import {constants} from 'ts/utils/constants'; -import {utils} from 'ts/utils/utils'; +import { Environments } from 'ts/types'; +import { configs } from 'ts/utils/configs'; +import { constants } from 'ts/utils/constants'; +import { utils } from 'ts/utils/utils'; // Suggested way to include Rollbar with Webpack // https://github.com/rollbar/rollbar.js/tree/master/examples/webpack @@ -15,7 +15,7 @@ const rollbarConfig = { environment: configs.ENVIRONMENT, }, uncaughtErrorLevel: 'error', - hostWhiteList: [constants.PRODUCTION_DOMAIN, constants.STAGING_DOMAIN], + hostWhiteList: [configs.DOMAIN_PRODUCTION, configs.DOMAIN_STAGING], ignoredMessages: [ // Errors from the third-party scripts 'Script error', @@ -23,7 +23,7 @@ const rollbarConfig = { 'TypeError: Failed to fetch', 'Exchange has not been deployed to detected network (network/artifact mismatch)', // Source: https://groups.google.com/a/chromium.org/forum/#!topic/chromium-discuss/7VU0_VvC7mE - 'undefined is not an object (evaluating \'__gCrWeb.autofill.extractForms\')', + "undefined is not an object (evaluating '__gCrWeb.autofill.extractForms')", // Source: http://stackoverflow.com/questions/43399818/securityerror-from-facebook-and-cross-domain-messaging 'SecurityError (DOM Exception 18)', ], diff --git a/packages/website/ts/utils/mui_theme.ts b/packages/website/ts/utils/mui_theme.ts new file mode 100644 index 000000000..d73e80606 --- /dev/null +++ b/packages/website/ts/utils/mui_theme.ts @@ -0,0 +1,35 @@ +import { getMuiTheme } from 'material-ui/styles'; +import { colors } from 'ts/utils/colors'; + +export const muiTheme = getMuiTheme({ + appBar: { + height: 45, + color: colors.white, + textColor: colors.black, + }, + palette: { + pickerHeaderColor: colors.lightBlue, + primary1Color: colors.lightBlue, + primary2Color: colors.lightBlue, + textColor: colors.grey700, + }, + datePicker: { + color: colors.grey700, + textColor: colors.white, + calendarTextColor: colors.white, + selectColor: colors.darkestGrey, + selectTextColor: colors.white, + }, + timePicker: { + color: colors.grey700, + textColor: colors.white, + accentColor: colors.white, + headerColor: colors.darkestGrey, + selectColor: colors.darkestGrey, + selectTextColor: colors.darkestGrey, + }, + toggle: { + thumbOnColor: colors.limeGreen, + trackOnColor: colors.lightGreen, + }, +}); diff --git a/packages/website/ts/utils/typedoc_utils.ts b/packages/website/ts/utils/typedoc_utils.ts index 803cfa0cf..11ec8da58 100644 --- a/packages/website/ts/utils/typedoc_utils.ts +++ b/packages/website/ts/utils/typedoc_utils.ts @@ -1,34 +1,32 @@ import * as _ from 'lodash'; -import {DocsInfo} from 'ts/pages/documentation/docs_info'; +import { DocsInfo } from 'ts/pages/documentation/docs_info'; import { CustomType, CustomTypeChild, DocAgnosticFormat, DocSection, - DocsMenu, IndexSignature, KindString, - MenuSubsectionsBySection, Parameter, Property, SectionsMap, Type, TypeDocNode, TypeDocType, - TypeDocTypes, TypeParameter, TypescriptMethod, } from 'ts/types'; -import {constants} from 'ts/utils/constants'; -import {utils} from 'ts/utils/utils'; +import { utils } from 'ts/utils/utils'; export const typeDocUtils = { isType(entity: TypeDocNode): boolean { - return entity.kindString === KindString.Interface || - entity.kindString === KindString.Function || - entity.kindString === KindString['Type alias'] || - entity.kindString === KindString.Variable || - entity.kindString === KindString.Enumeration; + return ( + entity.kindString === KindString.Interface || + entity.kindString === KindString.Function || + entity.kindString === KindString.TypeAlias || + entity.kindString === KindString.Variable || + entity.kindString === KindString.Enumeration + ); }, isMethod(entity: TypeDocNode): boolean { return entity.kindString === KindString.Method; @@ -42,8 +40,10 @@ export const typeDocUtils = { isPrivateOrProtectedProperty(propertyName: string): boolean { return _.startsWith(propertyName, '_'); }, - getModuleDefinitionBySectionNameIfExists(versionDocObj: TypeDocNode, modulePaths: string[]): - TypeDocNode|undefined { + getModuleDefinitionBySectionNameIfExists( + versionDocObj: TypeDocNode, + modulePaths: string[], + ): TypeDocNode | undefined { const modules = versionDocObj.children; for (const mod of modules) { if (_.includes(modulePaths, mod.name)) { @@ -63,7 +63,8 @@ export const typeDocUtils = { return; // no-op } const packageDefinitionIfExists = typeDocUtils.getModuleDefinitionBySectionNameIfExists( - typeDocJson, modulePathsIfExists, + typeDocJson, + modulePathsIfExists, ); if (_.isUndefined(packageDefinitionIfExists)) { return; // no-op @@ -103,7 +104,11 @@ export const typeDocUtils = { case KindString.Constructor: isConstructor = true; const constructor = typeDocUtils._convertMethod( - entity, isConstructor, docsInfo.sections, sectionName, + entity, + isConstructor, + docsInfo.sections, + sectionName, + docsInfo.subPackageName, ); docSection.constructors.push(constructor); break; @@ -112,7 +117,11 @@ export const typeDocUtils = { if (entity.flags.isPublic) { isConstructor = false; const method = typeDocUtils._convertMethod( - entity, isConstructor, docsInfo.sections, sectionName, + entity, + isConstructor, + docsInfo.sections, + sectionName, + docsInfo.subPackageName, ); docSection.methods.push(method); } @@ -120,7 +129,12 @@ export const typeDocUtils = { case KindString.Property: if (!typeDocUtils.isPrivateOrProtectedProperty(entity.name)) { - const property = typeDocUtils._convertProperty(entity, docsInfo.sections, sectionName); + const property = typeDocUtils._convertProperty( + entity, + docsInfo.sections, + sectionName, + docsInfo.subPackageName, + ); docSection.properties.push(property); } break; @@ -129,9 +143,14 @@ export const typeDocUtils = { case KindString.Function: case KindString.Variable: case KindString.Enumeration: - case KindString['Type alias']: + case KindString.TypeAlias: if (docsInfo.isPublicType(entity.name)) { - const customType = typeDocUtils._convertCustomType(entity, docsInfo.sections, sectionName); + const customType = typeDocUtils._convertCustomType( + entity, + docsInfo.sections, + sectionName, + docsInfo.subPackageName, + ); docSection.types.push(customType); } break; @@ -142,34 +161,40 @@ export const typeDocUtils = { }); return docSection; }, - _convertCustomType(entity: TypeDocNode, sections: SectionsMap, sectionName: string): CustomType { - const typeIfExists = !_.isUndefined(entity.type) ? - typeDocUtils._convertType(entity.type, sections, sectionName) : - undefined; + _convertCustomType( + entity: TypeDocNode, + sections: SectionsMap, + sectionName: string, + subPackageName: string, + ): CustomType { + const typeIfExists = !_.isUndefined(entity.type) + ? typeDocUtils._convertType(entity.type, sections, sectionName, subPackageName) + : undefined; const isConstructor = false; - const methodIfExists = !_.isUndefined(entity.declaration) ? - typeDocUtils._convertMethod(entity.declaration, isConstructor, sections, sectionName) : - undefined; - const indexSignatureIfExists = !_.isUndefined(entity.indexSignature) ? - typeDocUtils._convertIndexSignature(entity.indexSignature[0], sections, sectionName) : - undefined; - const commentIfExists = !_.isUndefined(entity.comment) && !_.isUndefined(entity.comment.shortText) ? - entity.comment.shortText : - undefined; + const methodIfExists = !_.isUndefined(entity.declaration) + ? typeDocUtils._convertMethod(entity.declaration, isConstructor, sections, sectionName, subPackageName) + : undefined; + const indexSignatureIfExists = !_.isUndefined(entity.indexSignature) + ? typeDocUtils._convertIndexSignature(entity.indexSignature[0], sections, sectionName, subPackageName) + : undefined; + const commentIfExists = + !_.isUndefined(entity.comment) && !_.isUndefined(entity.comment.shortText) + ? entity.comment.shortText + : undefined; - const childrenIfExist = !_.isUndefined(entity.children) ? - _.map(entity.children, (child: TypeDocNode) => { - const childTypeIfExists = !_.isUndefined(child.type) ? - typeDocUtils._convertType(child.type, sections, sectionName) : - undefined; - const c: CustomTypeChild = { - name: child.name, - type: childTypeIfExists, - defaultValue: child.defaultValue, - }; - return c; - }) : - undefined; + const childrenIfExist = !_.isUndefined(entity.children) + ? _.map(entity.children, (child: TypeDocNode) => { + const childTypeIfExists = !_.isUndefined(child.type) + ? typeDocUtils._convertType(child.type, sections, sectionName, subPackageName) + : undefined; + const c: CustomTypeChild = { + name: child.name, + type: childTypeIfExists, + defaultValue: child.defaultValue, + }; + return c; + }) + : undefined; const customType = { name: entity.name, @@ -183,21 +208,31 @@ export const typeDocUtils = { }; return customType; }, - _convertIndexSignature(entity: TypeDocNode, sections: SectionsMap, sectionName: string): IndexSignature { + _convertIndexSignature( + entity: TypeDocNode, + sections: SectionsMap, + sectionName: string, + subPackageName: string, + ): IndexSignature { const key = entity.parameters[0]; const indexSignature = { keyName: key.name, - keyType: typeDocUtils._convertType(key.type, sections, sectionName), + keyType: typeDocUtils._convertType(key.type, sections, sectionName, subPackageName), valueName: entity.type.name, }; return indexSignature; }, - _convertProperty(entity: TypeDocNode, sections: SectionsMap, sectionName: string): Property { + _convertProperty( + entity: TypeDocNode, + sections: SectionsMap, + sectionName: string, + subPackageName: string, + ): Property { const source = entity.sources[0]; const commentIfExists = !_.isUndefined(entity.comment) ? entity.comment.shortText : undefined; const property = { name: entity.name, - type: typeDocUtils._convertType(entity.type, sections, sectionName), + type: typeDocUtils._convertType(entity.type, sections, sectionName, subPackageName), source: { fileName: source.fileName, line: source.line, @@ -207,28 +242,39 @@ export const typeDocUtils = { return property; }, _convertMethod( - entity: TypeDocNode, isConstructor: boolean, sections: SectionsMap, sectionName: string, + entity: TypeDocNode, + isConstructor: boolean, + sections: SectionsMap, + sectionName: string, + subPackageName: string, ): TypescriptMethod { const signature = entity.signatures[0]; const source = entity.sources[0]; const hasComment = !_.isUndefined(signature.comment); const isStatic = _.isUndefined(entity.flags.isStatic) ? false : entity.flags.isStatic; - const topLevelInterface = isStatic ? 'ZeroEx.' : 'zeroEx.'; // HACK: we use the fact that the sectionName is the same as the property name at the top-level // of the public interface. In the future, we shouldn't use this hack but rather get it from the JSON. - let callPath = (!_.isUndefined(sections.zeroEx) && sectionName !== sections.zeroEx) ? - `${topLevelInterface}${sectionName}.` : - topLevelInterface; - callPath = isConstructor || entity.name === '__type' ? '' : callPath; + let callPath; + if (isConstructor || entity.name === '__type') { + callPath = ''; + } else if (subPackageName === '0x.js') { + const topLevelInterface = isStatic ? 'ZeroEx.' : 'zeroEx.'; + callPath = + !_.isUndefined(sections.zeroEx) && sectionName !== sections.zeroEx + ? `${topLevelInterface}${sectionName}.` + : topLevelInterface; + } else { + callPath = `${sectionName}.`; + } const parameters = _.map(signature.parameters, param => { - return typeDocUtils._convertParameter(param, sections, sectionName); + return typeDocUtils._convertParameter(param, sections, sectionName, subPackageName); }); - const returnType = typeDocUtils._convertType(signature.type, sections, sectionName); - const typeParameter = _.isUndefined(signature.typeParameter) ? - undefined : - typeDocUtils._convertTypeParameter(signature.typeParameter[0], sections, sectionName); + const returnType = typeDocUtils._convertType(signature.type, sections, sectionName, subPackageName); + const typeParameter = _.isUndefined(signature.typeParameter) + ? undefined + : typeDocUtils._convertTypeParameter(signature.typeParameter[0], sections, sectionName, subPackageName); const method = { isConstructor, @@ -247,15 +293,25 @@ export const typeDocUtils = { }; return method; }, - _convertTypeParameter(entity: TypeDocNode, sections: SectionsMap, sectionName: string): TypeParameter { - const type = typeDocUtils._convertType(entity.type, sections, sectionName); + _convertTypeParameter( + entity: TypeDocNode, + sections: SectionsMap, + sectionName: string, + subPackageName: string, + ): TypeParameter { + const type = typeDocUtils._convertType(entity.type, sections, sectionName, subPackageName); const parameter = { name: entity.name, type, }; return parameter; }, - _convertParameter(entity: TypeDocNode, sections: SectionsMap, sectionName: string): Parameter { + _convertParameter( + entity: TypeDocNode, + sections: SectionsMap, + sectionName: string, + subPackageName: string, + ): Parameter { let comment = '<No comment>'; if (entity.comment && entity.comment.shortText) { comment = entity.comment.shortText; @@ -263,11 +319,9 @@ export const typeDocUtils = { comment = entity.comment.text; } - const isOptional = !_.isUndefined(entity.flags.isOptional) ? - entity.flags.isOptional : - false; + const isOptional = !_.isUndefined(entity.flags.isOptional) ? entity.flags.isOptional : false; - const type = typeDocUtils._convertType(entity.type, sections, sectionName); + const type = typeDocUtils._convertType(entity.type, sections, sectionName, subPackageName); const parameter = { name: entity.name, @@ -277,25 +331,25 @@ export const typeDocUtils = { }; return parameter; }, - _convertType(entity: TypeDocType, sections: SectionsMap, sectionName: string): Type { + _convertType(entity: TypeDocType, sections: SectionsMap, sectionName: string, subPackageName: string): Type { const typeArguments = _.map(entity.typeArguments, typeArgument => { - return typeDocUtils._convertType(typeArgument, sections, sectionName); + return typeDocUtils._convertType(typeArgument, sections, sectionName, subPackageName); }); const types = _.map(entity.types, t => { - return typeDocUtils._convertType(t, sections, sectionName); + return typeDocUtils._convertType(t, sections, sectionName, subPackageName); }); const isConstructor = false; - const methodIfExists = !_.isUndefined(entity.declaration) ? - typeDocUtils._convertMethod(entity.declaration, isConstructor, sections, sectionName) : - undefined; + const methodIfExists = !_.isUndefined(entity.declaration) + ? typeDocUtils._convertMethod(entity.declaration, isConstructor, sections, sectionName, subPackageName) + : undefined; - const elementTypeIfExists = !_.isUndefined(entity.elementType) ? - { - name: entity.elementType.name, - typeDocType: entity.elementType.type, - } : - undefined; + const elementTypeIfExists = !_.isUndefined(entity.elementType) + ? { + name: entity.elementType.name, + typeDocType: entity.elementType.type, + } + : undefined; const type = { name: entity.name, diff --git a/packages/website/ts/utils/utils.ts b/packages/website/ts/utils/utils.ts index 8b23b6a40..13a6d6ae2 100644 --- a/packages/website/ts/utils/utils.ts +++ b/packages/website/ts/utils/utils.ts @@ -1,7 +1,6 @@ -import {ExchangeContractErrs, ZeroExError} from '0x.js'; -import BigNumber from 'bignumber.js'; +import { ExchangeContractErrs, ZeroExError } from '0x.js'; +import { BigNumber } from '@0xproject/utils'; import deepEqual = require('deep-equal'); -import ethUtil = require('ethereumjs-util'); import isMobile = require('is-mobile'); import * as _ from 'lodash'; import * as moment from 'moment'; @@ -9,7 +8,6 @@ import { EtherscanLinkSuffixes, Networks, Order, - OrderParty, ScreenWidths, Side, SideToAssetToken, @@ -17,7 +15,8 @@ import { Token, TokenByAddress, } from 'ts/types'; -import {constants} from 'ts/utils/constants'; +import { configs } from 'ts/utils/configs'; +import { constants } from 'ts/utils/constants'; import * as u2f from 'ts/vendor/u2f_api'; const LG_MIN_EM = 64; @@ -59,12 +58,22 @@ export const utils = { const formattedDate: string = m.format('h:MMa MMMM D YYYY'); return formattedDate; }, - generateOrder(networkId: number, exchangeContract: string, sideToAssetToken: SideToAssetToken, - orderExpiryTimestamp: BigNumber, orderTakerAddress: string, orderMakerAddress: string, - makerFee: BigNumber, takerFee: BigNumber, feeRecipient: string, - signatureData: SignatureData, tokenByAddress: TokenByAddress, orderSalt: BigNumber): Order { - const makerToken = tokenByAddress[sideToAssetToken[Side.deposit].address]; - const takerToken = tokenByAddress[sideToAssetToken[Side.receive].address]; + generateOrder( + networkId: number, + exchangeContract: string, + sideToAssetToken: SideToAssetToken, + orderExpiryTimestamp: BigNumber, + orderTakerAddress: string, + orderMakerAddress: string, + makerFee: BigNumber, + takerFee: BigNumber, + feeRecipient: string, + signatureData: SignatureData, + tokenByAddress: TokenByAddress, + orderSalt: BigNumber, + ): Order { + const makerToken = tokenByAddress[sideToAssetToken[Side.Deposit].address]; + const takerToken = tokenByAddress[sideToAssetToken[Side.Receive].address]; const order = { maker: { address: orderMakerAddress, @@ -74,7 +83,7 @@ export const utils = { decimals: makerToken.decimals, address: makerToken.address, }, - amount: sideToAssetToken[Side.deposit].amount.toString(), + amount: sideToAssetToken[Side.Deposit].amount.toString(), feeAmount: makerFee.toString(), }, taker: { @@ -85,7 +94,7 @@ export const utils = { decimals: takerToken.decimals, address: takerToken.address, }, - amount: sideToAssetToken[Side.receive].amount.toString(), + amount: sideToAssetToken[Side.Receive].amount.toString(), feeAmount: takerFee.toString(), }, expiration: orderExpiryTimestamp.toString(), @@ -105,14 +114,14 @@ export const utils = { async sleepAsync(ms: number) { return new Promise(resolve => setTimeout(resolve, ms)); }, - deepEqual(actual: any, expected: any, opts?: {strict: boolean}) { + deepEqual(actual: any, expected: any, opts?: { strict: boolean }) { return deepEqual(actual, expected, opts); }, getColSize(items: number) { const bassCssGridSize = 12; // Source: http://basscss.com/#basscss-grid - const colSize = 12 / items; + const colSize = bassCssGridSize / items; if (!_.isInteger(colSize)) { - throw new Error('Number of cols must be divisible by 12'); + throw new Error(`Number of cols must be divisible by ${bassCssGridSize}`); } return colSize; }, @@ -126,11 +135,11 @@ export const utils = { // This logic mirrors the CSS media queries in BassCSS for the `lg-`, `md-` and `sm-` CSS // class prefixes. Do not edit these. if (widthInEm > LG_MIN_EM) { - return ScreenWidths.LG; + return ScreenWidths.Lg; } else if (widthInEm > MD_MIN_EM) { - return ScreenWidths.MD; + return ScreenWidths.Md; } else { - return ScreenWidths.SM; + return ScreenWidths.Sm; } }, isUserOnMobile(): boolean { @@ -138,7 +147,7 @@ export const utils = { return isUserOnMobile; }, getEtherScanLinkIfExists(addressOrTxHash: string, networkId: number, suffix: EtherscanLinkSuffixes): string { - const networkName = constants.networkNameById[networkId]; + const networkName = constants.NETWORK_NAME_BY_ID[networkId]; if (_.isUndefined(networkName)) { return undefined; } @@ -149,7 +158,7 @@ export const utils = { window.location.hash = anchorId; }, async isU2FSupportedAsync(): Promise<boolean> { - const w = (window as any); + const w = window as any; return new Promise((resolve: (isSupported: boolean) => void) => { if (w.u2f && !w.u2f.getApiVersion) { // u2f object was found (Firefox with extension) @@ -177,18 +186,19 @@ export const utils = { const metamaskDenialErrMsg = 'User denied message'; const paritySignerDenialErrMsg = 'Request has been rejected'; const ledgerDenialErrMsg = 'Invalid status 6985'; - const isUserDeniedErrMsg = _.includes(errMsg, metamaskDenialErrMsg) || - _.includes(errMsg, paritySignerDenialErrMsg) || - _.includes(errMsg, ledgerDenialErrMsg); + const isUserDeniedErrMsg = + _.includes(errMsg, metamaskDenialErrMsg) || + _.includes(errMsg, paritySignerDenialErrMsg) || + _.includes(errMsg, ledgerDenialErrMsg); return isUserDeniedErrMsg; }, getCurrentEnvironment() { switch (location.host) { - case constants.DEVELOPMENT_DOMAIN: + case configs.DOMAIN_DEVELOPMENT: return 'development'; - case constants.STAGING_DOMAIN: + case configs.DOMAIN_STAGING: return 'staging'; - case constants.PRODUCTION_DOMAIN: + case configs.DOMAIN_PRODUCTION: return 'production'; default: return 'production'; @@ -207,14 +217,18 @@ export const utils = { return true; // Since it's registered, it is the canonical token } const registeredTokens = _.filter(tokens, t => t.isRegistered); - const tokenWithSameNameIfExists = _.find(registeredTokens, {name: token.name}); + const tokenWithSameNameIfExists = _.find(registeredTokens, { + name: token.name, + }); const isUniqueName = _.isUndefined(tokenWithSameNameIfExists); - const tokenWithSameSymbolIfExists = _.find(registeredTokens, {name: token.symbol}); + const tokenWithSameSymbolIfExists = _.find(registeredTokens, { + name: token.symbol, + }); const isUniqueSymbol = _.isUndefined(tokenWithSameSymbolIfExists); return isUniqueName && isUniqueSymbol; }, - zeroExErrToHumanReadableErrMsg(error: ZeroExError|ExchangeContractErrs, takerAddress: string): string { - const ZeroExErrorToHumanReadableError: {[error: string]: string} = { + zeroExErrToHumanReadableErrMsg(error: ZeroExError | ExchangeContractErrs, takerAddress: string): string { + const ZeroExErrorToHumanReadableError: { [error: string]: string } = { [ZeroExError.ExchangeContractDoesNotExist]: 'Exchange contract does not exist', [ZeroExError.EtherTokenContractDoesNotExist]: 'EtherToken contract does not exist', [ZeroExError.TokenTransferProxyContractDoesNotExist]: 'TokenTransferProxy contract does not exist', @@ -229,37 +243,37 @@ export const utils = { [ZeroExError.OutOfGas]: 'Transaction ran out of gas', [ZeroExError.NoNetworkId]: 'No network id detected', }; - const exchangeContractErrorToHumanReadableError: {[error: string]: string} = { + const exchangeContractErrorToHumanReadableError: { + [error: string]: string; + } = { [ExchangeContractErrs.OrderFillExpired]: 'This order has expired', [ExchangeContractErrs.OrderCancelExpired]: 'This order has expired', - [ExchangeContractErrs.OrderCancelAmountZero]: 'Order cancel amount can\'t be 0', + [ExchangeContractErrs.OrderCancelAmountZero]: "Order cancel amount can't be 0", [ExchangeContractErrs.OrderAlreadyCancelledOrFilled]: - 'This order has already been completely filled or cancelled', - [ExchangeContractErrs.OrderFillAmountZero]: 'Order fill amount can\'t be 0', + 'This order has already been completely filled or cancelled', + [ExchangeContractErrs.OrderFillAmountZero]: "Order fill amount can't be 0", [ExchangeContractErrs.OrderRemainingFillAmountZero]: - 'This order has already been completely filled or cancelled', + 'This order has already been completely filled or cancelled', [ExchangeContractErrs.OrderFillRoundingError]: 'Rounding error will occur when filling this order', [ExchangeContractErrs.InsufficientTakerBalance]: - 'Taker no longer has a sufficient balance to complete this order', + 'Taker no longer has a sufficient balance to complete this order', [ExchangeContractErrs.InsufficientTakerAllowance]: - 'Taker no longer has a sufficient allowance to complete this order', + 'Taker no longer has a sufficient allowance to complete this order', [ExchangeContractErrs.InsufficientMakerBalance]: - 'Maker no longer has a sufficient balance to complete this order', + 'Maker no longer has a sufficient balance to complete this order', [ExchangeContractErrs.InsufficientMakerAllowance]: - 'Maker no longer has a sufficient allowance to complete this order', + 'Maker no longer has a sufficient allowance to complete this order', [ExchangeContractErrs.InsufficientTakerFeeBalance]: 'Taker no longer has a sufficient balance to pay fees', [ExchangeContractErrs.InsufficientTakerFeeAllowance]: - 'Taker no longer has a sufficient allowance to pay fees', + 'Taker no longer has a sufficient allowance to pay fees', [ExchangeContractErrs.InsufficientMakerFeeBalance]: 'Maker no longer has a sufficient balance to pay fees', [ExchangeContractErrs.InsufficientMakerFeeAllowance]: - 'Maker no longer has a sufficient allowance to pay fees', - [ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker]: - `This order can only be filled by ${takerAddress}`, - [ExchangeContractErrs.InsufficientRemainingFillAmount]: - 'Insufficient remaining fill amount', + 'Maker no longer has a sufficient allowance to pay fees', + [ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker]: `This order can only be filled by ${takerAddress}`, + [ExchangeContractErrs.InsufficientRemainingFillAmount]: 'Insufficient remaining fill amount', }; - const humanReadableErrorMsg = exchangeContractErrorToHumanReadableError[error] || - ZeroExErrorToHumanReadableError[error]; + const humanReadableErrorMsg = + exchangeContractErrorToHumanReadableError[error] || ZeroExErrorToHumanReadableError[error]; return humanReadableErrorMsg; }, }; diff --git a/packages/website/ts/web3_wrapper.ts b/packages/website/ts/web3_wrapper.ts index b713f8a33..415df6e8b 100644 --- a/packages/website/ts/web3_wrapper.ts +++ b/packages/website/ts/web3_wrapper.ts @@ -1,34 +1,38 @@ -import {promisify} from '@0xproject/utils'; -import BigNumber from 'bignumber.js'; +import { BigNumber, intervalUtils, promisify } from '@0xproject/utils'; import * as _ from 'lodash'; -import {Dispatcher} from 'ts/redux/dispatcher'; +import { Dispatcher } from 'ts/redux/dispatcher'; +import { utils } from 'ts/utils/utils'; import * as Web3 from 'web3'; export class Web3Wrapper { - private dispatcher: Dispatcher; - private web3: Web3; - private prevNetworkId: number; - private shouldPollUserAddress: boolean; - private watchNetworkAndBalanceIntervalId: number; - private prevUserEtherBalanceInEth: BigNumber; - private prevUserAddress: string; - constructor(dispatcher: Dispatcher, provider: Web3.Provider, networkIdIfExists: number, - shouldPollUserAddress: boolean) { - this.dispatcher = dispatcher; - this.prevNetworkId = networkIdIfExists; - this.shouldPollUserAddress = shouldPollUserAddress; + private _dispatcher: Dispatcher; + private _web3: Web3; + private _prevNetworkId: number; + private _shouldPollUserAddress: boolean; + private _watchNetworkAndBalanceIntervalId: NodeJS.Timer; + private _prevUserEtherBalanceInEth: BigNumber; + private _prevUserAddress: string; + constructor( + dispatcher: Dispatcher, + provider: Web3.Provider, + networkIdIfExists: number, + shouldPollUserAddress: boolean, + ) { + this._dispatcher = dispatcher; + this._prevNetworkId = networkIdIfExists; + this._shouldPollUserAddress = shouldPollUserAddress; - this.web3 = new Web3(); - this.web3.setProvider(provider); + this._web3 = new Web3(); + this._web3.setProvider(provider); // tslint:disable-next-line:no-floating-promises - this.startEmittingNetworkConnectionAndUserBalanceStateAsync(); + this._startEmittingNetworkConnectionAndUserBalanceStateAsync(); } public isAddress(address: string) { - return this.web3.isAddress(address); + return this._web3.isAddress(address); } public async getAccountsAsync(): Promise<string[]> { - const addresses = await promisify<string[]>(this.web3.eth.getAccounts)(); + const addresses = await promisify<string[]>(this._web3.eth.getAccounts)(); return addresses; } public async getFirstAccountIfExistsAsync() { @@ -36,112 +40,119 @@ export class Web3Wrapper { if (_.isEmpty(addresses)) { return ''; } - return (addresses)[0]; + return addresses[0]; } public async getNodeVersionAsync(): Promise<string> { - const nodeVersion = await promisify<string>(this.web3.version.getNode)(); + const nodeVersion = await promisify<string>(this._web3.version.getNode)(); return nodeVersion; } public getProviderObj() { - return this.web3.currentProvider; + return this._web3.currentProvider; } public async getNetworkIdIfExists() { try { - const networkId = await this.getNetworkAsync(); + const networkId = await this._getNetworkAsync(); return Number(networkId); } catch (err) { return undefined; } } public async getBalanceInEthAsync(owner: string): Promise<BigNumber> { - const balanceInWei: BigNumber = await promisify<BigNumber>(this.web3.eth.getBalance)(owner); - const balanceEthOldBigNumber = this.web3.fromWei(balanceInWei, 'ether'); + const balanceInWei: BigNumber = await promisify<BigNumber>(this._web3.eth.getBalance)(owner); + const balanceEthOldBigNumber = this._web3.fromWei(balanceInWei, 'ether'); const balanceEth = new BigNumber(balanceEthOldBigNumber); return balanceEth; } public async doesContractExistAtAddressAsync(address: string): Promise<boolean> { - const code = await promisify<string>(this.web3.eth.getCode)(address); + const code = await promisify<string>(this._web3.eth.getCode)(address); // Regex matches 0x0, 0x00, 0x in order to accomodate poorly implemented clients const zeroHexAddressRegex = /^0[xX][0]*$/; const didFindCode = _.isNull(code.match(zeroHexAddressRegex)); return didFindCode; } public async signTransactionAsync(address: string, message: string): Promise<string> { - const signData = await promisify<string>(this.web3.eth.sign)(address, message); + const signData = await promisify<string>(this._web3.eth.sign)(address, message); return signData; } public async getBlockTimestampAsync(blockHash: string): Promise<number> { - const {timestamp} = await promisify<Web3.BlockWithoutTransactionData>(this.web3.eth.getBlock)(blockHash); + const { timestamp } = await promisify<Web3.BlockWithoutTransactionData>(this._web3.eth.getBlock)(blockHash); return timestamp; } public destroy() { - this.stopEmittingNetworkConnectionAndUserBalanceStateAsync(); + this._stopEmittingNetworkConnectionAndUserBalanceStateAsync(); // HACK: stop() is only available on providerEngine instances - const provider = this.web3.currentProvider; + const provider = this._web3.currentProvider; if (!_.isUndefined((provider as any).stop)) { (provider as any).stop(); } } // This should only be called from the LedgerConfigDialog public updatePrevUserAddress(userAddress: string) { - this.prevUserAddress = userAddress; + this._prevUserAddress = userAddress; } - private async getNetworkAsync() { - const networkId = await promisify(this.web3.version.getNetwork)(); + private async _getNetworkAsync() { + const networkId = await promisify(this._web3.version.getNetwork)(); return networkId; } - private async startEmittingNetworkConnectionAndUserBalanceStateAsync() { - if (!_.isUndefined(this.watchNetworkAndBalanceIntervalId)) { + private async _startEmittingNetworkConnectionAndUserBalanceStateAsync() { + if (!_.isUndefined(this._watchNetworkAndBalanceIntervalId)) { return; // we are already emitting the state } let prevNodeVersion: string; - this.prevUserEtherBalanceInEth = new BigNumber(0); - this.dispatcher.updateNetworkId(this.prevNetworkId); - this.watchNetworkAndBalanceIntervalId = window.setInterval(async () => { - // Check for network state changes - const currentNetworkId = await this.getNetworkIdIfExists(); - if (currentNetworkId !== this.prevNetworkId) { - this.prevNetworkId = currentNetworkId; - this.dispatcher.updateNetworkId(currentNetworkId); - } - - // Check for node version changes - const currentNodeVersion = await this.getNodeVersionAsync(); - if (currentNodeVersion !== prevNodeVersion) { - prevNodeVersion = currentNodeVersion; - this.dispatcher.updateNodeVersion(currentNodeVersion); - } - - if (this.shouldPollUserAddress) { - const userAddressIfExists = await this.getFirstAccountIfExistsAsync(); - // Update makerAddress on network change - if (this.prevUserAddress !== userAddressIfExists) { - this.prevUserAddress = userAddressIfExists; - this.dispatcher.updateUserAddress(userAddressIfExists); + this._prevUserEtherBalanceInEth = new BigNumber(0); + this._dispatcher.updateNetworkId(this._prevNetworkId); + this._watchNetworkAndBalanceIntervalId = intervalUtils.setAsyncExcludingInterval( + async () => { + // Check for network state changes + const currentNetworkId = await this.getNetworkIdIfExists(); + if (currentNetworkId !== this._prevNetworkId) { + this._prevNetworkId = currentNetworkId; + this._dispatcher.updateNetworkId(currentNetworkId); } - // Check for user ether balance changes - if (userAddressIfExists !== '') { - await this.updateUserEtherBalanceAsync(userAddressIfExists); + // Check for node version changes + const currentNodeVersion = await this.getNodeVersionAsync(); + if (currentNodeVersion !== prevNodeVersion) { + prevNodeVersion = currentNodeVersion; + this._dispatcher.updateNodeVersion(currentNodeVersion); } - } else { - // This logic is primarily for the Ledger, since we don't regularly poll for the address - // we simply update the balance for the last fetched address. - if (!_.isEmpty(this.prevUserAddress)) { - await this.updateUserEtherBalanceAsync(this.prevUserAddress); + + if (this._shouldPollUserAddress) { + const userAddressIfExists = await this.getFirstAccountIfExistsAsync(); + // Update makerAddress on network change + if (this._prevUserAddress !== userAddressIfExists) { + this._prevUserAddress = userAddressIfExists; + this._dispatcher.updateUserAddress(userAddressIfExists); + } + + // Check for user ether balance changes + if (userAddressIfExists !== '') { + await this._updateUserEtherBalanceAsync(userAddressIfExists); + } + } else { + // This logic is primarily for the Ledger, since we don't regularly poll for the address + // we simply update the balance for the last fetched address. + if (!_.isEmpty(this._prevUserAddress)) { + await this._updateUserEtherBalanceAsync(this._prevUserAddress); + } } - } - }, 5000); - } - private async updateUserEtherBalanceAsync(userAddress: string) { + }, + 5000, + (err: Error) => { + utils.consoleLog(`Watching network and balances failed: ${err}`); + this._stopEmittingNetworkConnectionAndUserBalanceStateAsync(); + }, + ); + } + private async _updateUserEtherBalanceAsync(userAddress: string) { const balance = await this.getBalanceInEthAsync(userAddress); - if (!balance.eq(this.prevUserEtherBalanceInEth)) { - this.prevUserEtherBalanceInEth = balance; - this.dispatcher.updateUserEtherBalance(balance); + if (!balance.eq(this._prevUserEtherBalanceInEth)) { + this._prevUserEtherBalanceInEth = balance; + this._dispatcher.updateUserEtherBalance(balance); } } - private stopEmittingNetworkConnectionAndUserBalanceStateAsync() { - clearInterval(this.watchNetworkAndBalanceIntervalId); + private _stopEmittingNetworkConnectionAndUserBalanceStateAsync() { + intervalUtils.clearAsyncExcludingInterval(this._watchNetworkAndBalanceIntervalId); } } diff --git a/packages/website/tsconfig.json b/packages/website/tsconfig.json index 5b3510c26..38b177d0b 100644 --- a/packages/website/tsconfig.json +++ b/packages/website/tsconfig.json @@ -1,21 +1,17 @@ { + "extends": "../../tsconfig", "compilerOptions": { "allowSyntheticDefaultImports": true, "outDir": "./transpiled/", - "sourceMap": true, - "lib": [ "es2015", "dom" ], - "noImplicitAny": true, - "module": "commonjs", - "target": "es5", "jsx": "react", "baseUrl": "./", "allowJs": true, + "strictNullChecks": false, + "noImplicitThis": false, + "declaration": false, "paths": { - "*": [ "node_modules/@types/*", "*"] + "*": ["node_modules/@types/*", "*"] } }, - "include": [ - "./ts/**/*", - "../../node_modules/web3-typescript-typings/index.d.ts" - ] + "include": ["./ts/**/*", "../../node_modules/web3-typescript-typings/index.d.ts"] } diff --git a/packages/website/tslint.json b/packages/website/tslint.json index 957c0e11d..d6a5f5031 100644 --- a/packages/website/tslint.json +++ b/packages/website/tslint.json @@ -1,11 +1,9 @@ { - "extends": [ - "@0xproject/tslint-config" - ], - "rules": { - "no-implicit-dependencies": false, - "no-object-literal-type-assertion": false, - "completed-docs": false, - "prefer-function-over-method": false - } + "extends": ["@0xproject/tslint-config"], + "rules": { + "no-implicit-dependencies": false, + "no-object-literal-type-assertion": false, + "completed-docs": false, + "prefer-function-over-method": false + } } |