Compare commits

...

627 Commits

Author SHA1 Message Date
Leonid Logvinov
8df2cc103e Fix linter errors 2018-02-01 16:29:16 +01:00
Leonid Logvinov
8e0e9c7d3a Update changelog 2018-02-01 16:27:12 +01:00
Leonid
913930b561 Merge pull request #357 from ERCdEX/luke/zrx_order_watch_cache
BUGFIX: don't remove maker/zrx order from cache twice
2018-02-01 16:25:25 +01:00
Leonid Logvinov
994c8db1f3 Add OrderWatcherConfig to the list of public types 2018-02-01 13:01:10 +01:00
Luke Autry
6811bdec40 don't remove maker/zrx order from cache twice 2018-01-31 22:56:05 -05:00
Brandon Millman
6682abf89d Merge pull request #354 from 0xProject/feature/tslint-config/underscore-protected-members
Modify lint rules to enforce underscore for protected members
2018-01-31 14:55:50 -08:00
Brandon Millman
78fbf0f7ba Prettier 2018-01-31 14:41:37 -08:00
Brandon Millman
89547332ee Merge branch 'development' into feature/tslint-config/underscore-protected-members
* development:
  Updated contract generation in 0x to new abi-gen CLI
  Removed deprecated CLI options
  Added PR # to the changelog of abi-gen
  Added CLI options for explicit specifying location of partials and main template
2018-01-31 12:38:12 -08:00
Leonid
75539bf675 Merge pull request #346 from joincivil/feature/abi-gen-partials
Added CLI options for explicit specifying location of partials and main template
2018-01-31 14:50:25 +01:00
Olaf Tomalka
eaeb715e56 Updated contract generation in 0x to new abi-gen CLI 2018-01-31 14:24:20 +01:00
Brandon Millman
ca55cc99ed Add PR number to changelog 2018-01-30 16:48:40 -08:00
Brandon Millman
7cc4a8f5ce Fix lint errors 2018-01-30 16:26:42 -08:00
Olaf Tomalka
fa35768fc9 Removed deprecated CLI options 2018-01-31 00:41:58 +01:00
Brandon Millman
4d0ff0dce4 Add protected keyword to underscore lint rule 2018-01-30 14:02:13 -08:00
Fabio Berger
8aac6e46d4 Remove unused prop 2018-01-30 21:34:13 +01:00
Fabio Berger
1feac1a308 Merge pull request #351 from 0xProject/feature/portal-ledger-support
Portal Ledger Support, Lazy-loading token balances/allowances
2018-01-30 21:27:21 +01:00
Fabio Berger
d3e42e4b3e Fix prettier 2018-01-30 21:16:47 +01:00
Fabio Berger
ecf86d1d13 Uppercase Networks enum values 2018-01-30 21:01:16 +01:00
Fabio Berger
adc6170f02 Make default gasPrice more readable 2018-01-30 20:53:22 +01:00
Fabio Berger
02600f40d2 Fix prettier mess 2018-01-30 20:53:09 +01:00
Fabio Berger
16ea0348a9 Fix linter errors 2018-01-30 20:45:09 +01:00
Fabio Berger
57acb8db5c Shrink img 2018-01-30 20:28:15 +01:00
Leonid
2bcb7d5639 Merge pull request #332 from 0xProject/feature/contracts-abi-gen
Contracts refactor. Bye, truffle!!! 👏
2018-01-30 20:27:14 +01:00
Fabio Berger
a99e54330a Merge branch 'development' into feature/portal-ledger-support
* development:
  Prettierignore package.json
  Enable solidity syntax highlighting
2018-01-30 20:13:02 +01:00
Fabio Berger
e219772b2a Fix all setState calls after unmounted errors. Decided to create our own flag rather then using a cancellablePromise since there was little to be gained from this alternative 2018-01-30 20:12:32 +01:00
Fabio Berger
144a507a2e Fix bug where we were return undefined instead of the empty object 2018-01-30 20:11:18 +01:00
Fabio Berger
5019c51940 Default the derivation path to that found in the Ledger subprovider 2018-01-30 20:10:51 +01:00
Fabio Berger
da1071526f Add browser data to dialog info 2018-01-30 19:03:10 +01:00
Leonid Logvinov
7ad314472d Change order 2018-01-30 16:33:52 +01:00
Leonid Logvinov
4f6168a982 Separate npm scripts in contracts 2018-01-30 16:01:37 +01:00
Leonid Logvinov
218a872968 Remove a semicolon 2018-01-30 16:01:37 +01:00
Leonid Logvinov
0043c5e1ac Fix glob patterns 2018-01-30 16:01:37 +01:00
Leonid Logvinov
d0e7046a89 Remove constructor arg 2018-01-30 16:01:37 +01:00
Leonid Logvinov
52ad16b920 Remove authorized address magic from tests 2018-01-30 16:01:37 +01:00
Leonid Logvinov
5a4c0bff6a Remove accounts magic from tests 2018-01-30 16:01:37 +01:00
Leonid Logvinov
6205209fbb Make an RPC constructor param implicit 2018-01-30 16:01:37 +01:00
Leonid Logvinov
6ebf8a57d1 Remove no-unused-variabe rule 2018-01-30 16:01:37 +01:00
Leonid Logvinov
c02dfc4fb1 Fix tslint issues 2018-01-30 16:01:37 +01:00
Leonid Logvinov
9d62e5fb6f Use an enum for contract name 2018-01-30 16:01:37 +01:00
Leonid Logvinov
6f13d107c4 Remove promisified web3 functions from tests 2018-01-30 16:01:37 +01:00
Leonid Logvinov
e56b2ceebb Remove truffle as a dependency 2018-01-30 16:01:37 +01:00
Leonid Logvinov
7de244ed62 Fix prettier 2018-01-30 16:01:37 +01:00
Leonid Logvinov
1e9147b8bb Normalize the dependencies 2018-01-30 16:01:37 +01:00
Leonid Logvinov
2f65fadeaa Add --bail to mocha config 2018-01-30 16:01:37 +01:00
Leonid Logvinov
a17091b394 Make awaitTransactionMinedAsync non-generic again 2018-01-30 16:01:36 +01:00
Leonid Logvinov
ed77c6cb54 Add back the artifacts 2018-01-30 16:01:36 +01:00
Leonid Logvinov
bc37cc8a91 Remove duplicate code 2018-01-30 16:01:36 +01:00
Leonid Logvinov
387363283c Remove truffle from tests 2018-01-30 16:01:36 +01:00
Leonid Logvinov
709026bf1a Refactor contracts tests to not use injected web3 instance 2018-01-30 16:01:36 +01:00
Leonid Logvinov
f2b2b86786 Remove truffle from Exchange tests 2018-01-30 16:01:36 +01:00
Leonid Logvinov
d0fbea76d8 Remove truffle from ZRXToken tests 2018-01-30 16:01:36 +01:00
Leonid Logvinov
8269610a5c Remove truffle from UnlimitedAllowanceToken tests 2018-01-30 16:01:36 +01:00
Leonid Logvinov
20c88a46d9 Remove truffle from UnlimitedAllowanceTokenV2 tests 2018-01-30 16:01:36 +01:00
Leonid Logvinov
661029f7cc Remove truffle from TokenRegistry tests 2018-01-30 16:01:36 +01:00
Leonid Logvinov
850d32d60c Remove truffle from MultiSigWalletWithTimeLock tests 2018-01-30 16:01:36 +01:00
Leonid Logvinov
eb881b9729 Remove truffle from MultiSigWalletWithTimeLockExceptRemoveAuthAddr tests 2018-01-30 16:01:36 +01:00
Leonid Logvinov
091ba473ff Remove truffle from Ether Token tests 2018-01-30 16:01:36 +01:00
Leonid Logvinov
fca051c565 Remove truffle from tokenTransferProxy tests 2018-01-30 16:01:35 +01:00
Leonid Logvinov
6463cda204 Remove truffle from tokenTransferProxy tests 2018-01-30 16:01:35 +01:00
Leonid Logvinov
d004df56e3 Prettierignore package.json 2018-01-30 16:00:29 +01:00
Leonid Logvinov
359dd482c4 Enable solidity syntax highlighting 2018-01-30 15:46:37 +01:00
Fabio Berger
89e98240b4 Add Rinkeby support 2018-01-30 15:05:55 +01:00
Fabio Berger
8d30058a6d Pass in whether we want the personal message prefix appended and never append it for Ledger. This fixes signing when Ledger is used and the backing node is not Parity 2018-01-30 14:19:58 +01:00
Fabio Berger
69151c06e4 Merge branch 'development' into feature/portal-ledger-support
* development:
  Publish
  Add PR number
  Add config file specifically in prettier command and fix files
  Fix prettier
  Fix prettier
  Add shouldAddPersonalMessagePrefix param to signOrderHashAsync instead of trying to infer whether to add it or not from the nodeVersion
  Publish
  Move @0xproject/types to dependencies
  Updated web3-typescript-typings changelog
  Fixed getTransactionReceipt not returning null
  Run prettier
  Update changelog
  Add Rinkeby addresses to artifacts
  Fix bad merge on package.json
  Respond to GH comments and add /info endpoint
  Change package name to @0xproject/testnet-faucets
  Implement testnet faucets for any testnet available via infura
  Rename to testnet-faucets
  Add to the Pull Request Template
  Create an ISSUE TEMPLATE
2018-01-30 14:00:35 +01:00
Fabio Berger
2e3c02887e Publish
- 0x.js@0.31.0
 - @0xproject/abi-gen@0.1.5
 - @0xproject/assert@0.0.14
 - chai-as-promised-typescript-typings@0.0.7
 - @0xproject/connect@0.5.3
 - contracts@2.1.7
 - @0xproject/deployer@0.0.4
 - @0xproject/dev-utils@0.0.8
 - @0xproject/json-schemas@0.7.6
 - @0xproject/monorepo-scripts@0.1.7
 - @0xproject/subproviders@0.3.4
 - @0xproject/testnet-faucets@1.0.8
 - @0xproject/tslint-config@0.4.5
 - @0xproject/types@0.1.7
 - @0xproject/utils@0.2.3
 - web3-typescript-typings@0.9.7
 - @0xproject/web3-wrapper@0.1.8
 - @0xproject/website@0.0.10
2018-01-30 13:54:36 +01:00
Fabio Berger
7603cef308 Merge pull request #349 from 0xProject/fix/0x.js/signOrderHash
Add shouldAddPersonalMessagePrefix param to signOrderHashAsync
2018-01-30 13:45:44 +01:00
Fabio Berger
be370c4e19 Add PR number 2018-01-30 13:45:20 +01:00
Fabio Berger
c6dece6bd1 Add config file specifically in prettier command and fix files 2018-01-30 13:26:46 +01:00
Fabio Berger
93a5b3f457 Fix prettier 2018-01-30 13:21:01 +01:00
Fabio Berger
4242176d29 Fix prettier 2018-01-30 13:16:31 +01:00
Fabio Berger
1cadbeed88 Add shouldAddPersonalMessagePrefix param to signOrderHashAsync instead of trying to infer whether to add it or not from the nodeVersion 2018-01-30 12:38:44 +01:00
Fabio Berger
86cc011212 Wholesale replace the tokenByAddress and de-dup properly 2018-01-30 11:16:13 +01:00
Fabio Berger
c0facfc28f Call destroy ealier so that web3Wrapper stops polling for userAddress/networkId updates before we prep for the batchDispatch 2018-01-30 11:15:36 +01:00
Jacob Evans
ad52a82190 Merge pull request #335 from 0xProject/feature/issue-template
Issue/Pull Request Template
2018-01-30 11:34:41 +11:00
Leonid Logvinov
60b6ed514f Publish
- 0x.js@0.30.2
 - @0xproject/abi-gen@0.1.4
 - @0xproject/assert@0.0.13
 - chai-as-promised-typescript-typings@0.0.6
 - @0xproject/connect@0.5.2
 - contracts@2.1.6
 - @0xproject/deployer@0.0.3
 - @0xproject/dev-utils@0.0.7
 - @0xproject/json-schemas@0.7.5
 - @0xproject/monorepo-scripts@0.1.6
 - @0xproject/subproviders@0.3.3
 - @0xproject/testnet-faucets@1.0.7
 - @0xproject/tslint-config@0.4.4
 - @0xproject/types@0.1.6
 - @0xproject/utils@0.2.2
 - web3-typescript-typings@0.9.6
 - @0xproject/web3-wrapper@0.1.7
 - @0xproject/website@0.0.9
2018-01-29 21:19:40 +01:00
Leonid Logvinov
ef32822b31 Move @0xproject/types to dependencies 2018-01-29 21:16:10 +01:00
Fabio Berger
bb0cedd2de Disallow negative amounts 2018-01-29 18:35:06 +01:00
Fabio Berger
8175c7c085 Remove the ability to clear tokenByAddress. It should simply be updated. 2018-01-29 17:56:35 +01:00
Fabio Berger
5c2d725721 Use live backend on development 2018-01-29 16:38:30 +01:00
Fabio Berger
72571628da Fetch default gasPrice from our ethGasStation API mirror and set it for all transactions 2018-01-29 16:38:05 +01:00
Fabio Berger
fa6130c907 remove unused type 2018-01-29 14:10:57 +01:00
Fabio Berger
8ccdd54974 Small improvements 2018-01-29 13:57:05 +01:00
Fabio Berger
6c1409b00d Fix bug related to balance/allowance fetching being async 2018-01-29 13:25:51 +01:00
Fabio Berger
542a1a11b9 Add missing entries for Ropsten and Rinkeby testnets, added Ropsten to Ledger network dropdown 2018-01-29 13:16:40 +01:00
Fabio Berger
63ffa80c5c Re-set Ledger config dialog to connect step if dialog is closed 2018-01-29 12:46:07 +01:00
Fabio Berger
609342be7a Add flash message instructing user to confirm tx on Ledger 2018-01-29 12:45:50 +01:00
Fabio Berger
52394884da Add the stack trace to help with debugging 2018-01-29 12:11:05 +01:00
Fabio Berger
af08177f79 Make it such that users can switch between Ledger accounts without first switching back to an injected provider 2018-01-29 12:10:49 +01:00
Fabio Berger
45fdfc2d3d Use colors module and remove in-lined colors 2018-01-29 10:55:53 +01:00
Fabio Berger
d18554e0e8 Replace heavy loading animation with simple circular loader 2018-01-29 10:46:15 +01:00
Fabio Berger
3c3f9ca85b Add network name to the select provider 2018-01-29 10:44:30 +01:00
Fabio Berger
005a02efeb Fix bug where could not switch to Ledger and back 2018-01-28 17:45:20 +01:00
Fabio Berger
6206ebc994 Implement just-in-time loading of token balances & allowances 2018-01-28 16:19:55 +01:00
Fabio Berger
dd9f5adc2e Initial Ledger support implementation 2018-01-28 10:29:15 +01:00
Fabio Berger
748d805a32 Remove unused Ledgerco import 2018-01-28 10:28:53 +01:00
Fabio Berger
4b59bf01b3 Add light blue as our accent color 2018-01-28 10:28:34 +01:00
Fabio Berger
b4faa4851a Properly detect user signing cancellation on Metamask, Parity signer and Ledger 2018-01-28 10:28:17 +01:00
Olaf Tomalka
f37fcc147c Added PR # to the changelog of abi-gen 2018-01-26 18:30:10 +01:00
Olaf Tomalka
dc5694e544 Added CLI options for explicit specifying location of partials and main template 2018-01-26 18:22:32 +01:00
Amir Bandeali
e588f6f8c3 Merge pull request #338 from joincivil/feature/transaction-receipt
Fix getTransactionReceipt not returning null
2018-01-26 09:04:18 -08:00
Olaf Tomalka
d227f2ad7c Updated web3-typescript-typings changelog 2018-01-25 23:53:38 +01:00
Olaf Tomalka
97c228031a Fixed getTransactionReceipt not returning null 2018-01-25 23:52:24 +01:00
Amir Bandeali
ad85011d62 Merge pull request #337 from 0xProject/feature/0x.js/update-artifacts
Add Rinkeby addresses to artifacts
2018-01-25 12:03:58 -08:00
Amir Bandeali
a70379625d Run prettier 2018-01-25 10:55:06 -08:00
Amir Bandeali
7350333129 Update changelog 2018-01-25 10:53:44 -08:00
Amir Bandeali
216420fdc5 Add Rinkeby addresses to artifacts 2018-01-25 10:53:44 -08:00
Brandon Millman
c559fbbe8c Merge pull request #339 from 0xProject/feature/kovan-faucets/all-testnet-support
Add support for all testnets to the faucet
2018-01-25 10:48:41 -08:00
Fabio Berger
71d68f975c 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
2018-01-25 16:42:58 +01:00
Brandon Millman
390534497e Fix bad merge on package.json 2018-01-24 22:33:33 -08:00
Brandon Millman
3f0ec89f11 Merge branch 'development' into feature/kovan-faucets/all-testnet-support
* development:
  Publish
  Update yarn.lock
  Update the CHANGELOG
  Fix the bug making it impossible to specify the custom ZRX address
2018-01-24 17:13:16 -08:00
Brandon Millman
d3aa4f2bc7 Respond to GH comments and add /info endpoint 2018-01-24 17:11:14 -08:00
Leonid Logvinov
f58f0ddb67 Publish
- 0x.js@0.30.1
 - @0xproject/abi-gen@0.1.3
 - @0xproject/assert@0.0.12
 - chai-as-promised-typescript-typings@0.0.5
 - @0xproject/connect@0.5.1
 - contracts@2.1.5
 - @0xproject/deployer@0.0.2
 - @0xproject/dev-utils@0.0.6
 - @0xproject/json-schemas@0.7.4
 - @0xproject/kovan_faucets@1.0.6
 - @0xproject/monorepo-scripts@0.1.5
 - @0xproject/subproviders@0.3.2
 - @0xproject/tslint-config@0.4.3
 - @0xproject/types@0.1.5
 - @0xproject/utils@0.2.1
 - web3-typescript-typings@0.9.5
 - @0xproject/web3-wrapper@0.1.6
 - @0xproject/website@0.0.8
2018-01-24 17:02:13 +01:00
Leonid Logvinov
633e3129d4 Update yarn.lock 2018-01-24 17:01:27 +01:00
Leonid
877bdce4c8 Merge pull request #341 from 0xProject/fix/zrx-address
Fix the bug making it impossible to specify the custom ZRX address
2018-01-24 15:25:29 +01:00
Leonid Logvinov
6e1fbd2d97 Update the CHANGELOG 2018-01-24 15:20:03 +01:00
Leonid Logvinov
36bfe62a8f Fix the bug making it impossible to specify the custom ZRX address 2018-01-24 15:17:56 +01:00
Brandon Millman
b08bd0f9ab Change package name to @0xproject/testnet-faucets 2018-01-23 18:02:30 -08:00
Brandon Millman
3998b47d84 Implement testnet faucets for any testnet available via infura 2018-01-23 17:42:35 -08:00
Brandon Millman
d965fdb11d Rename to testnet-faucets 2018-01-23 10:10:43 -08:00
Jacob Evans
ddb64b3ec1 Add to the Pull Request Template 2018-01-23 14:43:25 +11:00
Jacob Evans
5055ec8617 Create an ISSUE TEMPLATE 2018-01-23 14:31:10 +11:00
Fabio Berger
8a858501f2 Fix fill/cancel order by looking for NoError instead of empty blockchainErr given the BlockchainErrs type refactor 2018-01-21 17:48:32 +01:00
Leonid
e1af25c8a6 Merge pull request #323 from 0xProject/feature/separate-deployer
Move deployer to a separate package
2018-01-19 13:43:32 +01:00
Leonid
6091f818da Merge branch 'development' into feature/separate-deployer 2018-01-19 13:39:57 +01:00
Leonid Logvinov
a45f9b4802 Add a comment about a yarn bug 2018-01-19 13:37:41 +01:00
Fabio Berger
9ccf63b44a Add our mainnet and kovan nodes as backups for Portal requests 2018-01-19 11:33:35 +08:00
Fabio Berger
d34135ae43 Fix bug hiding the user info from topBar 2018-01-19 11:26:03 +08:00
Jacob Evans
a81f6f9ad1 Merge pull request #328 from 0xProject/fix/website/alphanumeric-token-symbol
Allow Token symbols to be alphanumeric
2018-01-19 13:41:29 +11:00
Brandon Millman
8a80b10cc2 Add dev-utils package to top level README 2018-01-18 17:23:29 -08:00
Jacob Evans
22b1ee132a Merge pull request #324 from 0xProject/fix/0x.js/negativeFillValues
Reject negative amounts in public methods
2018-01-19 12:19:14 +11:00
Jacob Evans
ab7f681f15 Prettier newline 2018-01-19 11:35:02 +11:00
Jacob Evans
2ac806ef08 Prettier 2018-01-19 10:51:57 +11:00
Jacob Evans
13ec8ed03c Allow Token symbols to be alphanumeric 2018-01-19 10:42:37 +11:00
Jacob Evans
fb77817c2d Update CHANGELOG, rebase on development 2018-01-19 10:33:25 +11:00
Jacob Evans
ceb8a492b1 Should not -> cannot 2018-01-19 10:31:06 +11:00
Jacob Evans
cfc868bf4d Reject negative amounts in isValidBaseUnitAmount 2018-01-19 10:31:06 +11:00
Fabio Berger
7b4e2257d8 Re-add changelog for 0x.js 2018-01-19 10:31:06 +11:00
Brandon Millman
4ac6e5477d Merge pull request #326 from 0xProject/greenkeeper/@0xproject/utils-0.2.0
Update @0xproject/utils to the latest version 🚀
2018-01-18 14:50:15 -08:00
Leonid Logvinov
614ea14a7f Fix prettier 2018-01-18 16:18:25 +01:00
Leonid Logvinov
ce45f99006 Update yarn.lock 2018-01-18 15:58:46 +01:00
Leonid
9203813a61 Merge pull request #325 from 0xProject/fix/portal-bugs
Small Fixes/Additions
2018-01-18 15:27:01 +01:00
Leonid Logvinov
ba987b0574 Move tests to a separate folder 2018-01-18 15:17:17 +01:00
Leonid Logvinov
b20f34adb7 Change file layout 2018-01-18 15:12:56 +01:00
Leonid Logvinov
63d0d810b1 Add bin definition 2018-01-18 14:44:53 +01:00
Leonid Logvinov
5491400684 Add postpublish scripts and README 2018-01-18 14:43:10 +01:00
Leonid Logvinov
6a5165e9b3 Fix a link 2018-01-18 14:39:41 +01:00
Leonid Logvinov
9a7c4442d2 Fix scopes 2018-01-18 14:34:35 +01:00
Leonid Logvinov
0e5363b5c3 Update yarn.lock 2018-01-18 14:26:32 +01:00
Leonid Logvinov
d41bce36be Fix merge conflicts 2018-01-18 14:23:54 +01:00
Leonid Logvinov
1380cd811e Fix CI config 2018-01-18 14:22:49 +01:00
Leonid Logvinov
d99bb3a87c Fix merge conflicts 2018-01-18 14:21:15 +01:00
Leonid Logvinov
4b9501318d Move deployer to a separate package 2018-01-18 14:18:51 +01:00
Leonid
e5eec04f92 Merge pull request #322 from 0xProject/fix/ci-time
Speed-up CI
2018-01-18 14:16:53 +01:00
Fabio Berger
f9c21efc30 Use intervalUtils.clearAsyncExcludingInterval instead of calling clearInterval directly for grepability 2018-01-18 19:29:54 +08:00
greenkeeper[bot]
ae72b71895 chore(package): update @0xproject/utils to version 0.2.0 2018-01-18 10:09:13 +00:00
Brandon Millman
87e3fe725d Run prettier to revert formatting changes made by the lerna publish step 2018-01-18 00:21:52 -08:00
Fabio Berger
807d9e3eef Add discourse forum to Community section of website footer 2018-01-18 15:20:34 +08:00
Fabio Berger
9e569b3791 Remove dead-code 2018-01-18 15:20:15 +08:00
Fabio Berger
024f093585 Fix Portal topbar so that it displays the mobile menu 2018-01-18 15:02:53 +08:00
Fabio Berger
996e9e9102 Add missing onError callbacks 2018-01-18 15:02:36 +08:00
Brandon Millman
d58bfb46cf Publish
- 0x.js@0.30.0
 - @0xproject/abi-gen@0.1.2
 - @0xproject/assert@0.0.11
 - chai-as-promised-typescript-typings@0.0.4
 - chai-typescript-typings@0.0.2
 - @0xproject/connect@0.5.0
 - contracts@2.1.4
 - @0xproject/dev-utils@0.0.5
 - @0xproject/json-schemas@0.7.3
 - @0xproject/kovan_faucets@1.0.5
 - @0xproject/monorepo-scripts@0.1.4
 - @0xproject/subproviders@0.3.1
 - @0xproject/tslint-config@0.4.2
 - @0xproject/types@0.1.4
 - @0xproject/utils@0.2.0
 - web3-typescript-typings@0.9.4
 - @0xproject/web3-wrapper@0.1.5
 - @0xproject/website@0.0.7
2018-01-17 22:45:09 -08:00
Fabio Berger
eb0d7df50b Fix balance page copy to refer to the Wrap ETH tab instead of a "convert" button 2018-01-18 14:27:12 +08:00
Brandon Millman
547bee38c0 Update CHANGELOG 2018-01-17 21:55:04 -08:00
Leonid
60614ba250 Merge pull request #321 from 0xProject/fix/fill-up-to-validation
Fix fillOrdersUpTo validation
2018-01-17 23:56:08 +01:00
Leonid Logvinov
278f68ae77 Fix the typos 2018-01-17 16:22:47 +01:00
Leonid Logvinov
b4375d6f64 Enable restrict-plus-operands and fix issues detected 2018-01-17 16:14:25 +01:00
Leonid Logvinov
9f47c72d31 Remove unused dependencies 2018-01-17 16:07:49 +01:00
Leonid Logvinov
de3bf03f42 Add --frozen-lockfile flag on CI 2018-01-17 15:55:58 +01:00
Leonid Logvinov
59a39ac57d Fix a stupid RPC bug which caused the port togo over 65535 2018-01-17 15:35:14 +01:00
Leonid Logvinov
df9c2b193e Remove trailing slash 2018-01-16 21:28:26 +01:00
Leonid Logvinov
3894311d68 Test deployer separately from contracts 2018-01-16 21:11:30 +01:00
Leonid Logvinov
35501dd4fc Fix ignore configuration 2018-01-16 16:17:20 +01:00
Leonid Logvinov
e2ca713658 Fix the glob pattern for exclusion 2018-01-16 16:03:06 +01:00
Leonid Logvinov
a45de6d427 Return is pensing events are undefined 2018-01-16 15:50:15 +01:00
Leonid Logvinov
a350638526 Upgrade testrpc to 6.0.3 to avoid some race-conditions 2018-01-16 15:40:20 +01:00
Leonid Logvinov
59f9605ed9 Run testrpc for rest tests 2018-01-16 15:26:15 +01:00
Leonid Logvinov
9521bf8d4f Separate contracts tests from others 2018-01-16 15:20:15 +01:00
Leonid Logvinov
7c1c94d39b Change cached directory 2018-01-16 14:36:04 +01:00
Leonid Logvinov
8a74963815 Respore dependency cache 2018-01-16 14:31:28 +01:00
Leonid Logvinov
3ebd8b7f45 Revert "Don't run testrpc for the rest of the tests"
This reverts commit ae8cb2e6a8.
2018-01-16 14:11:17 +01:00
Leonid Logvinov
ae8cb2e6a8 Don't run testrpc for the rest of the tests 2018-01-16 14:05:11 +01:00
Leonid Logvinov
1ccb978612 Split tests into two bundles 2018-01-16 14:04:02 +01:00
Leonid Logvinov
7040a01cf2 Remove umd tests 2018-01-16 14:01:46 +01:00
Leonid Logvinov
6bc0e815e9 Add caching between steps 2018-01-16 13:54:13 +01:00
Leonid Logvinov
593f7e826c Specify the executor 2018-01-16 13:45:36 +01:00
Leonid Logvinov
835fa0af13 Test workflow 2018-01-16 13:44:38 +01:00
Leonid
0e3bd0c6c1 Merge pull request #320 from joincivil/feature/default-account
Fix web3 typing defaultAccount not allowing `undefined`
2018-01-16 13:34:14 +01:00
Olaf Tomalka
86668eb7b9 Added PR number to web3 typings changelog 2018-01-16 13:24:53 +01:00
Leonid Logvinov
771f65c858 Update the CHANGELOG 2018-01-16 11:25:31 +01:00
Leonid Logvinov
89d6326a83 Fix fillOrdersUpTo balances validation 2018-01-16 11:22:04 +01:00
Leonid Logvinov
8b81ea162f Add a regression test for fillUpToValidation 2018-01-16 11:08:17 +01:00
Olaf Tomalka
a53e6db537 Fix web3 typing defaultAccount not allowing undefined
The default value for the defaultAccount property is undefined,
this happens in real-life scenarios, and so the type should
explicitly warn users about it
2018-01-15 16:02:42 +01:00
Leonid
62e3feeb94 Merge pull request #319 from 0xProject/feature/final-monorepo
Import last TS packages into the monorepo
2018-01-13 02:03:22 +01:00
Leonid
a950494503 Merge pull request #312 from 0xProject/feature/error-reporting-intervals
Better error handling on async/sync intervals
2018-01-13 00:51:23 +01:00
Leonid Logvinov
3cb310122e Sort packages alphabetically in README 2018-01-13 00:50:07 +01:00
Leonid Logvinov
feace988b4 Add postpublish scripts 2018-01-12 22:16:45 +01:00
Leonid Logvinov
6a56f20928 Return after checking for an error and add an explanatory comment 2018-01-12 21:39:51 +01:00
Brandon Millman
80a46d14be Merge pull request #318 from 0xProject/feature/httpClientErrorImprovements
Improve HttpClient errors
2018-01-12 12:18:03 -08:00
Brandon Millman
fbcbf066cd Stop appending /v0 to HttpClient api endpoint urls 2018-01-12 11:53:14 -08:00
Leonid Logvinov
4d30e1115f Add chai-as-promised-typescript-typings 2018-01-12 17:48:15 +01:00
Leonid Logvinov
897cfb491c Remove redundant type refs 2018-01-12 17:23:59 +01:00
Brandon Millman
c2c7512431 Improve HttpClient errors 2018-01-12 08:01:41 -08:00
Leonid Logvinov
568cf4d182 Add web3-typescript-typings and chai-as-promised-typescript-typings to the main monorepo 2018-01-12 16:55:16 +01:00
Leonid Logvinov
f54330f1c5 Import chai-as-promised-typescript-typings 2018-01-12 16:49:48 +01:00
Leonid Logvinov
97e01d7a42 Fix @bmilman linkedin link 2018-01-12 15:32:29 +01:00
Leonid
4be3e000e1 Merge pull request #317 from 0xProject/feature/new-team-members
[WIP] Add @tom and @dekz while removing @PhABC
2018-01-12 15:25:05 +01:00
Leonid Logvinov
b47baa9ee1 Add new team photos 2018-01-12 15:22:44 +01:00
Leonid Logvinov
f6c98112df Add a CHANGELOG to a website 2018-01-11 17:45:51 +01:00
Leonid Logvinov
94d29ab22e Add @tom and @dekz while removing @PhABC 2018-01-11 17:45:51 +01:00
Leonid Logvinov
b0b179550a Prettify package.json files 2018-01-11 17:45:36 +01:00
Leonid Logvinov
41c7ab4f9c Update dependencies in yarn.lock 2018-01-11 17:38:22 +01:00
Leonid Logvinov
432c7c63fe Fix a version in web3-typescript-typings CHANGELOG 2018-01-11 14:44:30 +01:00
Leonid Logvinov
2bba1ae292 Publish
- 0x.js@0.29.2
 - @0xproject/abi-gen@0.1.1
 - @0xproject/connect@0.4.1
 - contracts@2.1.3
 - @0xproject/kovan_faucets@1.0.4
 - web3-typescript-typings@0.9.3
 - @0xproject/web3-wrapper@0.1.4
 - @0xproject/website@0.0.6
2018-01-11 14:43:58 +01:00
Leonid Logvinov
7830d518e0 Add types for getData on a web3 contract 2018-01-11 14:40:16 +01:00
Leonid Logvinov
571b3c4da8 Add types for getData on a web3 contract 2018-01-11 14:25:49 +01:00
Leonid Logvinov
5b6f8d4c3f Apply prettier 2018-01-11 13:44:01 +01:00
Leonid Logvinov
ae57b21b98 Update the CHANGELOG 2018-01-11 13:22:37 +01:00
Leonid Logvinov
292c3bbff8 Make some callbacks failable and add error handling 2018-01-11 13:22:04 +01:00
Leonid Logvinov
065570ebf5 Add an error handler parameter to intervals 2018-01-11 13:22:04 +01:00
Leonid Logvinov
1f5dfd71d5 Add forgotten CHANGELOG changes 2018-01-11 13:16:58 +01:00
Leonid Logvinov
31b3ac4b98 Publish
- 0x.js@0.29.1
 - @0xproject/abi-gen@0.1.0
 - @0xproject/assert@0.0.10
 - @0xproject/connect@0.4.0
 - contracts@2.1.2
 - @0xproject/dev-utils@0.0.4
 - @0xproject/json-schemas@0.7.2
 - @0xproject/kovan_faucets@1.0.3
 - @0xproject/monorepo-scripts@0.1.3
 - @0xproject/subproviders@0.3.0
 - @0xproject/tslint-config@0.4.1
 - @0xproject/types@0.1.3
 - @0xproject/utils@0.1.3
 - web3-typescript-typings@0.9.1
 - @0xproject/web3-wrapper@0.1.3
 - @0xproject/website@0.0.5
2018-01-11 13:05:49 +01:00
Leonid Logvinov
7f4a383d75 Update CHANGELOGs before publish 2018-01-11 13:03:38 +01:00
Leonid
de943c5f30 Merge pull request #307 from 0xProject/feature/web3-type-roots
Base tsconfig.json
2018-01-10 19:35:37 +01:00
Leonid Logvinov
e34b0af251 Fix ts error in portal after enabling more strict checks 2018-01-10 12:43:50 +01:00
Leonid Logvinov
fa7237fde7 Fix a compiler error in abi-gen 2018-01-10 12:00:39 +01:00
Leonid Logvinov
ed530cef72 Reinstall dependencies to get a new version of marked and get rid of GitHub warning about 0.3.6 being vulnerable 2018-01-10 11:36:14 +01:00
Leonid Logvinov
0f8b2703d1 Fix a compiler error with constructor enum 2018-01-10 11:28:43 +01:00
Leonid Logvinov
a2176f566b Update README 2018-01-10 11:24:38 +01:00
Leonid Logvinov
bef056b084 Fix linter issues 2018-01-10 11:24:38 +01:00
Leonid Logvinov
c8c86c44f8 Fix callback types 2018-01-10 11:24:37 +01:00
Leonid Logvinov
f917a4a34a Remove typeRoots 2018-01-10 11:24:37 +01:00
Leonid Logvinov
78fd942faa Return to old way of including web3 types 2018-01-10 11:24:37 +01:00
Leonid Logvinov
a3274ac9b1 Import web3-typescript-typings to monorepo 2018-01-10 11:24:37 +01:00
Leonid Logvinov
2e67d69434 0.9.0 2018-01-10 11:24:37 +01:00
Leonid Logvinov
c2d6e78b2a Manually apply #14 2018-01-10 11:24:37 +01:00
Olaf Tomalka
7233a11ba0 Added stateMutability to ABIs
In the newest version of Solidity, additional property was added,
called state mutability, specyfing what kind of access does the
function have to memory and storage.
Additionally, constructor mutability is limited to payable/non-payable
as it HAS to modify the storage to actually deploy the contract
2018-01-10 11:24:37 +01:00
Leonid Logvinov
3a1360ce11 0.8.0 2018-01-10 11:24:37 +01:00
Leonid Logvinov
ba761044a6 Fix types definition in package.json 2018-01-10 11:24:37 +01:00
Leonid Logvinov
d8636a2c5d 0.7.2 2018-01-10 11:24:37 +01:00
Olaf Tomalka
9889c8f9e0 Fix ContractInstance new() not parsing properly
new is a keyword in typescript and so if a function is called new(),
tsc and for example Visual Studio Code don't regonize types for this
function. The fix is to write this function in quotes
2018-01-10 11:24:37 +01:00
Olaf Tomalka
7e2e392ecc Made the callback in filter.stopWatching optional 2018-01-10 11:24:37 +01:00
Amir Bandeali
6912a67eba Add new to contract interface 2018-01-10 11:24:37 +01:00
Amir Bandeali
6abc83de83 fix typo 2018-01-10 11:24:37 +01:00
Leonid Logvinov
0ca66a1469 0.7.1 2018-01-10 11:24:37 +01:00
Leonid Logvinov
a88be1af44 Make transactionIndex nullable 2018-01-10 11:24:36 +01:00
Leonid Logvinov
ae47fda257 0.7.0 2018-01-10 11:24:36 +01:00
Leonid Logvinov
6eb5411029 Improve log events types 2018-01-10 11:24:36 +01:00
Leonid Logvinov
73d13d61a7 0.6.4 2018-01-10 11:24:36 +01:00
Leonid Logvinov
fdf213ef72 Constraint status type 2018-01-10 11:24:36 +01:00
Leonid Logvinov
22fe605b1e 0.6.3 2018-01-10 11:24:36 +01:00
Leonid Logvinov
bcc902a889 Add status to a transaction receipt 2018-01-10 11:24:36 +01:00
Sergey Ukustov
24ff2ec30c Add async web3.personal.sign 2018-01-10 11:24:36 +01:00
Sergey Ukustov
4e0c67e2a1 Fix indentation 2018-01-10 11:24:36 +01:00
Leonid Logvinov
0cc21db654 0.6.2 2018-01-10 11:24:36 +01:00
Leonid Logvinov
dd5d1c00e5 Make all parameters of FilterObject optional 2018-01-10 11:24:36 +01:00
Leonid Logvinov
cad2555c03 0.6.1 2018-01-10 11:24:36 +01:00
Leonid Logvinov
005d8184aa Add LogTopic type 2018-01-10 11:24:36 +01:00
Leonid Logvinov
c228eddc57 0.6.0 2018-01-10 11:24:36 +01:00
Leonid Logvinov
ae37f8d9b6 Define sendAsync on HttpProvider 2018-01-10 11:24:36 +01:00
Leonid Logvinov
6a8113af1d 0.5.0 2018-01-10 11:24:35 +01:00
Leonid Logvinov
0c8cf12650 Add AbiType 2018-01-10 11:24:35 +01:00
Leonid Logvinov
2e29a51ccf 0.4.1 2018-01-10 11:24:35 +01:00
Leonid Logvinov
162f1d94dc Add ContractInstance type 2018-01-10 11:24:35 +01:00
Leonid Logvinov
a76bce1f32 0.4.0 2018-01-10 11:24:35 +01:00
Leonid Logvinov
be20e04c7b Extend Abi types 2018-01-10 11:24:35 +01:00
Leonid Logvinov
d9df82f31d 0.3.4 2018-01-10 11:24:35 +01:00
Leonid Logvinov
6210333628 Add return type for sendAsync 2018-01-10 11:24:35 +01:00
Leonid Logvinov
a552a790d3 0.3.3 2018-01-10 11:24:35 +01:00
Leonid Logvinov
9acb745956 Add sendAsync types in provider 2018-01-10 11:24:35 +01:00
Leonid Logvinov
875edaf96f 0.3.2 2018-01-10 11:24:35 +01:00
Leonid Logvinov
a9afc0f3f0 Add Web3.isChecksumAddress 2018-01-10 11:24:35 +01:00
Leonid Logvinov
3bbeaabe26 0.3.1 2018-01-10 11:24:35 +01:00
libertylocked
c04cbb480a Add auth options to HttpProvider 2018-01-10 11:24:35 +01:00
Leonid Logvinov
2c241c294e Add tslint.json 2018-01-10 11:24:35 +01:00
Leonid Logvinov
ce851f3c28 0.3.0 2018-01-10 11:24:35 +01:00
Leonid Logvinov
817a6d1828 Fix linter errors 2018-01-10 11:24:35 +01:00
Leonid Logvinov
4d0735e7f6 Add linting script and specify style guide 2018-01-10 11:24:34 +01:00
Leonid Logvinov
80291930f0 Make error types consistent 2018-01-10 11:24:34 +01:00
Leonid Logvinov
cf8678b979 Introduce BlockWithoutTransactionData and BlockWithTransactionData 2018-01-10 11:24:34 +01:00
Leonid Logvinov
67722c0fb8 Add LogEntry type 2018-01-10 11:24:34 +01:00
Leonid Logvinov
0b6e246c04 Add web3.personal.sign 2018-01-10 11:24:34 +01:00
Leonid Logvinov
3992295678 Add a lot of types 2018-01-10 11:24:34 +01:00
Sergey Ukustov
da404b9acc Extract API interfaces: web3.version, web3.eth, web3.personal 2018-01-10 11:24:34 +01:00
Sergey Ukustov
da8db153be Optional provider parameter in Web3 constructor 2018-01-10 11:24:34 +01:00
Fabio Berger
2c90f7324b 0.2.1 2018-01-10 11:24:34 +01:00
Fabio Berger
2cdb0de1c3 Add missing semi-colon 2018-01-10 11:24:34 +01:00
Fabio Berger
66bd798e80 Add missing semi-colons 2018-01-10 11:24:34 +01:00
libertylocked
cf37dfb257 Add web3.eth.blockNumber 2018-01-10 11:24:34 +01:00
Sergey Ukustov
217f84204e Add web3.sha3 method declaration 2018-01-10 11:24:34 +01:00
Fabio Berger
fbbe0ec3db 0.2.0 2018-01-10 11:24:34 +01:00
Fabio Berger
1ec34767f9 0.1.0 2018-01-10 11:24:34 +01:00
Fabio Berger
14e94a5376 Use single instead of double quotes by convention 2018-01-10 11:24:34 +01:00
Fabio Berger
08508afdb2 Remove spaces between union types to remain stylistically consistent 2018-01-10 11:24:33 +01:00
Sergey Ukustov
4220f25e01 Constructor definition does not include name or constant modifier 2018-01-10 11:24:33 +01:00
Sergey Ukustov
4ff5afecc8 Revamp AbiDefinition 2018-01-10 11:24:33 +01:00
Sergey Ukustov
2eabb439d9 filter.stopWatching accepts callback 2018-01-10 11:24:33 +01:00
Sergey Ukustov
2bc9d5d490 filter.watch callback param accepts arguments 2018-01-10 11:24:33 +01:00
Leonid Logvinov
9e1c142f02 0.0.11 2018-01-10 11:24:33 +01:00
Leonid Logvinov
1a38893b52 Fix version typings 2018-01-10 11:24:33 +01:00
Leonid Logvinov
f28d75cf7c 0.0.10 2018-01-10 11:24:33 +01:00
Leonid Logvinov
a3c9d0ace5 Add at function to Contract class 2018-01-10 11:24:33 +01:00
Leonid Logvinov
aea1799a64 0.0.9 2018-01-10 11:24:33 +01:00
Leonid Logvinov
ef76c4c62b Make currentProvider a variable, not a function 2018-01-10 11:24:33 +01:00
Leonid Logvinov
210e7c5579 Flash out README with instructions 2018-01-10 11:24:33 +01:00
Fabio Berger
3fa0046542 0.0.8 2018-01-10 11:24:33 +01:00
Fabio Berger
d6754685cc remove default import 2018-01-10 11:24:33 +01:00
Fabio Berger
bb5721700b 0.0.7 2018-01-10 11:24:32 +01:00
Fabio Berger
5c4a1dcbd5 Move interface definitions into the web3 namespace 2018-01-10 11:24:32 +01:00
Fabio Berger
4f488dee61 0.0.6 2018-01-10 11:24:32 +01:00
Fabio Berger
0d33758104 0.0.5 2018-01-10 11:24:32 +01:00
Fabio Berger
15b5fcbaf9 Export all interfaces and export the web3 constructor as the default export 2018-01-10 11:24:32 +01:00
Fabio Berger
0718b0d5b0 0.0.4 2018-01-10 11:24:32 +01:00
Fabio Berger
0af2ba1b7d Move Provider type outside of namespace 2018-01-10 11:24:32 +01:00
Fabio Berger
ea2fdecb83 0.0.3 2018-01-10 11:24:32 +01:00
Fabio Berger
07eb250083 Allow numbers to also be passed to fromWei and toWei 2018-01-10 11:24:32 +01:00
Fabio Berger
ee04717e1b 0.0.2 2018-01-10 11:24:32 +01:00
Fabio Berger
d7d22c36ed Add toWei and getTransactionReceipt definitions 2018-01-10 11:24:32 +01:00
Fabio Berger
36bf91f920 0.0.1 2018-01-10 11:24:32 +01:00
Fabio Berger
98e9c3b800 Add getBlockNumber definition 2018-01-10 11:24:32 +01:00
Fabio Berger
a7f1137db8 Add bigNumber dependency 2018-01-10 11:24:32 +01:00
Fabio Berger
f86159e717 add node_modules to gitignore 2018-01-10 11:24:32 +01:00
Fabio Berger
6e93223ea3 Add license 2018-01-10 11:24:32 +01:00
Fabio Berger
a6d677043f Add gitignore 2018-01-10 11:24:31 +01:00
Fabio Berger
eb1bf198ac Add package.json 2018-01-10 11:24:31 +01:00
Fabio Berger
0a2f82a19d Add initial version of typings and README 2018-01-10 11:24:31 +01:00
Leonid Logvinov
27d9fba785 Include web3 types via typeRoots and factor out common parts of tsconfig.json 2018-01-10 11:24:31 +01:00
Leonid Logvinov
e6a783aff8 Apply prettier 2018-01-10 11:24:00 +01:00
Leonid Logvinov
a767c353d2 Merge branch 'fix/prettify_json' into development 2018-01-10 11:23:03 +01:00
Leonid
a39d3d7233 Merge pull request #305 from 0xProject/fix/bignumber_config
Use configured version of bignumber in all packages
2018-01-10 11:18:51 +01:00
Brandon Millman
40c7ee6355 Merge pull request #311 from 0xProject/fix/httpClientJsonParsing
Merge connect json parsing refactor into development
2018-01-09 14:38:33 -08:00
Brandon Millman
eb760aa33f Prettier 2018-01-09 14:19:33 -08:00
Brandon Millman
262c34abac Update style 2018-01-09 14:18:45 -08:00
Brandon Millman
8019b1b823 Merge branch 'development' into refactor/httpClientJsonParsing
* development: (21 commits)
  Update connect CHANGELOG
  Changes to abi-gen after code review
  Added constructor ABIs to abi-gen
  Describe #295 in a CHANGELOG
  Add #302 description to changelog
  Fix formatting
  Apply prettier config
  Install prettier
  Remove formatting esilnt rules
  sendTransactionAsync should return txHash string
  Added Event generation to abi-gen
  Publish
  Add dates to CHANGELOG entries
  Update subproviders CHANGELOG
  Support both personal_sign and eth_sign
  Fix Ledger tests given change from `personal_sign` to `eth_sign`
  Update subprovider to catch correct RPC method
  Rename guide
  Update contribution guide
  Fix broken links in the abi-gen README
  ...
2018-01-08 18:02:41 -08:00
Brandon Millman
7a56e83fa3 Merge pull request #296 from 0xProject/fix/mutatedInput
Prevent getFeesAsync method on HttpClient from mutating input
2018-01-08 16:57:59 -08:00
Brandon Millman
a1c38d9cb2 Update connect CHANGELOG 2018-01-08 16:47:33 -08:00
Brandon Millman
734cf5819a Merge branch 'development' into fix/mutatedInput
* development:
  Changes to abi-gen after code review
  Added constructor ABIs to abi-gen
  Describe #295 in a CHANGELOG
  Add #302 description to changelog
  Fix formatting
  Apply prettier config
  Install prettier
  Remove formatting esilnt rules
  sendTransactionAsync should return txHash string
  Added Event generation to abi-gen
  Publish
  Add dates to CHANGELOG entries
  Update subproviders CHANGELOG
  Support both personal_sign and eth_sign
  Fix Ledger tests given change from `personal_sign` to `eth_sign`
  Update subprovider to catch correct RPC method
  Rename guide
  Update contribution guide
  Fix broken links in the abi-gen README
  Fix typing generation for arrays in which types separated by |s
2018-01-08 16:35:12 -08:00
Leonid
35e0b6143a Merge pull request #304 from joincivil/ritave/feature/abi-gen-constructor
Added constructor ABIs to abi-gen
2018-01-05 12:49:51 +01:00
Olaf Tomalka
e019ae4aed Changes to abi-gen after code review
* Added change to CHANGELOG
* Renamed variable and context to ctor to avoid keyword
* Used lodash' isUndefined to better check ctor
2018-01-05 12:48:17 +01:00
Leonid Logvinov
c700046b76 Apply prettify on json and md files 2018-01-04 16:32:03 +01:00
Leonid Logvinov
326a6b729f Fix prettier 2018-01-04 16:31:46 +01:00
Leonid Logvinov
e2ef0c5b94 Fix linter errors 2018-01-04 15:12:32 +01:00
Leonid Logvinov
c49f68ef3e Fix linter errors 2018-01-04 14:53:38 +01:00
Leonid Logvinov
d0f66f8624 Merge imports 2018-01-04 12:55:22 +01:00
Leonid Logvinov
4dfa720f2d Use configured version of bignumber in all packages 2018-01-04 12:38:19 +01:00
Olaf Tomalka
f3b8bac477 Added constructor ABIs to abi-gen
Additionally if the constructor is not existent in JSON, meaning it's
implcite with no parameters, we're
explicitly creating one, with actual JSON parameters that it should have.
2018-01-03 15:48:29 +01:00
Leonid Logvinov
ce6abad97f Describe #295 in a CHANGELOG 2018-01-03 12:08:39 +01:00
Leonid
807e908f78 Merge pull request #295 from dharmaprotocol/fix-array-typing-generation
Fix array typing generation when permitting multiple types
2018-01-03 12:07:31 +01:00
Leonid Logvinov
94c75b5262 Add #302 description to changelog 2018-01-03 12:05:44 +01:00
Leonid
eb0dd6b6e9 Merge pull request #302 from joincivil/ritave/feature/abi-gen-events
Added Event generation to abi-gen
2018-01-03 12:02:06 +01:00
Leonid
1c542c3e0d Merge pull request #303 from ERCdEX/ercdex/send_transaction_return_txhash
_sendTransactionAsync should return txHash string
2018-01-03 11:53:37 +01:00
Leonid Logvinov
d46fcb33c5 Fix formatting 2018-01-03 11:42:20 +01:00
Leonid
d5e0da0eb6 Merge pull request #291 from 0xProject/feature/prettier
Use prettier
2018-01-03 11:39:08 +01:00
Leonid Logvinov
e744e4cd98 Apply prettier config 2018-01-03 11:37:38 +01:00
Leonid Logvinov
9a96e8c704 Install prettier 2018-01-03 11:37:38 +01:00
Leonid Logvinov
31a94f468e Remove formatting esilnt rules 2018-01-03 11:37:38 +01:00
Luke
7422b9b53b sendTransactionAsync should return txHash string 2018-01-02 23:41:48 -05:00
Olaf Tomalka
161a9d6ad2 Added Event generation to abi-gen 2017-12-30 16:13:32 +01:00
Fabio Berger
f684cc3711 Publish
- 0x.js@0.29.0
 - @0xproject/abi-gen@0.0.4
 - @0xproject/assert@0.0.9
 - @0xproject/connect@0.3.2
 - contracts@2.1.1
 - @0xproject/dev-utils@0.0.3
 - @0xproject/json-schemas@0.7.1
 - @0xproject/kovan_faucets@1.0.2
 - @0xproject/monorepo-scripts@0.1.2
 - @0xproject/subproviders@0.2.0
 - @0xproject/tslint-config@0.4.0
 - @0xproject/types@0.1.2
 - @0xproject/utils@0.1.2
 - @0xproject/web3-wrapper@0.1.2
 - @0xproject/website@0.0.4
2017-12-28 10:57:04 +01:00
Fabio Berger
ab0c8c3496 Add dates to CHANGELOG entries 2017-12-28 10:36:06 +01:00
Fabio Berger
47534b200d Update subproviders CHANGELOG 2017-12-28 10:29:52 +01:00
Fabio Berger
f2976af734 Support both personal_sign and eth_sign 2017-12-28 10:28:27 +01:00
Fabio Berger
ee463058f1 Fix Ledger tests given change from personal_sign to eth_sign 2017-12-28 09:46:50 +01:00
Fabio Berger
c36a7471a8 Merge pull request #300 from cavanmflynn/fix/ledger-subprovider-signing
Update subprovider to catch correct RPC method
2017-12-28 09:45:41 +01:00
Cavan Flynn
6ea8cee551 Update subprovider to catch correct RPC method
ZeroEx uses web3.eth.sign, rather than web3.eth.personal.sign. In addition, the message to sign is the second parameter; not the first. The first parameter is the address.
2017-12-27 19:48:58 -05:00
Fabio Berger
69806c8839 Rename guide 2017-12-25 17:54:24 +01:00
Fabio Berger
690036aa30 Update contribution guide 2017-12-25 17:53:18 +01:00
Brandon Millman
8fe81c9d09 Refactor JSON parsing in HttpClient 2017-12-24 21:01:28 -05:00
Brandon Millman
eda6b8d01b Fix broken links in the abi-gen README 2017-12-24 19:46:45 -05:00
Brandon Millman
9f3acf8e28 Prevent getFeesAsync method on HttpClient from mutating input 2017-12-24 19:02:01 -05:00
Nadav Hollander
31c9c82f6c Fix typing generation for arrays in which types separated by |s 2017-12-24 10:16:06 -08:00
Brandon Millman
cbf06b2165 Merge pull request #289 from 0xProject/fix/missingBigNumberConfigs
Add missing calls to bigNumberConfigs in packages where we are instan…
2017-12-21 21:04:50 -05:00
Fabio Berger
e884eb9882 Merge pull request #288 from 0xProject/fix/docLinks
Fix doc anchor link collisions
2017-12-21 22:45:22 +01:00
Brandon Millman
f8cbfea4a1 Remove unused import 2017-12-21 15:40:09 -05:00
Fabio Berger
e01c0f054d Merge branch 'development' into fix/docLinks
* development:
  Update and standardize contracts README
  Add to CHANGELOG
  Refactor toBaseUnitAmount so that it throws if user supplies unitAmount with too many decimals
  Make assertion stricter so that one cannot submit invalid baseUnit amounts to `toUnitAmount`
  Add some missed underscores, update changelog and comments
  Add new underscore-privates rule to @0xproject/tslint-config and fix lint errors

# Conflicts:
#	packages/website/ts/pages/documentation/documentation.tsx
#	packages/website/ts/pages/shared/nested_sidebar_menu.tsx
2017-12-21 21:24:54 +01:00
Brandon Millman
12dc8c0d15 Add missing calls to bigNumberConfigs in packages where we are instantiating BigNumbers 2017-12-21 14:55:55 -05:00
Brandon Millman
cb3582289f Merge pull request #285 from 0xProject/fix/underscorePrivate
Add new underscore-privates rule to @0xproject/tslint-config and fix …
2017-12-21 13:16:25 -05:00
Fabio Berger
734d220d60 Merge pull request #287 from 0xProject/fix/toBaseUnitAmount
Fix toBaseUnitAmount Issue
2017-12-21 18:22:28 +01:00
Fabio Berger
d725de7286 Create types sectionName constant 2017-12-21 17:28:20 +01:00
Fabio Berger
3e91773cd9 Add sectionName prefix to all anchor links in order to fix method name collisions between sections 2017-12-21 17:28:06 +01:00
Amir Bandeali
dc1d2a33a5 Merge pull request #286 from 0xProject/feature/updateContractsReadme
Update and standardize contracts README
2017-12-21 09:26:33 -06:00
Amir Bandeali
ac4074911d Update and standardize contracts README 2017-12-21 09:21:10 -06:00
Fabio Berger
66cf60f9cb Fix Max button bug 2017-12-21 15:32:23 +01:00
Fabio Berger
fffe8c355e Add to CHANGELOG 2017-12-21 14:40:18 +01:00
Fabio Berger
b94d13b413 Refactor toBaseUnitAmount so that it throws if user supplies unitAmount with too many decimals 2017-12-21 09:34:50 +01:00
Fabio Berger
85e16c1233 Make assertion stricter so that one cannot submit invalid baseUnit amounts to toUnitAmount 2017-12-21 09:33:57 +01:00
Brandon Millman
2d53b7d9a4 Add some missed underscores, update changelog and comments 2017-12-20 19:08:11 -05:00
Brandon Millman
23052a5c2e Merge branch 'development' into fix/underscorePrivate
* development: (29 commits)
  Move call to error reporter to end of handler so that even if reporting the error takes a while, it doesn't block the UI
  Update outdated WETH ranges
  Fix conditional
  Fix top-padding
  Publish
  Update CHANGELOGs
  Add slashes to base URLs
  Fix linter issue
  Fix WETH symbol
  Update snapshot and artifacts
  Replace our EtherTokens with WETH9 from maker
  Fix test description
  Fix a typo
  Add err==null assertions
  Add WETH9 tests
  Use the new snapshot including WETH9 and it's artifacts
  Add WETH9 and mirations
  Fix WETH events watching
  Fix a typo
  Init the _etherTokenContractsByAddress
  ...
2017-12-20 19:07:54 -05:00
Fabio Berger
42b3a7c9d7 Move call to error reporter to end of handler so that even if reporting the error takes a while, it doesn't block the UI 2017-12-20 18:36:12 +01:00
Fabio Berger
33315046cd Update outdated WETH ranges 2017-12-20 18:31:01 +01:00
Fabio Berger
2cf647d5ad Fix conditional 2017-12-20 17:40:01 +01:00
Fabio Berger
b1d88ca643 Merge branch 'development' of github.com:0xProject/0x.js into development
* 'development' of github.com:0xProject/0x.js:
  Publish
2017-12-20 17:24:19 +01:00
Fabio Berger
b79b48cfbe Fix top-padding 2017-12-20 17:24:12 +01:00
Leonid Logvinov
a2bf19efc1 Publish
- 0x.js@0.28.0
 - @0xproject/abi-gen@0.0.3
 - @0xproject/assert@0.0.8
 - @0xproject/connect@0.3.1
 - contracts@2.1.0
 - @0xproject/dev-utils@0.0.2
 - @0xproject/json-schemas@0.7.0
 - @0xproject/kovan_faucets@1.0.1
 - @0xproject/monorepo-scripts@0.1.1
 - @0xproject/subproviders@0.1.1
 - @0xproject/tslint-config@0.3.0
 - @0xproject/types@0.1.1
 - @0xproject/utils@0.1.1
 - @0xproject/web3-wrapper@0.1.1
 - @0xproject/website@0.0.3
2017-12-20 17:10:12 +01:00
Leonid Logvinov
6636a0861d Update CHANGELOGs 2017-12-20 16:40:19 +01:00
Leonid Logvinov
5d4078bcf4 Add slashes to base URLs 2017-12-20 16:25:41 +01:00
Brandon Millman
396e3d3ec2 Merge pull request #280 from 0xProject/feature/updateReadmes
Update readmes for connect, kovan-faucets, types, and utils packages
2017-12-20 10:06:44 -05:00
Leonid
e88b01ed5b Merge pull request #277 from 0xProject/feature/weth-events
Add etherToken.getLogsAsync and etherToken.subscribe with tests
2017-12-20 15:33:15 +01:00
Brandon Millman
cb11aec84d Add new underscore-privates rule to @0xproject/tslint-config and fix lint errors 2017-12-20 15:30:25 +01:00
Leonid Logvinov
3e3587c281 Fix linter issue 2017-12-20 15:21:36 +01:00
Fabio Berger
972e1675f6 Merge branch 'development' of github.com:0xProject/0x.js into development
* 'development' of github.com:0xProject/0x.js:
  Change contributing test
  Fix yarn workspaces explanation
  Change CONTRIBUTING section
  Fix the headers
  Address feedback
  Write 4 README's
2017-12-20 15:18:15 +01:00
Fabio Berger
05ee368763 Fix md link 2017-12-20 15:17:36 +01:00
Leonid
291e2c8fa0 Merge pull request #279 from 0xProject/feature/READMEs
Write 4 README's
2017-12-20 15:17:23 +01:00
Fabio Berger
ad61fe4b54 Fix link 2017-12-20 15:16:18 +01:00
Fabio Berger
439fe10e1e Merge pull request #284 from 0xProject/feature/newAndImprovedReadmes
Improve/Add to README's
2017-12-20 15:14:04 +01:00
Leonid Logvinov
d05a36deed Fix WETH symbol 2017-12-20 15:02:22 +01:00
Leonid Logvinov
03fd73fab8 Update snapshot and artifacts 2017-12-20 15:00:25 +01:00
Fabio Berger
1d430cf62f Standardize on improved contributing section 2017-12-20 14:53:50 +01:00
Leonid Logvinov
9ed05f56d3 Replace our EtherTokens with WETH9 from maker 2017-12-20 14:53:38 +01:00
Fabio Berger
23aa3ec5ea Add Yarn < v1.0 disclaimer 2017-12-20 14:51:04 +01:00
Fabio Berger
a0f5ceddce Flesh out LedgerSubprovider usage example 2017-12-20 14:50:20 +01:00
Fabio Berger
3171943228 Fix command 2017-12-20 14:50:08 +01:00
Leonid Logvinov
455f74d449 Fix test description 2017-12-20 14:45:35 +01:00
Leonid Logvinov
01bc254cd0 Fix a typo 2017-12-20 14:45:13 +01:00
Leonid Logvinov
2a7cafbf20 Add err==null assertions 2017-12-20 14:44:54 +01:00
Leonid Logvinov
bf1603839e Change contributing test 2017-12-20 14:21:39 +01:00
Leonid Logvinov
8ed776e113 Fix yarn workspaces explanation 2017-12-20 14:17:17 +01:00
Leonid Logvinov
c3508dcdc6 Change CONTRIBUTING section 2017-12-20 14:10:35 +01:00
Leonid Logvinov
3579f063d6 Fix the headers 2017-12-20 14:07:50 +01:00
Leonid Logvinov
ecc6cb2b7c Address feedback 2017-12-20 14:07:50 +01:00
Leonid Logvinov
de6fe25751 Write 4 README's 2017-12-20 14:07:50 +01:00
Leonid Logvinov
d639a22cff Add WETH9 tests 2017-12-20 14:02:25 +01:00
Leonid Logvinov
b1f36a9024 Use the new snapshot including WETH9 and it's artifacts 2017-12-20 14:02:25 +01:00
Leonid Logvinov
d8d15149fc Add WETH9 and mirations 2017-12-20 14:02:25 +01:00
Leonid Logvinov
c07de97fd8 Fix WETH events watching 2017-12-20 14:02:24 +01:00
Leonid Logvinov
78eb79396e Fix a typo 2017-12-20 14:02:24 +01:00
Leonid Logvinov
abce410897 Init the _etherTokenContractsByAddress 2017-12-20 14:02:24 +01:00
Leonid Logvinov
9594185f11 Export new public types 2017-12-20 14:02:24 +01:00
Leonid Logvinov
35c20d505e Update CHANGELOG 2017-12-20 14:02:24 +01:00
Leonid Logvinov
b829d55752 Make order watcher react to new etherToken events 2017-12-20 14:01:59 +01:00
Leonid Logvinov
e92d6ff84f Add EtherToken events to the ABI 2017-12-20 14:01:59 +01:00
Leonid Logvinov
0056c66d32 Enable multiple EtherTokenContract instances 2017-12-20 14:01:59 +01:00
Leonid Logvinov
613fada49f Add etherToken.getLogsAsync and etherToken.subscribe with tests 2017-12-20 14:01:59 +01:00
Leonid
b603197ae8 Merge pull request #278 from 0xProject/fix/error-taker-format
Throw a better error message when taker is null|undefined or anything but not a string
2017-12-20 13:06:21 +01:00
Brandon Millman
69b81836fe Merge branch 'development' into feature/updateReadmes
* development:
  Remove reliance on testrpc snapshot in ZRX tests
2017-12-20 01:12:07 -05:00
Brandon Millman
0be4e1e1b3 Fix wording 2017-12-20 01:11:58 -05:00
Amir Bandeali
14c994ce14 Merge pull request #282 from 0xProject/fix/zrx-tests
Remove reliance on testrpc snapshot in ZRX tests
2017-12-19 20:31:46 -06:00
Fabio Berger
dd39fadce7 Update and improve website README 2017-12-20 02:49:36 +01:00
Fabio Berger
5d24022209 Add mono repo scripts README 2017-12-20 02:37:14 +01:00
Fabio Berger
c75eaca5b6 Add clean instructions 2017-12-20 02:37:02 +01:00
Fabio Berger
53798302da Improve subproviders readme 2017-12-20 02:24:17 +01:00
Fabio Berger
b799a8a108 Flesh out main repo README 2017-12-20 02:14:44 +01:00
Fabio Berger
3d6c0b75a1 Improve package descriptions 2017-12-20 01:47:03 +01:00
Brandon Millman
c531d734d4 Merge branch 'development' into feature/updateReadmes
* development: (35 commits)
  Remove etherToken from smart contract docs
  Update new WETH addresses and localStorage clearance key
  Fix merge
  Remove re-assignment
  Fix scrolling topBar on Portal
  Fix overflow issue on calculated fillAmount
  Fix faulty import
  Refactor remaining _.assign to spread operator
  Move muiTheme into it's own module
  Add WETH
  remove extra space
  Remove binding on prop passed callbacks
  Add airtable tasks to TODO's
  Refactor configs and constants, standardize on uppercase/snakecase, alphebetize, rename for logical grouping
  Sort colors into color spectrum
  remove unused style
  standarize on `grey` over `gray` spelling and other color related fixes
  Standardize colors to always be in uppercase hex and consolidate material-ui greys
  Consolidate all custom colors and material-ui colors into a colors module
  Remove unused `location` prop
  ...
2017-12-19 17:51:09 -05:00
Brandon Millman
f239522a19 Update some wording and remove N/A test sections 2017-12-19 17:50:54 -05:00
Fabio Berger
d1c36f50d5 Merge pull request #283 from 0xProject/createWethPage
Merge WETH page improvements into development
2017-12-19 23:36:37 +01:00
Fabio Berger
484312e677 Remove etherToken from smart contract docs 2017-12-19 23:28:18 +01:00
Fabio Berger
0dc5178083 Update new WETH addresses and localStorage clearance key 2017-12-19 23:24:04 +01:00
Fabio Berger
08f2406ca2 Fix merge 2017-12-19 23:04:08 +01:00
Fabio Berger
41104b2d45 Merge branch 'development' into createWethPage
* development: (27 commits)
  Remove re-assignment
  Fix scrolling topBar on Portal
  Fix overflow issue on calculated fillAmount
  Fix faulty import
  Introduce an identityCommandBuilder
  Define types for methodID
  Define types for ethereumjs-abi
  Install types for yargs
  Fix comments
  Fix linter issues
  Fix linter error
  Rename SubscriptionOpts to BlockRange
  Refactor remaining _.assign to spread operator
  Move muiTheme into it's own module
  Refactor configs and constants, standardize on uppercase/snakecase, alphebetize, rename for logical grouping
  Sort colors into color spectrum
  remove unused style
  standarize on `grey` over `gray` spelling and other color related fixes
  Standardize colors to always be in uppercase hex and consolidate material-ui greys
  Consolidate all custom colors and material-ui colors into a colors module
  ...

# Conflicts:
#	packages/website/ts/components/eth_wrappers.tsx
#	packages/website/ts/components/portal.tsx
#	packages/website/ts/utils/configs.ts
#	packages/website/ts/utils/constants.ts
2017-12-19 22:58:06 +01:00
Amir Bandeali
766824120a Remove reliance on testrpc snapshot in ZRX tests 2017-12-19 15:03:42 -06:00
Fabio Berger
c39ac903a9 Merge pull request #275 from 0xProject/refactor/website
Refactor Website
2017-12-19 21:26:34 +01:00
Brandon Millman
ca2bb60877 Update readmes for connect, kovan-facuets, types, and utils packages 2017-12-19 12:55:48 -05:00
Leonid Logvinov
3c66f18a46 Don't throw in transformers 2017-12-19 18:39:35 +01:00
Fabio Berger
8a940a800a Remove re-assignment 2017-12-19 18:06:41 +01:00
Fabio Berger
06bd5a9b03 Merge branch 'development' into refactor/website
* development:
  Introduce an identityCommandBuilder
  Define types for methodID
  Define types for ethereumjs-abi
  Install types for yargs
  Fix comments
  Fix linter issues
  Fix linter error
  Rename SubscriptionOpts to BlockRange
2017-12-19 18:02:50 +01:00
Leonid Logvinov
93518802d6 Update CHANGELOG 2017-12-19 16:26:05 +01:00
Leonid Logvinov
75f637bd75 Throw a better error message when taker is null|undefined or anything but not a string 2017-12-19 16:22:57 +01:00
Fabio Berger
e38c7ff076 Fix scrolling topBar on Portal 2017-12-19 12:42:16 +01:00
Fabio Berger
66fe7b88b0 Fix overflow issue on calculated fillAmount 2017-12-19 12:38:41 +01:00
Fabio Berger
16179d2f8e Fix faulty import 2017-12-19 12:37:51 +01:00
Leonid
1316a2dd2a Merge pull request #273 from 0xProject/fix/contract-fixes
Add proper types for yargs and ethereumjs-abi
2017-12-19 12:20:28 +01:00
Leonid Logvinov
e5b5fc400a Introduce an identityCommandBuilder 2017-12-19 12:19:48 +01:00
Leonid Logvinov
786ea52738 Define types for methodID 2017-12-19 12:19:48 +01:00
Leonid Logvinov
ed6756898f Define types for ethereumjs-abi 2017-12-19 12:19:48 +01:00
Leonid Logvinov
a5d2cbfd6f Install types for yargs 2017-12-19 12:19:48 +01:00
Leonid
04268d7f4b Merge pull request #272 from 0xProject/fix/subscription-opts
Rename SubscriptionOpts to BlockRange
2017-12-19 12:10:59 +01:00
Leonid Logvinov
156dae1d33 Fix comments 2017-12-19 12:10:44 +01:00
Leonid Logvinov
436d78eb93 Fix linter issues 2017-12-19 12:10:43 +01:00
Leonid Logvinov
f269ecd95e Fix linter error 2017-12-19 12:10:43 +01:00
Leonid Logvinov
1e4fdcf615 Rename SubscriptionOpts to BlockRange 2017-12-19 12:10:43 +01:00
Fabio Berger
b7004b3002 Refactor remaining _.assign to spread operator 2017-12-19 11:25:50 +01:00
Fabio Berger
c6af59a3e7 Move muiTheme into it's own module 2017-12-19 11:18:02 +01:00
Fabio Berger
32396b5eca Merge branch 'development' into refactor/website
* development:
  Add additional public changes introduced to changelog
  Update CHANGELOG
  Add a comment
  Introduce a variable for true
  Remove redundant template string
  Implement the address derivations
  Add hdnode dependency
  Move web3 import after subprovider imports in test web3_factory
  Fixed https://github.com/0xProject/wiki/issues/19 by disabling re-rendering of markdownCodeBlock renderer if props haven't updated
  Add convenience `rebuild` command
  Update website calls to deposit/withdraw
  Add entry to CHANGELOG
  Fix tests in contracts
  Modify the etherToken wrapper methods to accept an etherTokenAddress as the first arg. Since it is becoming apparent we will be updating the canonical WETH contract, we want users of 0x.js to be able to interact with n number of etherTokens without re-instantiating for each one.
  Fix documentation issue where `unsubscribeAll` shown as method on every contractWrapper instance even though it's only used by Exchange and Token wrappers.

# Conflicts:
#	packages/website/ts/components/eth_weth_conversion_button.tsx
2017-12-19 11:04:25 +01:00
Fabio Berger
2930537a51 Add WETH 2017-12-19 10:41:52 +01:00
Fabio Berger
16c91bca0a remove extra space 2017-12-19 10:41:45 +01:00
Fabio Berger
1f85d31663 Remove binding on prop passed callbacks 2017-12-19 10:39:25 +01:00
Fabio Berger
684542d073 Add airtable tasks to TODO's 2017-12-19 10:36:54 +01:00
Fabio Berger
bab01abe27 Merge branch 'development' into createWethPage
* development:
  Add additional public changes introduced to changelog
  Update CHANGELOG
  Add a comment
  Introduce a variable for true
  Remove redundant template string
  Implement the address derivations
  Add hdnode dependency
  Move web3 import after subprovider imports in test web3_factory
  Fixed https://github.com/0xProject/wiki/issues/19 by disabling re-rendering of markdownCodeBlock renderer if props haven't updated
  Add convenience `rebuild` command
  Update website calls to deposit/withdraw
  Add entry to CHANGELOG
2017-12-19 10:28:11 +01:00
Fabio Berger
c63f76dde7 Merge pull request #268 from 0xProject/fix/codeSelectingInDocs
Fix code selection bug in docs
2017-12-19 10:23:35 +01:00
Fabio Berger
79bd416c61 Merge pull request #267 from 0xProject/refactor/passInEtherTokenAddress
Refactor EtherToken wrapper to accept address in method args
2017-12-19 10:23:07 +01:00
Fabio Berger
7710989dee Add additional public changes introduced to changelog 2017-12-18 22:04:12 +01:00
Fabio Berger
fb0b7efc45 Refactor configs and constants, standardize on uppercase/snakecase, alphebetize, rename for logical grouping 2017-12-18 19:30:25 +01:00
Brandon Millman
1af427e4a7 Merge pull request #269 from 0xProject/fix/brokenCi
Move web3 import after subprovider imports in test web3_factory
2017-12-18 10:41:15 -05:00
Leonid
bb6d594ec7 Merge pull request #271 from 0xProject/fix/ledger-derivation
Implement ledger optimization for address derivation
2017-12-18 16:09:22 +01:00
Leonid Logvinov
a57dda2c2a Update CHANGELOG 2017-12-18 15:57:40 +01:00
Leonid Logvinov
a3a2df098b Add a comment 2017-12-18 15:56:31 +01:00
Leonid Logvinov
90d1c3e2c9 Introduce a variable for true 2017-12-18 14:49:13 +01:00
Leonid Logvinov
950406f1f9 Remove redundant template string 2017-12-18 14:47:39 +01:00
Leonid Logvinov
064405126d Implement the address derivations 2017-12-18 12:30:34 +01:00
Leonid Logvinov
6d447fd8a5 Add hdnode dependency 2017-12-18 12:30:14 +01:00
Fabio Berger
400228e139 Sort colors into color spectrum 2017-12-18 10:44:55 +01:00
Fabio Berger
edfae32484 remove unused style 2017-12-18 10:44:41 +01:00
Fabio Berger
1aed970ce3 standarize on grey over gray spelling and other color related fixes 2017-12-18 10:28:34 +01:00
Fabio Berger
445ff1e28e Standardize colors to always be in uppercase hex and consolidate material-ui greys 2017-12-18 10:06:16 +01:00
Fabio Berger
df9d3e3e16 Consolidate all custom colors and material-ui colors into a colors module 2017-12-18 09:15:12 +01:00
Brandon Millman
4dc6694651 Move web3 import after subprovider imports in test web3_factory 2017-12-17 23:30:14 -05:00
Fabio Berger
98c01c2f80 Remove unused location prop 2017-12-17 20:57:39 -05:00
Fabio Berger
f698dd4077 Use bigNumberConfigs from @0xproject/utils in website repo 2017-12-17 20:55:50 -05:00
Fabio Berger
0578116f1d Fix unhoverable help tooltip by renaming Trade Permissions to Allowance 2017-12-17 20:51:54 -05:00
Fabio Berger
abbad68eb8 Replace remaining strEnums with property TS string enums 2017-12-17 20:48:23 -05:00
Fabio Berger
90d274ffc4 Update ActionType enum and move from using _.assign in reducer 2017-12-17 20:06:49 -05:00
Fabio Berger
449fd9f024 Remove unused enums 2017-12-17 19:38:59 -05:00
Fabio Berger
22c4ee6ef7 Update first two string enums to native type 2017-12-17 19:35:24 -05:00
Fabio Berger
951fbc9b76 Temporarily pretend as if new WETH contracts are already whitelisted by tokenRegistry and put hacks behind the shouldDeprecateOldWethToken flag 2017-12-17 19:18:33 -05:00
Fabio Berger
89f368a8b8 Add notice dialog to balances page about updating the WETH contract. We also draw attention to the new dedicated section for unwrapping from outdated WETH tokens 2017-12-17 18:58:12 -05:00
Fabio Berger
672c8acaca Fix linter errors 2017-12-17 17:21:33 -05:00
Fabio Berger
681617480a Move weth.io url to constants 2017-12-17 17:10:51 -05:00
Fabio Berger
95dfac6f9b Make it such that Wrapped Ether page works on networks without any outdated WETH tokens 2017-12-17 17:09:16 -05:00
Fabio Berger
b2256679be Add Max convenience button in unwrap WETH dialog 2017-12-17 15:41:24 -05:00
Fabio Berger
9e914be975 Link all EtherTokens to Etherscan and add address tooltip 2017-12-17 14:14:23 -06:00
Fabio Berger
edbe6915e0 Fixed https://github.com/0xProject/wiki/issues/19 by disabling re-rendering of markdownCodeBlock renderer if props haven't updated 2017-12-17 13:22:54 -06:00
Fabio Berger
fd3e8cd813 Add convenience rebuild command 2017-12-17 13:20:27 -06:00
Fabio Berger
b640e2cc49 Update website calls to deposit/withdraw 2017-12-17 12:40:04 -06:00
Fabio Berger
51af6de624 Update to passing etherTokenAddress into withdraw and deposit calls 2017-12-17 12:36:50 -06:00
Fabio Berger
054c00e323 Add entry to CHANGELOG 2017-12-17 01:07:28 -06:00
Fabio Berger
5664333490 Since sending the error report could take some time, we first trigger onError so that the user gets notified immediately 2017-12-17 00:44:34 -06:00
Fabio Berger
ac78c64f9e Fix tests in contracts 2017-12-17 00:40:19 -06:00
Fabio Berger
1f748afed9 Modify the etherToken wrapper methods to accept an etherTokenAddress as the first arg. Since it is becoming apparent we will be updating the canonical WETH contract, we want users of 0x.js to be able to interact with n number of etherTokens without re-instantiating for each one. 2017-12-17 00:32:53 -06:00
Fabio Berger
4a73c05435 Fix documentation issue where unsubscribeAll shown as method on every contractWrapper instance even though it's only used by Exchange and Token wrappers. 2017-12-17 00:19:15 -06:00
Fabio Berger
fe8f2d87c7 Temporary hack to alleviate issues with updating tokenRegistry with new WETH address 2017-12-15 14:07:14 -06:00
Fabio Berger
a71a1edf2c Two mysteriously missing imports 2017-12-15 13:01:45 -06:00
Fabio Berger
87209b8f57 Merge pull request #264 from 0xProject/createWethPage
Create WETH Page
2017-12-15 12:58:22 -06:00
Fabio Berger
13279f1f20 Fix linter errors 2017-12-15 12:47:16 -06:00
Fabio Berger
b46dd2e0a2 Merge branch 'development' into createWethPage
* development: (54 commits)
  Fix redundant spaces
  Fix tests
  Fix website unused vars
  Fix connect unused vars
  Fix 0x.js unused vars
  Dissallow unused vars/imports
  Implement first custom linter rule async-suffix
  Reuse intervalutils in website
  Add a newline
  Name a variable
  Add a comment
  Fix a conditional
  Make migrations deterministic
  Fix linter error
  Fix linter errors
  Add a function to init token balances
  Rename tokenUtils.getNonProtocolTokens to tokenUtils.getDummyTokens
  Add DummyToken to gitignore
  Add DummyToken to artifacts list
  Increase mocha timeout
  ...
2017-12-15 12:37:03 -06:00
Leonid
3eb08735d4 Merge pull request #266 from 0xProject/fix/no-unused-vars
Remove all unused vars and imports
2017-12-15 19:03:01 +01:00
Leonid Logvinov
c8e52882ca Fix redundant spaces 2017-12-15 18:44:13 +01:00
Fabio Berger
484dd4c33a Update name to be a call to action 2017-12-15 11:06:18 -06:00
Fabio Berger
94f40a54b4 Add default value for onConversionSuccessful 2017-12-15 11:05:53 -06:00
Leonid Logvinov
818a50a3fb Fix tests 2017-12-15 15:32:10 +01:00
Leonid Logvinov
2041e9945e Fix website unused vars 2017-12-15 15:19:19 +01:00
Leonid Logvinov
126048bac9 Fix connect unused vars 2017-12-15 13:58:30 +01:00
Leonid Logvinov
274aa50d74 Fix 0x.js unused vars 2017-12-15 13:30:19 +01:00
Leonid Logvinov
c36d85a46c Dissallow unused vars/imports 2017-12-15 13:14:44 +01:00
Fabio Berger
ac1fbeb962 Improve WETH page styling 2017-12-14 19:28:49 -06:00
Leonid
de8c445f96 Merge pull request #265 from 0xProject/feature/custom-linter-rule
Implement first custom linter rule async-suffix
2017-12-14 22:34:54 +01:00
Leonid Logvinov
c23d42fea5 Implement first custom linter rule async-suffix 2017-12-14 21:49:19 +01:00
Leonid
a0aa21103b Merge pull request #258 from 0xProject/feature/contracts-refactor
A bunch of refactorings
2017-12-14 17:48:45 +01:00
Leonid Logvinov
ce242b10e2 Reuse intervalutils in website 2017-12-14 17:43:42 +01:00
Fabio Berger
6d386220d9 Use new wrap/unwrap buttons, fetch outdated WETH balances and re-fetch after a successful unwrap. 2017-12-14 10:43:20 -06:00
Fabio Berger
7ce1021798 Refactor the WETH conversion dialog/button to be either wrap or unwrap specific and not both 2017-12-14 10:41:33 -06:00
Leonid Logvinov
9ad9e1204c Add a newline 2017-12-14 17:15:49 +01:00
Leonid Logvinov
a63061f5b2 Name a variable 2017-12-14 17:15:07 +01:00
Leonid Logvinov
4997331410 Add a comment 2017-12-14 17:13:34 +01:00
Leonid Logvinov
f7f4b6da8d Fix a conditional 2017-12-14 17:12:18 +01:00
Leonid Logvinov
c975676f6c Make migrations deterministic 2017-12-14 16:40:37 +01:00
Leonid Logvinov
d702c65a5b Fix linter error 2017-12-14 15:59:00 +01:00
Leonid Logvinov
4391f9913e Fix linter errors 2017-12-14 15:47:03 +01:00
Leonid Logvinov
28c409fc6d Add a function to init token balances 2017-12-14 15:47:03 +01:00
Leonid Logvinov
449a04d39c Rename tokenUtils.getNonProtocolTokens to tokenUtils.getDummyTokens 2017-12-14 15:47:03 +01:00
Leonid Logvinov
4bcd7ba31e Add DummyToken to gitignore 2017-12-14 15:47:03 +01:00
Leonid Logvinov
5bda301fec Add DummyToken to artifacts list 2017-12-14 15:47:03 +01:00
Leonid Logvinov
84c7c6eb12 Increase mocha timeout 2017-12-14 15:47:03 +01:00
Leonid Logvinov
a5b7980b06 Add DummyToken to artifacts list 2017-12-14 15:47:03 +01:00
Leonid Logvinov
f746f5bfa3 Update addresses and add DummyToken artifact 2017-12-14 15:47:03 +01:00
Leonid Logvinov
3ed2eedfda Change circle commit hash to the newest one from the monorepo 2017-12-14 15:47:03 +01:00
Leonid Logvinov
4ce8eaa158 Fix CI build 2017-12-14 15:47:02 +01:00
Leonid Logvinov
7abb026819 Delete abi-gen-templates 2017-12-14 15:47:02 +01:00
Leonid Logvinov
abd55411d4 Move shared types to types package 2017-12-14 15:47:02 +01:00
Leonid Logvinov
cb596c1413 Move more shared utils into utils package and reuse them 2017-12-14 15:47:02 +01:00
Leonid Logvinov
6120a43fff Create dev-utils with blockchainLifecycle in it 2017-12-14 15:47:02 +01:00
Leonid Logvinov
02e7354b53 Move 0x.js temnplates to 0x.js instead of having them as a separate package 2017-12-14 15:47:02 +01:00
Leonid Logvinov
0a0d3503c0 Remove generated contracts and ignore them. Add a prebuild command to regenerate them 2017-12-14 15:47:02 +01:00
Fabio Berger
105bcc6664 Clear trackedTokens so that a user starts tracking the new WETH and no longer the old one 2017-12-13 19:58:33 -06:00
Fabio Berger
ceae51fe32 Make label optional and make sure the input field still renders properly without it 2017-12-13 19:46:48 -06:00
Fabio Berger
b054080fa1 Remove ETH-WETH convert button from balances page 2017-12-13 19:45:44 -06:00
Fabio Berger
565010408e Remove temporary hack 2017-12-13 19:44:27 -06:00
Fabio Berger
5619780cc1 Use boxed ETH 2017-12-13 19:43:43 -06:00
Brandon Millman
d69143487e Reorganize packages section of readme 2017-12-13 15:37:47 -08:00
Brandon Millman
2ef763a195 Merge pull request #229 from 0xProject/feature/addKovanFaucets
Add kovan faucet project into the mono repo
2017-12-13 15:09:39 -08:00
Brandon Millman
6ba4ed99c4 Fix hanging requests by importing web3 last 2017-12-13 15:05:57 -08:00
Brandon Millman
aec3c83191 Add kovan faucet to main README 2017-12-13 12:39:52 -08:00
Brandon Millman
19d8449981 Merge branch 'development' into feature/addKovanFaucets
* development:
  Add new packages to main README
  Remove redundant totalSupply from token interface
2017-12-13 12:37:01 -08:00
Brandon Millman
91f276d925 Cleanup kovan-faucet package 2017-12-13 12:36:29 -08:00
Leonid Logvinov
6bda6a22e3 Add new packages to main README 2017-12-13 16:05:48 +01:00
Amir Bandeali
1fbe638950 Remove redundant totalSupply from token interface 2017-12-12 16:07:04 -08:00
Brandon Millman
1e9f23ebba Fix build errors 2017-12-12 15:56:30 -08:00
Brandon Millman
bbb768c5cf Add kovan faucet project into the mono repo 2017-12-12 15:45:22 -08:00
Amir Bandeali
5678196706 Merge pull request #255 from 0xProject/feature/updateWeth
Update WETH
2017-12-12 15:39:29 -08:00
Amir Bandeali
987637abed Increase timeout on deployer tests 2017-12-12 15:11:57 -08:00
Amir Bandeali
ff422ecfb2 Add version string to EtherToken_v2 2017-12-12 15:05:31 -08:00
Amir Bandeali
1fb643cb69 Formatting fixes 2017-12-12 15:05:30 -08:00
Amir Bandeali
88db8c3724 Add missing package in utils, fix linting error 2017-12-12 15:05:30 -08:00
Amir Bandeali
cf50a82ecc fix tests after merging with development 2017-12-12 15:05:30 -08:00
Amir Bandeali
145fea5253 Add test:circleci command, add newlines to end of contracts 2017-12-12 15:05:30 -08:00
Amir Bandeali
b97f140b78 Add gas limits to failing tests 2017-12-12 15:05:30 -08:00
Amir Bandeali
1dda4d5f78 Rename contracts lib to utils 2017-12-12 15:05:29 -08:00
Amir Bandeali
6f2cb66163 Refactor unlimited allowance logic out of ERC20Token 2017-12-12 15:05:29 -08:00
Amir Bandeali
8b29f6f18d Fix typo, change variable name to be consistent 2017-12-12 15:05:28 -08:00
Amir Bandeali
2cc410e61f Update 0x.js version, fix build errors 2017-12-12 15:05:27 -08:00
Amir Bandeali
548fda8dba Add updated contracts, reorganize contract file structure 2017-12-12 15:02:05 -08:00
Amir Bandeali
b58bf8259d Add tests for ERC20Token and EtherToken_v2 2017-12-12 15:02:05 -08:00
Amir Bandeali
e6862e9739 Fix errors with new testrpc version 2017-12-12 15:02:04 -08:00
Amir Bandeali
7008e882c0 Add version to new EtherToken, fix typos 2017-12-12 15:02:04 -08:00
Amir Bandeali
7d59faa650 Add updated ERC20 implementation, update WETH 2017-12-12 15:02:04 -08:00
Fabio Berger
eaa6484f24 Merge branch 'development' into createWethPage
* development:
  update yarn.lock
  Fix typedoc_utils to take into account subPackageName when rendering call path
  Add WebSocketOrderbookChannel to connect docs
2017-12-12 15:40:23 -06:00
Fabio Berger
6630b1d8a5 update yarn.lock 2017-12-12 15:27:07 -06:00
Fabio Berger
d0916e196c progress weth page 2017-12-12 14:53:39 -06:00
Brandon Millman
8e74a22c6f Merge pull request #263 from 0xProject/fix/docsCallPath
Fix typedoc_utils to take into account subPackageName when rendering …
2017-12-12 12:52:35 -08:00
Brandon Millman
2ffcc853fd Fix typedoc_utils to take into account subPackageName when rendering call path 2017-12-12 10:23:51 -08:00
Brandon Millman
caeb5cb6ab Merge pull request #261 from 0xProject/feature/addWebSocketDocs
Add WebSocketOrderbookChannel to connect docs
2017-12-12 10:23:17 -08:00
Fabio Berger
4f72c527de Merge branch 'development' of github.com:0xProject/0x.js into development
* 'development' of github.com:0xProject/0x.js:
  Re-hard code the dependency
  Add missing dependency
  Add missing dependency
  Fix a dependency
  Fix an invocation
  Move dependency
  Merge dependencies
  Don't unsubscribe on error. It's done automatically
  Rename blockAndLogStreamer to blockAndLogStreamerIfExists
  Move isAddress to shared utils and remove all dependencies on ethereum-address
  Remove ethereum-address dependency and add this logic to the repo
2017-12-12 11:38:13 -06:00
Fabio Berger
71cb2e05d1 Resize token icons 2017-12-12 11:36:57 -06:00
Brandon Millman
d1fb61e0de Add WebSocketOrderbookChannel to connect docs 2017-12-12 15:37:55 +01:00
Leonid
cb7188d473 Merge pull request #257 from 0xProject/fix/ethereum-address
Remove ethereum-address dependency and add this logic to the repo
2017-12-12 15:30:04 +01:00
Leonid
02f22d9155 Merge pull request #262 from 0xProject/fix/portal-bug
Fix portal subscriptions bug
2017-12-12 15:27:35 +01:00
Leonid Logvinov
707b98849c Re-hard code the dependency 2017-12-12 15:25:06 +01:00
Leonid Logvinov
d778378b37 Add missing dependency 2017-12-12 15:14:54 +01:00
Leonid Logvinov
f3f596b231 Add missing dependency 2017-12-12 15:06:38 +01:00
Leonid Logvinov
276ee9903a Fix a dependency 2017-12-12 14:01:58 +01:00
Leonid Logvinov
16a970b65d Fix an invocation 2017-12-12 13:56:19 +01:00
Leonid Logvinov
1647e45247 Move dependency 2017-12-12 13:55:34 +01:00
Leonid Logvinov
3477a84bbd Merge dependencies 2017-12-12 13:54:17 +01:00
Leonid Logvinov
c61fe3ce64 Don't unsubscribe on error. It's done automatically 2017-12-12 13:33:12 +01:00
Leonid Logvinov
f94dc1fe44 Rename blockAndLogStreamer to blockAndLogStreamerIfExists 2017-12-12 13:32:54 +01:00
Brandon Millman
1339aadf4e Merge pull request #259 from 0xProject/fix/addChangelogAndPostpublishScripts
Fix broken postpublish_utils, add CHANGELOG and postpublish.js script…
2017-12-11 13:10:43 -08:00
Leonid Logvinov
a14424ae5f Move isAddress to shared utils and remove all dependencies on ethereum-address 2017-12-11 12:43:19 +01:00
Leonid Logvinov
f1e7ea118b Remove ethereum-address dependency and add this logic to the repo 2017-12-11 12:21:44 +01:00
Brandon Millman
9c6453e129 Fix broken postpublish_utils, add CHANGELOG and postpublish.js scripts to all packages 2017-12-08 15:01:52 -08:00
Fabio Berger
ec3d8a034f Update yarn.lock 2017-12-08 13:06:35 -06:00
Fabio Berger
c452294bcc Change dev domain since .dev is actually owned by Google and Chrome now enforces HSTS by default 2017-12-08 13:06:24 -06:00
Fabio Berger
d5757499bc Merge branch 'feature/addSubproviders' into feature/portal-ledger-support
* feature/addSubproviders:
  remove console.log
  Update README.md
  Fix unit test
  Add missing params
  Debug CircleCi failure
  Update yarn.lock
  Inline network module
  Add todo
  Stop supporting different file extensions in abi-gen
  Refactor networkId out of web3Wrapper
  Update connect types in preperation for publishing
  Add link to random id generator
  Remove `prebuild` command and add `test:circleci`
  Fix CI command
  Address feedback
  Refactor web3Wrapper to a separate package
2017-12-08 11:23:44 -06:00
Fabio Berger
139c8c2e78 Merge branch 'feature/addSubproviders' into feature/portal-ledger-support
* feature/addSubproviders:
  Make sure we don't pass empty maker into getOrderHashHex
  Make sure we always pass in the correct networkId even if no injectedWeb3 found
2017-12-07 15:15:51 -06:00
Fabio Berger
215e33fa6c Merge branch 'feature/addSubproviders' into feature/portal-ledger-support
* feature/addSubproviders:
  remove unneeded reset
  Use rejectedWith
  Add missing calls to configure
  remove unneeded type assertions
  remove unused type
  Simplify interface to signPersonalMessageAsync
  Fix unit test
  Fix ethereumjs-tx declaration and import
  Use assert.isHexString
  Add type defs for ledgerco and ethereumjs-tx
  Make test only run unit tests since cannot run integration tests on CI
  Improve README
  Fix version and remove the UMD build
  Fix tslint error
2017-12-07 11:42:50 -06:00
Fabio Berger
3d12b84f1d Merge branch 'feature/addSubproviders' into feature/portal-ledger-support
* feature/addSubproviders:
  Standardize deps
  Inline function
  Introduce a const
  Make private
  Add version matcher script
  Use same versions of dependencies everywhere
  Add missing await
  Move declaration into proper conditional block
  Fix Party element so that an identicon's height is that which was passed in
2017-12-06 11:01:53 -06:00
Fabio Berger
d8adc88c52 Add missing await 2017-12-05 22:15:31 -06:00
Fabio Berger
5119e49e47 Move declaration into proper conditional block 2017-12-05 22:15:23 -06:00
Fabio Berger
cfb9f87418 Fix Party element so that an identicon's height is that which was passed in 2017-12-05 22:07:25 -06:00
551 changed files with 22841 additions and 16506 deletions

View File

@@ -5,24 +5,118 @@ jobs:
docker:
- image: circleci/node:6.12
environment:
CONTRACTS_COMMIT_HASH: '78fe8dd'
CONTRACTS_COMMIT_HASH: '9ed05f5'
working_directory: ~/repo
steps:
- checkout
- run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV
- restore_cache:
key: dependency-cache-{{ checksum "package.json" }}
- run:
name: yarn
command: yarn
command: yarn --frozen-lockfile
- save_cache:
key: dependency-cache-{{ checksum "package.json" }}
paths:
- ~/.cache/yarn
- ./node_modules
- run: wget https://s3.amazonaws.com/testrpc-shapshots/${CONTRACTS_COMMIT_HASH}.zip
- run: unzip ${CONTRACTS_COMMIT_HASH}.zip -d testrpc_snapshot
- run: node ./node_modules/lerna/bin/lerna.js bootstrap
- run: yarn lerna:run build
- save_cache:
key: repo-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo
test-0xjs:
docker:
- image: circleci/node:6.12
working_directory: ~/repo
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run:
name: testrpc
command: npm run testrpc -- --db testrpc_snapshot
background: true
- run: yarn lerna:run test:circleci
- run: yarn lerna:run --scope 0x.js test:circleci
test-contracts:
docker:
- image: circleci/node:6.12
working_directory: ~/repo
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run:
name: testrpc
command: npm run testrpc -- --db testrpc_snapshot
background: true
- run: yarn lerna:run --scope contracts test:circleci
test-deployer:
docker:
- image: circleci/node:6.12
working_directory: ~/repo
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run:
name: testrpc
command: npm run testrpc -- --db testrpc_snapshot
background: true
- run: yarn lerna:run --scope @0xproject/deployer test:circleci
test-rest:
docker:
- image: circleci/node:6.12
working_directory: ~/repo
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run:
name: testrpc
command: npm run testrpc -- --db testrpc_snapshot
background: true
- run: yarn lerna:run --ignore contracts --ignore 0x.js --ignore @0xproject/deployer test:circleci
lint:
working_directory: ~/repo
docker:
- image: circleci/node:6.12
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn lerna:run lint
prettier:
working_directory: ~/repo
docker:
- image: circleci/node:6.12
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn prettier:ci
workflows:
version: 2
main:
jobs:
- build
- test-0xjs:
requires:
- build
- test-contracts:
requires:
- build
- test-deployer:
requires:
- build
- test-rest:
requires:
- build
- prettier:
requires:
- build
- lint:
requires:
- build

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
*.sol linguist-language=Solidity

3
.gitignore vendored
View File

@@ -68,3 +68,6 @@ generated_docs/
TODO.md
packages/website/public/bundle*
# generated binaries
bin/

5
.prettierignore Normal file
View File

@@ -0,0 +1,5 @@
lib
generated
.nyc_output
/packages/contracts/build/contracts
package.json

6
.prettierrc Normal file
View File

@@ -0,0 +1,6 @@
{
"tabWidth": 4,
"printWidth": 120,
"trailingComma": all,
"singleQuote": true
}

View File

@@ -1,62 +1,46 @@
# 0x.js CONTRIBUTING.md
## 0x Contribution Guide
Thank you for your interest in contributing to 0x.js! We welcome contributions from anyone on the internet, and are grateful for even the smallest of fixes!
Thank you for your interest in contributing to 0x protocol! We welcome contributions from anyone on the internet, and are grateful for even the smallest of fixes!
## Developer's guide
### How to contribute
## How to contribute
If you'd like to contribute to 0x protocol, please fork the repo, fix, commit and send a pull request against the `development` branch for the maintainers to review and merge into the main code base. If you wish to submit more complex changes though, please check with a core dev first on [our RocketChat #dev channel](http://chat.0xproject.com) to ensure those changes are in-line with the general philosophy of the project and/or to get some early feedback which can make both your efforts easier as well as our review and merge procedures quick and simple.
If you'd like to contribute to 0x.js, please fork the repo, fix, commit and send a pull request against the `development` branch for the maintainers to review and merge into the main code base. If you wish to submit more complex changes though, please check up with a core dev first on [our gitter channel](https://gitter.im/0xProject/Lobby) or in the `#dev` channel on our [slack](https://slack.0xproject.com/) to ensure those changes are in line with the general philosophy of the project and/or to get some early feedback which can make both your efforts easier as well as our review and merge procedures quick and simple.
We encourage a “PR early” approach so create the PR as early as possible even without the fix/feature ready, so that devs and other volunteers know you have picked up the issue. These early PRs should indicate an 'in progress' status by adding the '[WIP]' prefix to the PR title. Please make sure your contributions adhere to our coding guidelines:
We encourage a “PR early” approach so create the PR as early as possible even without the fix/feature ready, so that devs and other contributors know you have picked up the issue. These early PRs should indicate an 'in progress' status by adding the '[WIP]' prefix to the PR title. Please make sure your contributions adhere to our coding guidelines:
* Pull requests adding features or refactoring should be opened against the `development` branch
* Pull requests fixing bugs in the latest release version should be opened again the `master` branch
* Write [good commit messages](https://chris.beams.io/posts/git-commit/)
## Code quality
### Code quality
Because 0x.js is used by multiple relayers in production and their businesses depend on it, we strive for exceptional code quality. Please follow the existing code standards and conventions. `tslint` and `prettier` (described below) will help you.
Because 0x.js is used by multiple relayers in production and their businesses depend on it, we strive for excellent code quality. Please follow the existing code standards and conventions. `tslint` (described below) will help you.
If you're adding functionality, please also add tests and make sure they pass. We have an automatic coverage reporting tool, so we'll see it if they are missing ;)
If you're adding a new public function/member, make sure you document it with Java doc-style comments. We use typedoc to generate [awesome documentation](https://0xproject.com/docs/0xjs) from the comments within our source code.
## Running and building
If the sub-package you are modifying has a `CHANGELOG.md` file, make sure to add an entry in it for the change made to the package. For published packages, only changes that modify the public interface or behavior of the package need a CHANGELOG entry.
First thing to do with an unknown code base is to run the tests.
We assume that you have `npm` and `yarn` installed.
### Styleguide
To do that:
* Install dependencies: `yarn`
* Initialize the testrpc state (migrate the contracts) by doing one of the following:
* Manual contracts migration:
* Run testrpc: `yarn testrpc`
* Clone the `[contracts](https://github.com/0xProject/contracts)` repo and run `yarn migrate`
* Use one of the existing testrpc snapshots
* Check out `circle.yml` for an example
* Run tests: `yarn test`
To build run: `yarn build`
We also recommend you read through the tests.
## Styleguide
We use `[tslint](https://palantir.github.io/tslint/)` with [custom configs](https://github.com/0xProject/tslint-config-0xproject) to keep our code style consistent.
We use [TSLint](https://palantir.github.io/tslint/) with [custom configs](https://github.com/0xProject/0x.js/tree/development/packages/tslint-config) to keep our code style consistent.
To lint your code just run: `yarn lint`
We also use [Prettier](https://prettier.io/) to auto-format our code. Be sure to either add a [text editor integration](https://prettier.io/docs/en/editors.html) or a [pre-commit hook](https://prettier.io/docs/en/precommit.html) to properly format your code changes.
If using the Atom text editor, we recommend you install the following packages:
* [atom-typescript](https://atom.io/packages/atom-typescript)
* [linter-tslint](https://atom.io/packages/linter-tslint)
* [prettier-atom](https://atom.io/packages/prettier-atom)
* [language-ethereum](https://atom.io/packages/language-ethereum)
Our CI will also run it as a part of the test run when you submit your PR.
Our CI will also run TSLint and Prettier as a part of the test run when you submit your PR. Make sure that the CI tests pass for your contribution.
### Branch structure & versioning
## Branch structure & versioning
We use [semantic versioning](http://semver.org/), but before we reach v1.0.0 all breaking changes as well as new features will be minor version bumps.
We use [semantic versioning](http://semver.org/), but before a package reaches v1.0.0 all breaking changes as well as new features will be minor version bumps.
We have two main branches: `master` and `development`.

62
ISSUE_TEMPLATE.md Normal file
View File

@@ -0,0 +1,62 @@
<!--- Thank you for taking the time to file an Issue -->
<!--- Before submitting please check to see if this issue was already reported -->
<!--- Provide a general summary of the issue in the Title above -->
## Expected Behavior
<!--- If you're describing a bug, tell us what should happen -->
<!--- If you're suggesting a package change/improvement, tell us how it should work -->
<!--- If you're suggesting a contract or protocol change/improvement, visit our ZEIPs repo -->
## Current Behavior
<!--- If describing a bug, tell us what happens instead of the expected behavior -->
<!--- If suggesting a change/improvement, explain the difference from current behavior -->
## Possible Solution
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
<!--- or ideas how to implement the addition or change -->
## Steps to Reproduce (for bugs)
<!--- Provide a link to a live example, or an unambiguous set of steps to -->
<!--- reproduce this bug. Include code to reproduce, if relevant -->
```
1.
2.
3.
```
## Context
<!--- How has this issue affected you? What are you trying to accomplish? -->
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
## Your Environment
<!--- Include as many relevant details about the environment you experienced the bug in -->
| Package | Version |
| ------------------: | :------ |
| `0x.js` | 0.25.0 |
| `Exchange Contract` | v1 |
| Network |
| ------- |
| NAME |
<!-- For example:
| mainnet |
| kovan |
| testrpc |
-->

View File

@@ -1,2 +1,36 @@
This PR:
*
<!--- Thank you for taking the time to submit a Pull Request -->
<!--- Provide a general summary of the issue in the Title above -->
## Description
<!--- Describe your changes in detail -->
## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->
## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->
## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply:
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
## Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
* [ ] Change requires a change to the documentation.
* [ ] Added tests to cover my changes.

106
README.md
View File

@@ -11,18 +11,104 @@ This repository contains all the 0x developer tools written in TypeScript. Our h
[![CircleCI](https://circleci.com/gh/0xProject/0x.js.svg?style=svg&circle-token=61bf7cd8c9b4e11b132089dfcffdd1be277d1e0c)](https://circleci.com/gh/0xProject/0x.js)
[![Coverage Status](https://coveralls.io/repos/github/0xProject/0x.js/badge.svg?branch=master&t=fp0cXD)](https://coveralls.io/github/0xProject/0x.js?branch=master)
[![Discord](https://img.shields.io/badge/chat-rocket.chat-yellow.svg?style=flat
)](https://chat.0xproject.com)
[![Discord](https://img.shields.io/badge/chat-rocket.chat-yellow.svg?style=flat)](https://chat.0xproject.com)
[![Join the chat at https://gitter.im/0xProject/Lobby](https://badges.gitter.im/0xProject/Lobby.svg)](https://gitter.im/0xProject/Lobby?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)
[![Greenkeeper badge](https://badges.greenkeeper.io/0xProject/0x.js.svg?token=7c22e5c72acf39d3ead8d29c5d9bb38f9096df3e643024dcedd53ab732847be1&ts=1496426342666)](https://greenkeeper.io/)
### Core Packages
### Published Packages
| Package | Version | Description |
|--------|-------|------------|
| [`0x.js`](/packages/0x.js) | [![npm](https://img.shields.io/npm/v/0x.js.svg?maxAge=2592000)](https://www.npmjs.com/package/0x.js) | A Javascript library for interacting with the 0x protocol |
| [`@0xproject/assert`](/packages/assert) | [![npm](https://img.shields.io/npm/v/@0xproject/assert.svg?maxAge=2592000)](https://www.npmjs.com/package/@0xproject/assert) | Standard type and schema assertions |
| [`@0xproject/connect`](/packages/connect) | [![npm](https://img.shields.io/npm/v/@0xproject/connect.svg?maxAge=2592000)](https://www.npmjs.com/package/@0xproject/connect) | A Javascript library for interacting with the standard relayer api |
| [`@0xproject/json-schemas`](/packages/json-schemas) | [![npm](https://img.shields.io/npm/v/@0xproject/json-schemas.svg?maxAge=2592000)](https://www.npmjs.com/package/@0xproject/json-schemas) | 0x-related json schemas |
| [`@0xproject/tslint-config`](/packages/tslint-config) | [![npm](https://img.shields.io/npm/v/@0xproject/tslint-config.svg?maxAge=2592000)](https://www.npmjs.com/package/@0xproject/tslint-config) | Custom 0x project TSLint rules |
| Package | Version | Description |
| -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| [`0x.js`](/packages/0x.js) | [![npm](https://img.shields.io/npm/v/0x.js.svg)](https://www.npmjs.com/package/0x.js) | A Javascript library for interacting with the 0x protocol |
| [`chai-as-promised-typescript-typings`](/packages/chai-as-promised-typescript-typings) | [![npm](https://img.shields.io/npm/v/chai-as-promised-typescript-typings.svg)](https://www.npmjs.com/package/chai-as-promised-typescript-typings) | Chai as promised typescript typings |
| [`chai-typescript-typings`](/packages/chai-typescript-typings) | [![npm](https://img.shields.io/npm/v/chai-typescript-typings.svg)](https://www.npmjs.com/package/chai-typescript-typings) | Chai typescript typings |
| [`web3-typescript-typings`](/packages/web3-typescript-typings) | [![npm](https://img.shields.io/npm/v/web3-typescript-typings.svg)](https://www.npmjs.com/package/web3-typescript-typings) | Web3 typescript typings |
| [`@0xproject/abi-gen`](/packages/abi-gen) | [![npm](https://img.shields.io/npm/v/@0xproject/abi-gen.svg)](https://www.npmjs.com/package/@0xproject/abi-gen) | Tool to generate TS wrappers from smart contract ABIs |
| [`@0xproject/assert`](/packages/assert) | [![npm](https://img.shields.io/npm/v/@0xproject/assert.svg)](https://www.npmjs.com/package/@0xproject/assert) | Type and schema assertions used by our packages |
| [`@0xproject/connect`](/packages/connect) | [![npm](https://img.shields.io/npm/v/@0xproject/connect.svg)](https://www.npmjs.com/package/@0xproject/connect) | A Javascript library for interacting with the standard relayer api |
| [`@0xproject/dev-utils`](/packages/dev-utils) | [![npm](https://img.shields.io/npm/v/@0xproject/dev-utils.svg)](https://www.npmjs.com/package/@0xproject/dev-utils) | Dev utils to be shared across 0x projects and packages |
| [`@0xproject/json-schemas`](/packages/json-schemas) | [![npm](https://img.shields.io/npm/v/@0xproject/json-schemas.svg)](https://www.npmjs.com/package/@0xproject/json-schemas) | 0x-related json schemas |
| [`@0xproject/subproviders`](/packages/subproviders) | [![npm](https://img.shields.io/npm/v/@0xproject/subproviders.svg)](https://www.npmjs.com/package/@0xproject/subproviders) | Useful web3 subproviders (e.g LedgerSubprovider) |
| [`@0xproject/tslint-config`](/packages/tslint-config) | [![npm](https://img.shields.io/npm/v/@0xproject/tslint-config.svg)](https://www.npmjs.com/package/@0xproject/tslint-config) | Custom 0x development TSLint rules |
| [`@0xproject/types`](/packages/types) | [![npm](https://img.shields.io/npm/v/@0xproject/types.svg)](https://www.npmjs.com/package/@0xproject/types) | Shared type declarations |
| [`@0xproject/utils`](/packages/utils) | [![npm](https://img.shields.io/npm/v/@0xproject/utils.svg)](https://www.npmjs.com/package/@0xproject/utils) | Shared utilities |
| [`@0xproject/web3-wrapper`](/packages/web3-wrapper) | [![npm](https://img.shields.io/npm/v/@0xproject/web3-wrapper.svg)](https://www.npmjs.com/package/@0xproject/web3-wrapper) | Web3 wrapper |
### Private Packages
| Package | Description |
| ----------------------------------------------------------- | ---------------------------------------------------------------- |
| [`@0xproject/contracts`](/packages/contracts) | 0x solidity smart contracts & tests |
| [`@0xproject/monorepo-scripts`](/packages/monorepo-scripts) | Shared monorepo scripts |
| [`@0xproject/testnet-faucets`](/packages/testnet-faucets) | A faucet micro-service that dispenses test ERC20 tokens or Ether |
| [`@0xproject/website`](/packages/website) | 0x website & Portal DApp |
## Usage
Dedicated documentation pages:
* [0x.js Library](https://0xproject.com/docs/0xjs)
* [0x Connect](https://0xproject.com/docs/connect)
* [Smart contracts](https://0xproject.com/docs/contracts)
* [Standard Relayer API](https://github.com/0xProject/standard-relayer-api/blob/master/README.md)
## 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
Build all packages
```bash
yarn lerna:run build
```
### Lint
Lint all packages
```bash
yarn lerna:run lint
```
### Run Tests
Before running the tests, you will need to spin up a [TestRPC](https://www.npmjs.com/package/ethereumjs-testrpc) instance and deploy all the 0x smart contracts.
In a separate terminal, start TestRPC (a convenience command is provided as part of this repo)
```bash
yarn testrpc
```
Then in your main terminal run
```
cd packages/contracts
yarn migrate
cd ..
```
And finally from the root project directory run
```bash
yarn lerna:run test
```

View File

@@ -1,9 +1,7 @@
{
"lerna": "2.5.1",
"packages": [
"packages/*"
],
"version": "independent",
"npmClient": "yarn",
"useWorkspaces": true
"lerna": "2.5.1",
"packages": ["packages/*"],
"version": "independent",
"npmClient": "yarn",
"useWorkspaces": true
}

View File

@@ -1,22 +1,26 @@
{
"private": true,
"name": "0x.js",
"workspaces": [
"packages/*"
],
"workspaces": ["packages/*"],
"scripts": {
"testrpc": "testrpc -p 8545 --networkId 50 -m \"${npm_package_config_mnemonic}\"",
"prettier": "prettier --write '**/*.{ts,tsx,json,md}' --config .prettierrc",
"prettier:ci": "prettier --list-different '**/*.{ts,tsx,json,md}' --config .prettierrc",
"lerna:run": "lerna run",
"lerna:publish": "yarn install; lerna run clean; lerna run build; lerna publish --registry=https://registry.npmjs.org/"
"lerna:rebuild": "lerna run clean; lerna run build;",
"lerna:publish":
"yarn install; lerna run clean; lerna run build; lerna publish --registry=https://registry.npmjs.org/"
},
"config": {
"mnemonic": "concert load couple harbor equip island argue ramp clarify fence smart topic"
"mnemonic": "concert load couple harbor equip island argue ramp clarify fence smart topic"
},
"devDependencies": {
"lerna": "^2.5.1",
"@0xproject/utils": "^0.2.0",
"async-child-process": "^1.1.1",
"semver-sort": "^0.0.4",
"ethereumjs-testrpc": "^6.0.3",
"lerna": "^2.5.1",
"prettier": "1.9.2",
"publish-release": "0xproject/publish-release",
"ethereumjs-testrpc": "6.0.3"
"semver-sort": "^0.0.4"
}
}

View File

@@ -1,11 +1,59 @@
# CHANGELOG
v0.27.1 - _November 28, 2017_
------------------------
## v0.31.1 - _February 1, 2018_
* Fix the bug causing order watcher to throw is makerToken === zrx (#357)
## v0.31.0 - _January 30, 2018_
* Add the `shouldAddPersonalMessagePrefix` parameter to `signOrderHashAsync` so that the
caller can decide on whether to add the personalMessage prefix before relaying the request
to the signer. Parity Signer, Ledger and TestRPC add the prefix themselves, Metamask expects
it to have already been added. (#349)
## v0.30.2 - _January 29, 2018_
* Add Rinkeby testnet addresses to artifacts (#337)
* Move @0xproject/types to dependencies from devDependencies fixing missing type errors
## v0.30.1 - _January 24, 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 +64,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 +137,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 +221,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 +245,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 +258,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.

View File

@@ -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:

View File

@@ -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 {
@@ -22,6 +20,6 @@ export class {{contractName}}Contract extends BaseContract {
{{/each}}
constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) {
super(web3ContractInstance, defaults);
classUtils.bindAll(this, ['web3ContractInstance', 'defaults']);
classUtils.bindAll(this, ['_web3ContractInstance', '_defaults']);
}
} // tslint:disable:max-file-line-count

View File

@@ -5,8 +5,8 @@ public {{this.name}} = {
): Promise<{{> return_type outputs=outputs}}> {
const self = this as {{contractName}}Contract;
const result = await promisify<{{> return_type outputs=outputs}}>(
self.web3ContractInstance.{{this.name}}.call,
self.web3ContractInstance,
self._web3ContractInstance.{{this.name}}.call,
self._web3ContractInstance,
)(
{{> params inputs=inputs}}
);

View File

@@ -9,7 +9,7 @@ public {{this.name}} = {
{{/this.payable}}
): Promise<string> {
const self = this as {{contractName}}Contract;
const txDataWithDefaults = await self.applyDefaultsToTxDataAsync(
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync(
txData,
self.{{this.name}}.estimateGasAsync.bind(
self,
@@ -17,7 +17,7 @@ public {{this.name}} = {
),
);
const txHash = await promisify<string>(
self.web3ContractInstance.{{this.name}}, self.web3ContractInstance,
self._web3ContractInstance.{{this.name}}, self._web3ContractInstance,
)(
{{> params inputs=inputs}}
txDataWithDefaults,
@@ -29,11 +29,11 @@ public {{this.name}} = {
txData: TxData = {},
): Promise<number> {
const self = this as {{contractName}}Contract;
const txDataWithDefaults = await self.applyDefaultsToTxDataAsync(
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync(
txData,
);
const gas = await promisify<number>(
self.web3ContractInstance.{{this.name}}.estimateGas, self.web3ContractInstance,
self._web3ContractInstance.{{this.name}}.estimateGas, self._web3ContractInstance,
)(
{{> params inputs=inputs}}
txDataWithDefaults,
@@ -45,7 +45,7 @@ public {{this.name}} = {
txData: TxData = {},
): string {
const self = this as {{contractName}}Contract;
const abiEncodedTransactionData = self.web3ContractInstance.{{this.name}}.getData();
const abiEncodedTransactionData = self._web3ContractInstance.{{this.name}}.getData();
return abiEncodedTransactionData;
},
};

View File

@@ -1,106 +1,94 @@
{
"name": "0x.js",
"version": "0.27.2",
"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/abi-gen": "^0.0.2",
"@0xproject/tslint-config": "^0.2.1",
"@0xproject/types": "^0.1.0",
"@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-templates": "^0.0.2",
"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.7",
"@0xproject/json-schemas": "^0.6.10",
"@0xproject/utils": "^0.1.0",
"@0xproject/web3-wrapper": "^0.1.0",
"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.31.0",
"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 --abis 'src/artifacts/@(Exchange|Token|TokenTransferProxy|EtherToken|TokenRegistry|DummyToken).json' --template contract_templates/contract.handlebars --partials 'contract_templates/partials/**/*.handlebars' --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.5",
"@0xproject/dev-utils": "^0.0.8",
"@0xproject/tslint-config": "^0.4.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.7",
"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.5",
"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.7",
"webpack": "^3.1.0"
},
"dependencies": {
"@0xproject/assert": "^0.0.14",
"@0xproject/json-schemas": "^0.7.6",
"@0xproject/types": "^0.1.7",
"@0xproject/utils": "^0.2.3",
"@0xproject/web3-wrapper": "^0.1.8",
"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.7.0",
"lodash": "^4.17.4",
"uuid": "^3.1.0",
"web3": "^0.20.0"
}
}

View File

@@ -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;
});

View File

@@ -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

View File

@@ -1,38 +1,24 @@
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 { TransactionReceiptWithDecodedLogs } from '@0xproject/types';
import { AbiDecoder, 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 {
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 { 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, SignedOrder, Web3Provider, ZeroExConfig, ZeroExError } from './types';
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 +116,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 +137,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 +148,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 +176,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 +206,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.
@@ -236,20 +232,22 @@ export class ZeroEx {
* @param orderHash Hex encoded orderHash to sign.
* @param signerAddress The hex encoded Ethereum address you wish to sign it with. This address
* must be available via the Web3.Provider supplied to 0x.js.
* @param shouldAddPersonalMessagePrefix Some signers add the personal message prefix `\x19Ethereum Signed Message`
* themselves (e.g Parity Signer, Ledger, TestRPC) and others expect it to already be done by the client
* (e.g Metamask). Depending on which signer this request is going to, decide on whether to add the prefix
* before sending the request.
* @return An object containing the Elliptic curve signature parameters generated by signing the orderHash.
*/
public async signOrderHashAsync(orderHash: string, signerAddress: string): Promise<ECSignature> {
public async signOrderHashAsync(
orderHash: string,
signerAddress: string,
shouldAddPersonalMessagePrefix: boolean,
): Promise<ECSignature> {
assert.isHexString('orderHash', orderHash);
await assert.isSenderAddressAsync('signerAddress', signerAddress, this._web3Wrapper);
let msgHashHex;
const nodeVersion = await this._web3Wrapper.getNodeVersionAsync();
const isParityNode = utils.isParityNode(nodeVersion);
const isTestRpc = utils.isTestRpc(nodeVersion);
if (isParityNode || isTestRpc) {
// Parity and TestRpc nodes add the personalMessage prefix itself
msgHashHex = orderHash;
} else {
let msgHashHex = orderHash;
if (shouldAddPersonalMessagePrefix) {
const orderHashBuff = ethUtil.toBuffer(orderHash);
const msgHashBuff = ethUtil.hashPersonalMessage(orderHashBuff);
msgHashHex = ethUtil.bufferToHex(msgHashBuff);
@@ -288,37 +286,48 @@ 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);
});
return txReceiptPromise;
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);
},
);
},
);
const txReceipt = await txReceiptPromise;
return txReceipt;
}
/*
* HACK: `TokenWrapper` needs a token transfer proxy address. `TokenTransferProxy` address is fetched from

View File

@@ -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,
};

View File

@@ -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"
}
]
}

View File

@@ -1,250 +1,287 @@
{
"contract_name": "EtherToken",
"abi": [
{
"constant": true,
"inputs": [],
"name": "name",
"outputs": [
"contract_name": "EtherToken",
"abi": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_spender",
"type": "address"
"constant": true,
"inputs": [],
"name": "name",
"outputs": [
{
"name": "",
"type": "string"
}
],
"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": false,
"inputs": [
{
"name": "_spender",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"name": "_to",
"type": "address"
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"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": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"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": "transfer",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [],
"name": "deposit",
"outputs": [],
"payable": true,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
"constant": false,
"inputs": [
{
"name": "amount",
"type": "uint256"
}
],
"name": "withdraw",
"outputs": [],
"payable": false,
"type": "function"
},
{
"name": "_spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"payable": true,
"type": "fallback"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_from",
"type": "address"
"constant": true,
"inputs": [],
"name": "decimals",
"outputs": [
{
"name": "",
"type": "uint8"
}
],
"payable": false,
"type": "function"
},
{
"indexed": true,
"name": "_to",
"type": "address"
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [
{
"name": "",
"type": "string"
}
],
"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": false,
"inputs": [],
"name": "deposit",
"outputs": [],
"payable": true,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
},
{
"name": "_spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"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": [
{
"indexed": true,
"name": "_owner",
"type": "address"
},
{
"indexed": true,
"name": "_spender",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
},
{
"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"
}
],
"name": "Transfer",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_owner",
"type": "address"
],
"networks": {
"1": {
"address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
},
{
"indexed": true,
"name": "_spender",
"type": "address"
"3": {
"address": "0xc00fd9820cd2898cc4c054b7bf142de637ad129a"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
"4": {
"address": "0xc778417e063141139fce010982780140aa0cd5ab"
},
"42": {
"address": "0x653e49e301e508a13237c0ddc98ae7d4cd2667a1"
},
"50": {
"address": "0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c"
}
],
"name": "Approval",
"type": "event"
}
],
"networks": {
"1": {
"address": "0x2956356cd2a2bf3202f771f50d3d14a367b48070"
},
"3": {
"address": "0xc00fd9820cd2898cc4c054b7bf142de637ad129a"
},
"42": {
"address": "0x05d090b51c40b020eab3bfcb6a2dff130df22e9c"
},
"50": {
"address": "0x48bacb9266a570d521063ef5dd96e61686dbe788"
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,172 +1,172 @@
{
"contract_name": "Token",
"abi": [
{
"constant": false,
"inputs": [
"contract_name": "Token",
"abi": [
{
"name": "_spender",
"type": "address"
"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"
"constant": false,
"inputs": [
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"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": true,
"inputs": [
{
"name": "_owner",
"type": "address"
},
{
"name": "_spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"name": "remaining",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"indexed": true,
"name": "_to",
"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": "Transfer",
"type": "event"
},
{
"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"
}
]
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,184 +1,187 @@
{
"contract_name": "TokenTransferProxy",
"abi": [
{
"constant": false,
"inputs": [
"contract_name": "TokenTransferProxy",
"abi": [
{
"name": "token",
"type": "address"
"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": [
{
"name": "",
"type": "address"
}
],
"name": "authorized",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getAuthorizedAddresses",
"outputs": [
{
"name": "",
"type": "address[]"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"payable": false,
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "target",
"type": "address"
"constant": false,
"inputs": [
{
"name": "target",
"type": "address"
}
],
"name": "removeAuthorizedAddress",
"outputs": [],
"payable": false,
"type": "function"
},
{
"indexed": true,
"name": "caller",
"type": "address"
}
],
"name": "LogAuthorizedAddressAdded",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "target",
"type": "address"
"constant": true,
"inputs": [],
"name": "owner",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"type": "function"
},
{
"indexed": true,
"name": "caller",
"type": "address"
"constant": true,
"inputs": [
{
"name": "",
"type": "address"
}
],
"name": "authorized",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getAuthorizedAddresses",
"outputs": [
{
"name": "",
"type": "address[]"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"payable": false,
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "target",
"type": "address"
},
{
"indexed": true,
"name": "caller",
"type": "address"
}
],
"name": "LogAuthorizedAddressAdded",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "target",
"type": "address"
},
{
"indexed": true,
"name": "caller",
"type": "address"
}
],
"name": "LogAuthorizedAddressRemoved",
"type": "event"
}
],
"networks": {
"1": {
"address": "0x8da0d80f5007ef1e431dd2127178d224e32c2ef4"
},
"3": {
"address": "0x4e9aad8184de8833365fea970cd9149372fdf1e6"
},
"4": {
"address": "0xa8e9fa8f91e5ae138c74648c9c304f1c75003a8d"
},
"42": {
"address": "0x087eed4bc1ee3de49befbd66c662b434b15d49d4"
},
"50": {
"address": "0x1dc4c1cefef38a777b15aa20260a54e584b16c48"
}
],
"name": "LogAuthorizedAddressRemoved",
"type": "event"
}
],
"networks": {
"1": {
"address": "0x8da0d80f5007ef1e431dd2127178d224e32c2ef4"
},
"3": {
"address": "0x4e9aad8184de8833365fea970cd9149372fdf1e6"
},
"42": {
"address": "0x087eed4bc1ee3de49befbd66c662b434b15d49d4"
},
"50": {
"address": "0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c"
}
}
}

View File

@@ -1,17 +1,20 @@
{
"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"
},
"4": {
"address": "0x00f58d6d585f84b2d7267940cede30ce2fe6eae8"
},
"42": {
"address": "0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570"
},
"50": {
"address": "0x1d7022f5b17d2f8b695918fb48fa1089c9f85401"
}
}
}
}

View File

@@ -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,
});
},
};

View File

@@ -1,27 +1,27 @@
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import {Block, BlockAndLogStreamer} from 'ethereumjs-blockstream';
import { LogWithDecodedArgs, RawLog } from '@0xproject/types';
import { AbiDecoder, 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,
IndexedFilterValues,
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 { 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 +34,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 +73,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 +110,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 +126,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 +153,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);
}
}
}

View File

@@ -1,40 +1,53 @@
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import BigNumber from 'bignumber.js';
import { schemas } from '@0xproject/json-schemas';
import { LogWithDecodedArgs } from '@0xproject/types';
import { AbiDecoder, 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,
TransactionOpts,
ZeroExError,
} from '../types';
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 +55,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 +67,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 +94,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;
}
}

View File

@@ -1,13 +1,14 @@
import {schemas} from '@0xproject/json-schemas';
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import BigNumber from 'bignumber.js';
import { schemas } from '@0xproject/json-schemas';
import { DecodedLogArgs, LogWithDecodedArgs } from '@0xproject/types';
import { AbiDecoder, 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,
DecodedLogArgs,
BlockRange,
ECSignature,
EventCallback,
ExchangeContractErrCodes,
@@ -15,10 +16,7 @@ import {
ExchangeContractEventArgs,
ExchangeEvents,
IndexedFilterValues,
LogCancelContractEventArgs,
LogErrorContractEventArgs,
LogFillContractEventArgs,
LogWithDecodedArgs,
MethodOpts,
Order,
OrderAddresses,
@@ -26,21 +24,18 @@ 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 { 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 +79,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 +102,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 +167,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 +231,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 +326,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 +406,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 +459,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 +508,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 +534,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 +580,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 +627,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 +651,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;
}
@@ -610,23 +675,35 @@ export class ExchangeWrapper extends ContractWrapper {
public unsubscribe(subscriptionToken: string): void {
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 +726,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 +748,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 +773,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 +794,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 +821,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,12 +841,12 @@ 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;
});
if (!_.isUndefined(errLog)) {
const logArgs = errLog.args;
const logArgs = (errLog as LogWithDecodedArgs<LogErrorContractEventArgs>).args;
const errCode = logArgs.errorId.toNumber();
const errMessage = this._exchangeContractErrCodesToMsg[errCode];
throw new Error(errMessage);
@@ -753,17 +857,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();
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 +884,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 +895,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;

View File

@@ -0,0 +1,6 @@
dummy_token.ts
ether_token.ts
exchange.ts
token_registry.ts
token_transfer_proxy.ts
token.ts

View File

@@ -1,12 +1,11 @@
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>;
protected async applyDefaultsToTxDataAsync<T extends TxData|TxDataPayable>(
protected _web3ContractInstance: Web3.ContractInstance;
protected _defaults: Partial<TxData>;
protected async _applyDefaultsToTxDataAsync<T extends TxData|TxDataPayable>(
txData: T,
estimateGasAsync?: (txData: T) => Promise<number>,
): Promise<TxData> {
@@ -16,7 +15,7 @@ export class BaseContract {
// 3. Gas estimate calculation + safety margin
const removeUndefinedProperties = _.pickBy;
const txDataWithDefaults = {
...removeUndefinedProperties(this.defaults),
...removeUndefinedProperties(this._defaults),
...removeUndefinedProperties(txData as any),
// HACK: TS can't prove that T is spreadable.
// Awaiting https://github.com/Microsoft/TypeScript/pull/13288 to be merged
@@ -28,7 +27,7 @@ export class BaseContract {
return txDataWithDefaults;
}
constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) {
this.web3ContractInstance = web3ContractInstance;
this.defaults = defaults;
this._web3ContractInstance = web3ContractInstance;
this._defaults = defaults;
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -1,29 +1,26 @@
import {schemas} from '@0xproject/json-schemas';
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import BigNumber from 'bignumber.js';
import { schemas } from '@0xproject/json-schemas';
import { LogWithDecodedArgs } from '@0xproject/types';
import { AbiDecoder, 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 { 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 +29,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 +48,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 +74,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 +106,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 +129,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 +151,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 +173,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 +205,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 +226,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 +266,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 +293,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 +314,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;
}
@@ -283,29 +339,42 @@ export class TokenWrapper extends ContractWrapper {
public unsubscribe(subscriptionToken: string): void {
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;
}
private _invalidateContractInstances(): void {
this.unsubscribeAll();
this._unsubscribeAll();
this._tokenContractsByAddress = {};
}
private async _getTokenContractAsync(tokenAddress: string): Promise<TokenContract> {
@@ -314,11 +383,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;

View File

@@ -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;
}
@@ -55,20 +41,3 @@ declare module 'truffle-hdwallet-provider' {
}
export = HDWalletProvider;
}
// abi-decoder declarations
interface DecodedLogArg {
}
interface DecodedLog {
name: string;
events: DecodedLogArg[];
}
declare module 'abi-decoder' {
import * as Web3 from 'web3';
const addABI: (abi: Web3.AbiDefinition) => void;
const decodeLogs: (logs: Web3.LogEntry[]) => DecodedLog[];
}
declare module 'web3/lib/solidity/coder' {
const decodeParams: (types: string[], data: string) => any[];
}

View File

@@ -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;
}
}

View File

@@ -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,13 +24,13 @@ export {
TransferContractEventArgs,
ApprovalContractEventArgs,
TokenContractEventArgs,
EtherTokenContractEventArgs,
WithdrawalContractEventArgs,
DepositContractEventArgs,
ContractEventArgs,
ContractEventArg,
Web3Provider,
ZeroExConfig,
TransactionReceipt,
TransactionReceiptWithDecodedLogs,
LogWithDecodedArgs,
EtherTokenEvents,
MethodOpts,
OrderTransactionOpts,
TransactionOpts,
@@ -42,3 +43,7 @@ export {
OrderStateInvalid,
OrderState,
} from './types';
export { ContractEventArg, LogWithDecodedArgs, TransactionReceiptWithDecodedLogs } from '@0xproject/types';
export { TransactionReceipt } from '@0xproject/types';

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -1,40 +1,40 @@
import {schemas} from '@0xproject/json-schemas';
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import { schemas } from '@0xproject/json-schemas';
import { LogWithDecodedArgs } from '@0xproject/types';
import { AbiDecoder, 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,
LogEvent,
LogFillContractEventArgs,
LogWithDecodedArgs,
OnOrderStateChangeCallback,
OrderState,
OrderStateWatcherConfig,
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 { 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 +73,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 +84,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 +115,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 +131,14 @@ 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);
if (zrxTokenAddress !== signedOrder.makerTokenAddress) {
this._removeFromDependentOrderHashes(signedOrder.maker, signedOrder.makerTokenAddress, orderHash);
}
this._expirationWatcher.removeOrder(orderHash);
}
/**
@@ -147,7 +156,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,37 +214,45 @@ 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> {
const maybeDecodedLog = this._abiDecoder.tryToDecodeLogOrNoop(log);
const isLogDecoded = !_.isUndefined((maybeDecodedLog as LogWithDecodedArgs<any>).event);
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<ContractEventArgs>(log);
const isLogDecoded = !_.isUndefined(((maybeDecodedLog as any) as LogWithDecodedArgs<ContractEventArgs>).event);
if (!isLogDecoded) {
return; // noop
}
const decodedLog = maybeDecodedLog as LogWithDecodedArgs<ContractEventArgs>;
const decodedLog = (maybeDecodedLog as any) as LogWithDecodedArgs<ContractEventArgs>;
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 +260,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 ExchangeEvents.LogFill:
{
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: {
// Invalidate cache
const args = decodedLog.args as LogFillContractEventArgs;
this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(args.orderHash);
@@ -258,8 +313,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 +347,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 +364,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 +374,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;
}

View File

@@ -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;
}
}

View File

@@ -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: {

View File

@@ -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 = {};
}
}

View File

@@ -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 = {};
}
}

View File

@@ -1,4 +1,5 @@
import BigNumber from 'bignumber.js';
import { ContractEventArg, LogWithDecodedArgs } 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,15 +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 enum SolidityTypes {
Address = 'address',
Uint256 = 'uint256',
Uint8 = 'uint8',
Uint = 'uint',
}
export type EventCallback<ArgsType> = (err: null | Error, log?: DecodedLogEvent<ArgsType>) => void;
export type EventWatcherCallback = (err: null | Error, log?: LogEvent) => void;
export enum ExchangeContractErrCodes {
ERROR_FILL_EXPIRED, // Order has already expired
@@ -93,8 +87,6 @@ export enum ExchangeContractErrs {
BatchOrdersMustHaveAtLeastOneItem = 'BATCH_ORDERS_MUST_HAVE_AT_LEAST_ONE_ITEM',
}
export type RawLog = Web3.LogEntry;
export interface ContractEvent {
logIndex: number;
transactionIndex: number;
@@ -134,7 +126,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 +140,20 @@ 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 interface Order {
maker: string;
@@ -200,7 +206,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 +227,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 +237,7 @@ export interface SubscriptionOpts {
export type DoneCallback = (err?: Error) => void;
export interface OrderCancellationRequest {
order: Order|SignedOrder;
order: Order | SignedOrder;
takerTokenCancelAmount: BigNumber;
}
@@ -234,6 +247,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
@@ -243,11 +257,6 @@ export type AsyncMethod = (...args: any[]) => Promise<any>;
*/
export type Web3Provider = Web3.Provider;
export interface JSONRPCPayload {
params: any[];
method: string;
}
/*
* orderExpirationCheckingIntervalMs: How often to check for expired orders. Default: 50
* eventPollingIntervalMs: How often to poll the Ethereum node for new events. Defaults: 200
@@ -266,8 +275,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,30 +284,13 @@ export interface ZeroExConfig {
networkId: number;
gasPrice?: BigNumber;
exchangeContractAddress?: string;
zrxContractAddress?: string;
tokenRegistryContractAddress?: string;
etherTokenContractAddress?: string;
tokenTransferProxyContractAddress?: string;
orderWatcherConfig?: OrderStateWatcherConfig;
}
export enum AbiType {
Function = 'function',
Constructor = 'constructor',
Event = 'event',
Fallback = 'fallback',
}
export interface DecodedLogArgs {
[argName: string]: ContractEventArg;
}
export interface LogWithDecodedArgs<ArgsType> extends Web3.DecodedLogEntry<ArgsType> {}
export interface TransactionReceiptWithDecodedLogs extends TransactionReceipt {
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 +374,7 @@ export interface OrderStateInvalid {
error: ExchangeContractErrs;
}
export type OrderState = OrderStateValid|OrderStateInvalid;
export type OrderState = OrderStateValid | OrderStateInvalid;
export type OnOrderStateChangeCallback = (orderState: OrderState) => void;
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

View File

@@ -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`,
);
},

View File

@@ -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,
};

View File

@@ -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),
};

View File

@@ -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));
}
}

View File

@@ -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);
}

View File

@@ -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);
},
};

View File

@@ -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 = {

View File

@@ -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,
signedOrder.makerTokenAddress,
signedOrder.maker,
signedOrder.taker,
fillMakerTokenAmount,
TradeSide.Maker,
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, 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);

View File

@@ -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),

View File

@@ -1,10 +1,11 @@
import BigNumber from 'bignumber.js';
import { SolidityTypes } from '@0xproject/types';
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 } from '../types';
export const utils = {
/**
@@ -20,29 +21,38 @@ export const utils = {
// tslint:disable-next-line: no-console
console.log(message);
},
isParityNode(nodeVersion: string): boolean {
return _.includes(nodeVersion, 'Parity');
},
isTestRpc(nodeVersion: string): boolean {
return _.includes(nodeVersion, 'TestRPC');
},
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);

View File

@@ -1,21 +1,22 @@
import BigNumber from 'bignumber.js';
import { BlockchainLifecycle, devConstants, web3Factory } 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';
const blockchainLifecycle = new BlockchainLifecycle();
chaiSetup.configure();
const expect = chai.expect;
const SHOULD_ADD_PERSONAL_MESSAGE_PREFIX = false;
describe('ZeroEx library', () => {
const web3 = web3Factory.create();
const config = {
@@ -41,11 +42,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 +59,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 +86,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 +118,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 +141,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 +170,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[] = [];
@@ -172,43 +199,53 @@ describe('ZeroEx library', () => {
r: '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33',
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
};
const ecSignature = await zeroEx.signOrderHashAsync(orderHash, makerAddress);
const ecSignature = await zeroEx.signOrderHashAsync(
orderHash,
makerAddress,
SHOULD_ADD_PERSONAL_MESSAGE_PREFIX,
);
expect(ecSignature).to.deep.equal(expectedECSignature);
});
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),
];
const ecSignature = await zeroEx.signOrderHashAsync(orderHash, makerAddress);
const ecSignature = await zeroEx.signOrderHashAsync(
orderHash,
makerAddress,
SHOULD_ADD_PERSONAL_MESSAGE_PREFIX,
);
expect(ecSignature).to.deep.equal(expectedECSignature);
});
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),
];
const ecSignature = await zeroEx.signOrderHashAsync(orderHash, makerAddress);
const ecSignature = await zeroEx.signOrderHashAsync(
orderHash,
makerAddress,
SHOULD_ADD_PERSONAL_MESSAGE_PREFIX,
);
expect(ecSignature).to.deep.equal(expectedECSignature);
});
});
@@ -244,22 +281,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,
);
});
});
});

View File

@@ -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;

View File

@@ -1,11 +1,11 @@
import { web3Factory } from '@0xproject/dev-utils';
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';
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);
});
});
});

View File

@@ -1,14 +1,29 @@
import BigNumber from 'bignumber.js';
import { BlockchainLifecycle, devConstants, web3Factory } 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';
chaiSetup.configure();
const expect = chai.expect;
@@ -23,24 +38,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 +78,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 +96,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 +104,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 +113,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 +131,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);
});
});
});

View File

@@ -1,22 +1,17 @@
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import BigNumber from 'bignumber.js';
import { web3Factory } from '@0xproject/dev-utils';
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';
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);
});
});

View File

@@ -1,14 +1,13 @@
import BigNumber from 'bignumber.js';
import { BlockchainLifecycle, devConstants, web3Factory } 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';
chaiSetup.configure();
const expect = chai.expect;
@@ -45,17 +44,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 +76,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 +91,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);

File diff suppressed because it is too large Load Diff

View File

@@ -1,23 +1,21 @@
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import BigNumber from 'bignumber.js';
import { BlockchainLifecycle, devConstants, web3Factory } 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 { FillScenarios } from './utils/fill_scenarios';
import { reportNoErrorCallbackErrors } from './utils/report_callback_errors';
import { TokenUtils } from './utils/token_utils';
chaiSetup.configure();
const expect = chai.expect;
@@ -56,13 +54,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 +76,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 +123,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 +143,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)) {

View File

@@ -1,33 +1,27 @@
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import BigNumber from 'bignumber.js';
import { BlockchainLifecycle, devConstants, web3Factory } 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';
const TIMEOUT_MS = 150;
@@ -48,7 +42,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 +58,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 +70,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 +92,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 +113,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 +125,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 +146,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 +169,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 +192,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 +241,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 +263,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 +284,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 +346,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 +359,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 +380,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 +412,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 +451,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 +506,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);

View File

@@ -1,19 +1,18 @@
import BigNumber from 'bignumber.js';
import { BlockchainLifecycle, devConstants, web3Factory } 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';
chaiSetup.configure();
const expect = chai.expect;
@@ -34,7 +33,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 +48,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 +61,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 +215,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 +282,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 +444,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);

View File

@@ -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);

View File

@@ -1,29 +1,18 @@
import BigNumber from 'bignumber.js';
import * as chai from 'chai';
import { BlockchainLifecycle, devConstants, web3Factory } 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';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle();
describe('SubscriptionTest', () => {
@@ -31,7 +20,6 @@ describe('SubscriptionTest', () => {
let zeroEx: ZeroEx;
let userAddresses: string[];
let tokens: Token[];
let tokenUtils: TokenUtils;
let coinbase: string;
let addressWithoutFunds: string;
const config = {
@@ -42,7 +30,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 +41,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(() => {
@@ -64,58 +49,34 @@ describe('SubscriptionTest', () => {
tokenAddress = token.address;
});
afterEach(() => {
zeroEx.token.unsubscribeAll();
zeroEx.token._unsubscribeAll();
_.each(stubs, s => s.restore());
stubs = [];
});
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')),
];
zeroEx.token.unsubscribeAll();
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);
});

View File

@@ -1,14 +1,13 @@
import {schemas, SchemaValidator} from '@0xproject/json-schemas';
import { BlockchainLifecycle, devConstants, web3Factory } 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';
chaiSetup.configure();
const expect = chai.expect;
@@ -19,10 +18,10 @@ 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';

View File

@@ -1,11 +1,10 @@
import { web3Factory } from '@0xproject/dev-utils';
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';
chaiSetup.configure();
const expect = chai.expect;

View File

@@ -1,31 +1,27 @@
import {promisify} from '@0xproject/utils';
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import BigNumber from 'bignumber.js';
import { BlockchainLifecycle, devConstants, web3Factory } 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';
chaiSetup.configure();
const expect = chai.expect;
@@ -71,25 +67,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 +103,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 +128,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 +148,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 +178,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 +198,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 +229,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 +251,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 +318,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 +369,6 @@ describe('TokenWrapper', () => {
});
describe('#subscribe', () => {
const indexFilterValues = {};
const shouldThrowOnInsufficientBalanceOrAllowance = true;
let tokenAddress: string;
const transferAmount = new BigNumber(42);
const allowanceAmount = new BigNumber(42);
@@ -363,7 +377,7 @@ describe('TokenWrapper', () => {
tokenAddress = token.address;
});
afterEach(() => {
zeroEx.token.unsubscribeAll();
zeroEx.token._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,
@@ -372,65 +386,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 +455,7 @@ describe('TokenWrapper', () => {
describe('#getLogsAsync', () => {
let tokenAddress: string;
let tokenTransferProxyAddress: string;
const subscriptionOpts: SubscriptionOpts = {
const blockRange: BlockRange = {
fromBlock: 0,
toBlock: BlockParamLiteral.Latest,
};
@@ -456,7 +471,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 +489,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 +506,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 +517,4 @@ describe('TokenWrapper', () => {
});
});
});
// tslint:disable:max-file-line-count

View File

@@ -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();
}
}

View File

@@ -1,12 +1,9 @@
export const constants = {
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
RPC_HOST: 'localhost',
RPC_PORT: 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,
};

View File

@@ -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 createFillableSignedOrderAsync(makerTokenAddress: string, takerTokenAddress: string,
makerAddress: string, takerAddress: string,
fillableAmount: BigNumber,
expirationUnixTimestampSec?: BigNumber):
Promise<SignedOrder> {
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> {
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);
}
}

View File

@@ -1,7 +1,9 @@
import BigNumber from 'bignumber.js';
import { BigNumber } from '@0xproject/utils';
import * as _ from 'lodash';
import {SignedOrder, ZeroEx} from '../../src';
import { SignedOrder, ZeroEx } from '../../src';
const SHOULD_ADD_PERSONAL_MESSAGE_PREFIX = false;
export const orderFactory = {
async createSignedOrderAsync(
@@ -16,11 +18,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,
@@ -36,8 +39,8 @@ export const orderFactory = {
expirationUnixTimestampSec,
};
const orderHash = ZeroEx.getOrderHashHex(order);
const ecSignature = await zeroEx.signOrderHashAsync(orderHash, maker);
const signedOrder: SignedOrder = _.assign(order, {ecSignature});
const ecSignature = await zeroEx.signOrderHashAsync(orderHash, maker, SHOULD_ADD_PERSONAL_MESSAGE_PREFIX);
const signedOrder: SignedOrder = _.assign(order, { ecSignature });
return signedOrder;
},
};

View File

@@ -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;
};

View File

@@ -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;
}
}

View File

@@ -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"
]
}

View File

@@ -1,5 +1,3 @@
{
"extends": [
"@0xproject/tslint-config"
]
"extends": ["@0xproject/tslint-config"]
}

View File

@@ -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 = {

View File

@@ -1,15 +0,0 @@
{
"name": "abi-gen-templates",
"private": true,
"version": "0.0.2",
"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"
}

View File

@@ -0,0 +1,11 @@
# CHANGELOG
## v0.2.0 - _???_
* Added CLI options for explicit specifying location of partials and main template (#346)
## 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)

View File

@@ -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.

View File

@@ -1,48 +1,48 @@
{
"name": "@0xproject/abi-gen",
"version": "0.0.2",
"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.1",
"@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.5",
"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.3",
"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.5",
"@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.7"
}
}

View File

@@ -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;
});

View File

@@ -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,29 +11,51 @@ 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 MAIN_TEMPLATE_NAME = 'contract.mustache';
const ABI_TYPE_EVENT = 'event';
const args = yargs
.option('abiGlob', {
.option('abis', {
describe: 'Glob pattern to search for ABI JSON files',
type: 'string',
demand: true,
})
.option('templates', {
describe: 'Folder where to search for templates',
type: 'string',
demand: true,
demandOption: true,
})
.option('output', {
alias: ['o', 'out'],
describe: 'Folder where to put the output files',
type: 'string',
demand: true,
normalize: true,
demandOption: true,
})
.argv;
.option('partials', {
describe: 'Glob pattern for the partial template files',
type: 'string',
implies: 'template',
})
.option('template', {
describe: 'Path for the main template file that will be used to generate each contract',
type: 'string',
demandOption: true,
normalize: true,
})
.example(
"$0 --abis 'src/artifacts/**/*.json' --out 'src/contracts/generated/' --partials 'src/templates/partials/**/*.handlebars' --template 'src/templates/contract.handlebars'",
'Full usage example',
).argv;
function registerPartials(partialsGlob: string) {
const partialTemplateFileNames = globSync(partialsGlob);
utils.log(`Found ${chalk.green(`${partialTemplateFileNames.length}`)} ${chalk.bold('partial')} templates`);
for (const partialTemplateFileName of partialTemplateFileNames) {
const namedContent = utils.getNamedContent(partialTemplateFileName);
Handlebars.registerPartial(namedContent.name, namedContent.content);
}
return partialsGlob;
}
function writeOutputFile(name: string, renderedTsCode: string): void {
const fileName = toSnakeCase(name);
@@ -44,15 +66,14 @@ function writeOutputFile(name: string, renderedTsCode: string): void {
Handlebars.registerHelper('parameterType', utils.solTypeToTsType.bind(utils, ParamKind.Input));
Handlebars.registerHelper('returnType', utils.solTypeToTsType.bind(utils, ParamKind.Output));
const partialTemplateFileNames = globSync(`${args.templates}/partials/**/*.mustache`);
for (const partialTemplateFileName of partialTemplateFileNames) {
const namedContent = utils.getNamedContent(partialTemplateFileName);
Handlebars.registerPartial(namedContent.name, namedContent.content);
}
const mainTemplate = utils.getNamedContent(`${args.templates}/${MAIN_TEMPLATE_NAME}`);
if (args.partials) {
registerPartials(args.partials);
}
const mainTemplate = utils.getNamedContent(args.template);
const template = Handlebars.compile<ContextData>(mainTemplate.content);
const abiFileNames = globSync(args.abiGlob);
const abiFileNames = globSync(args.abis);
if (_.isEmpty(abiFileNames)) {
utils.log(`${chalk.red(`No ABI files found.`)}`);
utils.log(`Please make sure you've passed the correct folder name and that the files have
@@ -66,14 +87,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 +116,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);

View File

@@ -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[];
}

View File

@@ -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: [],
};
},
};

View File

@@ -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"]
}

View File

@@ -1,5 +1,3 @@
{
"extends": [
"@0xproject/tslint-config"
]
"extends": ["@0xproject/tslint-config"]
}

Some files were not shown because too many files have changed in this diff Show More