Compare commits

..

440 Commits

Author SHA1 Message Date
Brandon Millman
a6f9718131 Publish
- 0x.js@0.27.2
 - abi-gen-templates@0.0.2
 - @0xproject/abi-gen@0.0.2
 - @0xproject/assert@0.0.7
 - @0xproject/connect@0.3.0
 - contracts@2.0.0
 - @0xproject/json-schemas@0.6.10
 - @0xproject/monorepo-scripts@0.1.0
 - @0xproject/subproviders@0.1.0
 - @0xproject/tslint-config@0.2.1
 - @0xproject/types@0.1.0
 - @0xproject/utils@0.1.0
 - @0xproject/web3-wrapper@0.1.0
 - website@0.0.2
2017-12-08 13:17:03 -08:00
Brandon Millman
47075edc97 Add scope to abi-gen dependency in 0x.js 2017-12-08 13:11:47 -08:00
Brandon Millman
25cee41358 Add @0xproject scope to abi-gen package name 2017-12-08 13:05:24 -08:00
Brandon Millman
d08d65a3af Add yarn install to lerna:publish command 2017-12-08 12:44:13 -08:00
Brandon Millman
d14ed71191 Make contracts package private 2017-12-08 12:41:31 -08:00
Brandon Millman
f341f62b2b Update connect changelog 2017-12-08 11:56:01 -08:00
Fabio Berger
828dffffed Merge pull request #252 from 0xProject/feature/addSubproviders
Add Subproviders Subpackage
2017-12-08 11:22:25 -06:00
Fabio Berger
af8d24d0eb Merge branch 'development' into feature/addSubproviders
* development:
  Update README.md
  Inline network module
  Stop supporting different file extensions in abi-gen
  Refactor networkId out of web3Wrapper
  Update connect types in preperation for publishing
  Fix CI command
  Address feedback
  Refactor web3Wrapper to a separate package

# Conflicts:
#	package.json
#	packages/website/ts/blockchain.ts
2017-12-08 11:21:51 -06:00
Fabio Berger
ca85a97106 remove console.log 2017-12-08 11:12:30 -06:00
Fabio Berger
5eea829be9 Update README.md 2017-12-08 11:05:53 -06:00
Fabio Berger
e822e3562d Fix unit test 2017-12-08 10:22:31 -06:00
Leonid
f109d132e4 Merge pull request #253 from 0xProject/feature/web3-wrapper
Refactor web3Wrapper to a separate package
2017-12-08 19:10:05 +03:00
Fabio Berger
1fc1eae39a Add missing params 2017-12-08 10:03:01 -06:00
Fabio Berger
deb6aeae43 Debug CircleCi failure 2017-12-08 09:57:34 -06:00
Fabio Berger
f48f126b3a Update yarn.lock 2017-12-08 09:49:08 -06:00
Leonid Logvinov
e0d79bd332 Inline network module 2017-12-08 18:47:50 +03:00
Fabio Berger
5e75aab8ea Add todo 2017-12-08 09:45:53 -06:00
Leonid
36125c3539 Merge branch 'development' into feature/web3-wrapper 2017-12-08 14:46:51 +03:00
Leonid Logvinov
72ced622d7 Stop supporting different file extensions in abi-gen 2017-12-08 13:25:00 +03:00
Leonid Logvinov
b362e2c28e Refactor networkId out of web3Wrapper 2017-12-08 12:51:46 +03:00
Brandon Millman
2260a0a4cd Merge pull request #256 from 0xProject/feature/standardSpecUpdate
Update connect types in preperation for publishing
2017-12-07 16:39:18 -08:00
Brandon Millman
3c64b33f5c Update connect types in preperation for publishing 2017-12-07 14:40:16 -08:00
Fabio Berger
5301086c68 Add link to random id generator 2017-12-07 15:32:01 -06:00
Fabio Berger
5687279c8d Remove prebuild command and add test:circleci 2017-12-07 15:21:35 -06:00
Fabio Berger
6c2bf8ed26 Merge branch 'development' into feature/addSubproviders
* development:
  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:23 -06:00
Fabio Berger
f1ecdcf602 Make sure we don't pass empty maker into getOrderHashHex 2017-12-07 14:53:14 -06:00
Fabio Berger
1eaefac12b Make sure we always pass in the correct networkId even if no injectedWeb3 found 2017-12-07 14:51:40 -06:00
Fabio Berger
be17b75ad3 remove unneeded reset 2017-12-06 22:31:20 -06:00
Fabio Berger
0c23f5e07e Use rejectedWith 2017-12-06 22:30:08 -06:00
Fabio Berger
86e1fa8153 Add missing calls to configure 2017-12-06 22:30:00 -06:00
Fabio Berger
fae0651b0c remove unneeded type assertions 2017-12-06 20:56:14 -06:00
Fabio Berger
720641f14c remove unused type 2017-12-06 20:53:23 -06:00
Fabio Berger
e8495b0c7b Simplify interface to signPersonalMessageAsync 2017-12-06 20:52:48 -06:00
Fabio Berger
e80579a605 Fix unit test 2017-12-06 19:49:27 -06:00
Fabio Berger
5967d39ca9 Fix ethereumjs-tx declaration and import 2017-12-06 19:48:38 -06:00
Fabio Berger
b82b50e2f0 Use assert.isHexString 2017-12-06 19:05:22 -06:00
Fabio Berger
e893e8c442 Add type defs for ledgerco and ethereumjs-tx 2017-12-06 19:05:09 -06:00
Fabio Berger
3db5efa264 Make test only run unit tests since cannot run integration tests on CI 2017-12-06 19:04:41 -06:00
Leonid Logvinov
5401c69163 Fix CI command 2017-12-07 01:24:48 +03:00
Fabio Berger
b7030cffd9 Improve README 2017-12-06 16:18:42 -06:00
Fabio Berger
73b4b4488e Fix version and remove the UMD build 2017-12-06 16:18:35 -06:00
Leonid Logvinov
825402b0f9 Address feedback 2017-12-07 01:15:15 +03:00
Fabio Berger
f23071a214 Fix tslint error 2017-12-06 16:13:24 -06:00
Leonid Logvinov
f1b267cc9f Refactor web3Wrapper to a separate package 2017-12-06 20:55:09 +03:00
Fabio Berger
adf1afc6ba Standardize deps 2017-12-06 11:00:57 -06:00
Fabio Berger
0abbdc6b96 Merge branch 'development' into feature/addSubproviders
* development:
  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

# Conflicts:
#	packages/website/package.json
#	yarn.lock
2017-12-06 10:49:22 -06:00
Leonid
598f1dd2d8 Merge pull request #250 from 0xProject/feature/airport-experiments
Compare versions script
2017-12-06 15:52:38 +03:00
Leonid
594bd2de1c Merge branch 'development' into feature/airport-experiments 2017-12-06 15:52:22 +03:00
Leonid Logvinov
55083316fc Inline function 2017-12-06 15:48:30 +03:00
Leonid Logvinov
8c87394b2b Introduce a const 2017-12-06 15:48:30 +03:00
Leonid Logvinov
1dba4b85d0 Make private 2017-12-06 15:48:30 +03:00
Leonid Logvinov
22de68205b Add version matcher script 2017-12-06 15:48:30 +03:00
Leonid Logvinov
f76543ebfa Use same versions of dependencies everywhere 2017-12-06 15:48:30 +03:00
Fabio Berger
f0c27f98b8 Add missing await 2017-12-05 22:17:52 -06:00
Fabio Berger
da678ba018 Move declaration into proper conditional block 2017-12-05 22:17:48 -06:00
Fabio Berger
86ed1b4554 Fix Party element so that an identicon's height is that which was passed in 2017-12-05 22:17:43 -06:00
Fabio Berger
06e348f80b Have comments hug statements 2017-12-05 21:48:02 -06:00
Fabio Berger
f05e0174a0 Add declaration 2017-12-05 21:47:44 -06:00
Fabio Berger
6bea3ac157 Return actual error thrown 2017-12-05 21:47:29 -06:00
Fabio Berger
e4d42a079c remove unused modules 2017-12-05 21:47:05 -06:00
Fabio Berger
5bbdb7a8f7 Use subproviders subpackage in website and remove old subproviders 2017-12-05 21:33:42 -06:00
Fabio Berger
3cf7cb1054 remove extra space 2017-12-05 21:32:42 -06:00
Fabio Berger
78274440cb Add initial tests fort redundantRpcSubprovider 2017-12-05 18:50:02 -06:00
Fabio Berger
e59934ca21 Add null to err type 2017-12-05 18:49:48 -06:00
Fabio Berger
c93bb4ef98 Use null instead of undefined when no error exists 2017-12-05 18:48:51 -06:00
Fabio Berger
e3763bade2 Switch to using our custom base subprovider 2017-12-05 18:48:30 -06:00
Fabio Berger
1ea1c02387 remove unused import 2017-12-05 18:48:17 -06:00
Fabio Berger
f6321a8e70 Fix lint issues 2017-12-05 16:33:18 -06:00
Fabio Berger
08168c6e7d Merge branch 'development' into feature/addSubproviders
* development: (50 commits)
  Add PR number to changelog
  Address feedback
  Add requestId to subscription messages and update json-schemas
  Remove isomorphic-fetch types from contracts package
  Update README
  Regenerate files
  Make it private
  Change package name
  Update README
  Make fileExtension configurable
  Rename abi-gen to typed-contracts
  Add docs for typed-contracts
  Remove TODOs
  Introduce separate ContextData type and rework it
  Check ABI is defined
  Introduce a const for 'contract.mustache'
  Improve error message
  Reuse util
  Fix a typo
  Introduce a const for 'function'
  ...

# Conflicts:
#	yarn.lock
2017-12-05 16:18:36 -06:00
Fabio Berger
b5030df4e3 Remove spaces 2017-12-05 16:14:11 -06:00
Fabio Berger
8414c18866 Make exception 2017-12-05 16:12:10 -06:00
Fabio Berger
038668efdf Port subproviders over to mono repo, refactor LedgerSubprovider to no longer rely on hookedWalletSubprovider. Added unit and integration tests. 2017-12-05 15:45:35 -06:00
Brandon Millman
4441d76725 Merge pull request #251 from 0xProject/feature/websocketVersion2
Add requestId to subscription messages and update json-schemas
2017-12-05 11:57:14 -08:00
Brandon Millman
1f494feec4 Add PR number to changelog 2017-12-05 11:55:31 -08:00
Leonid
1153fa093b Merge pull request #249 from 0xProject/feature/typed-contracts
ABI to TS generator
2017-12-05 22:39:36 +03:00
Leonid Logvinov
c64ec92fb2 Address feedback 2017-12-05 22:34:59 +03:00
Brandon Millman
20e28d6c70 Add requestId to subscription messages and update json-schemas 2017-12-05 11:28:32 -08:00
Brandon Millman
c0015c2c11 Remove isomorphic-fetch types from contracts package 2017-12-05 11:25:47 -08:00
Leonid Logvinov
3880f2b3cc Update README 2017-12-05 20:35:14 +03:00
Leonid Logvinov
293847053a Regenerate files 2017-12-05 20:34:39 +03:00
Leonid Logvinov
e042f49e27 Make it private 2017-12-05 20:26:35 +03:00
Leonid Logvinov
c036b96848 Change package name 2017-12-05 20:26:18 +03:00
Leonid Logvinov
e95dba2c25 Update README 2017-12-05 20:12:35 +03:00
Leonid Logvinov
9891d7aaa6 Make fileExtension configurable 2017-12-05 19:59:13 +03:00
Leonid Logvinov
1ce66b4a81 Rename abi-gen to typed-contracts 2017-12-05 19:53:59 +03:00
Leonid Logvinov
63b1199bd5 Add docs for typed-contracts 2017-12-05 18:49:24 +03:00
Fabio Berger
47789d770d bump version 2017-12-05 09:26:00 -06:00
Fabio Berger
df58593ff4 Move testrpc to top-level package.json and standardize some versions 2017-12-05 09:25:45 -06:00
Leonid Logvinov
e2ef7a74db Remove TODOs 2017-12-05 18:07:39 +03:00
Leonid Logvinov
cde52b10b1 Introduce separate ContextData type and rework it 2017-12-05 18:05:03 +03:00
Leonid Logvinov
43983f1bb3 Check ABI is defined 2017-12-05 17:51:47 +03:00
Leonid Logvinov
eb4adcf797 Introduce a const for 'contract.mustache' 2017-12-05 17:46:51 +03:00
Leonid Logvinov
32568ebf09 Improve error message 2017-12-05 17:11:35 +03:00
Leonid Logvinov
c53d195ed0 Reuse util 2017-12-05 17:11:07 +03:00
Leonid Logvinov
9b1c9ecb8b Fix a typo 2017-12-05 17:08:41 +03:00
Leonid Logvinov
8cd204423a Introduce a const for 'function' 2017-12-05 17:08:22 +03:00
Leonid Logvinov
2abc5a88c5 Use lodash's map 2017-12-05 17:07:22 +03:00
Leonid Logvinov
4c0bc02c48 Fix an error message 2017-12-05 17:05:48 +03:00
Leonid Logvinov
16b27c4ae8 Delete abi from typed-contracts 2017-12-05 17:04:46 +03:00
Leonid Logvinov
dc5f4ab28b Type to-snake-case 2017-12-05 17:04:01 +03:00
Leonid Logvinov
f88ecaa035 Fix a comment 2017-12-05 17:01:24 +03:00
Leonid Logvinov
c0cf47138e Add a comment 2017-12-05 16:59:36 +03:00
Leonid Logvinov
e1127dc2e8 Fix a typo 2017-12-05 16:56:50 +03:00
Leonid Logvinov
5d1b845cad Fix linter error 2017-12-01 23:32:44 -06:00
Leonid Logvinov
355514ca38 Update comment 2017-12-01 23:31:50 -06:00
Leonid Logvinov
518d0eba84 Add comments before generated contracts 2017-12-01 23:31:50 -06:00
Leonid Logvinov
78fb8d2bdc Use our promisify 2017-12-01 23:31:50 -06:00
Leonid Logvinov
5673b42ec4 Make target optional 2017-12-01 23:31:50 -06:00
Leonid Logvinov
438c8ff807 Remove es6-promisify 2017-12-01 23:31:50 -06:00
Leonid Logvinov
ee15143dd7 Remove all contract wrapper 2017-12-01 23:31:50 -06:00
Leonid Logvinov
042caa3363 Add async prefix 2017-12-01 23:31:50 -06:00
Leonid Logvinov
eb667f653c Adjust 0x.js to use generated wrappers 2017-12-01 23:31:50 -06:00
Leonid Logvinov
6cbd0d4537 Remove old contract typings 2017-12-01 23:31:11 -06:00
Leonid Logvinov
11bf2a0e06 Add depencies and a command to generate contract wrappers 2017-12-01 23:31:11 -06:00
Leonid Logvinov
9485e4f4f3 Add promisify 2017-12-01 23:31:11 -06:00
Leonid Logvinov
865ee090c8 Add class utils 2017-12-01 23:31:11 -06:00
Leonid Logvinov
0fc356740a Add generated contract wrappers 2017-12-01 23:31:11 -06:00
Leonid Logvinov
f285a46d05 Add generator CLI util 2017-12-01 23:31:11 -06:00
Leonid Logvinov
1e1c99d8d6 Add templates 2017-12-01 23:31:11 -06:00
Amir Bandeali
c291419141 Merge pull request #247 from 0xProject/feature/addContractsRepo
Add contracts repo
2017-12-01 11:29:27 -08:00
Amir Bandeali
290a96d41f Remove duplicate in gitignore 2017-12-01 11:24:55 -08:00
Amir Bandeali
ca9518c48c Make class methods that don't use 'this' static 2017-11-30 22:11:44 -08:00
Amir Bandeali
d44d6ccfd8 Fix module versions, cleanup scripts 2017-11-30 22:06:59 -08:00
Amir Bandeali
cec0b2afe3 Add README to contracts package 2017-11-30 07:34:48 -08:00
Amir Bandeali
e85a69655c Fix indentations 2017-11-30 07:10:18 -08:00
Amir Bandeali
4b3e038323 Add contracts to packages, fix most linting errors 2017-11-30 07:10:18 -08:00
Fabio Berger
c57190dead Add orderWatcher to 0x.js docs 2017-11-29 18:57:21 -06:00
Fabio Berger
3d73167f53 Merge branch 'development' of github.com:0xProject/0x.js into development
* 'development' of github.com:0xProject/0x.js:
  Publish
  Update CHANGELOG.md
  Redeclare Order, SignedOrder, and ECSignature types in connect, remove 0x.js dependency
  Add SignedOrder and TokenTradeInfo to public interface and fix a HttpClient comment
2017-11-29 15:15:35 -06:00
Fabio Berger
2eefec54b4 Add order and signedOrder to public types 2017-11-29 15:13:21 -06:00
Brandon Millman
ab72656fdf Publish
- @0xproject/connect@0.2.0
 - website@0.0.1
2017-11-29 12:39:54 -08:00
Brandon Millman
b6f2f98db6 Update CHANGELOG.md 2017-11-29 12:36:28 -08:00
Brandon Millman
c051c48600 Merge pull request #246 from 0xProject/fix/signedOrderInConnect
Redeclare Order, SignedOrder, and ECSignature types in connect, remov…
2017-11-29 12:24:26 -08:00
Brandon Millman
04fc16587b Redeclare Order, SignedOrder, and ECSignature types in connect, remove 0x.js dependency 2017-11-29 12:19:16 -08:00
Brandon Millman
f1d5a7d31f Merge pull request #245 from 0xProject/fix/exportedTypes
Add SignedOrder and TokenTradeInfo to public interface and fix a Http…
2017-11-29 11:48:28 -08:00
Brandon Millman
7197356928 Add SignedOrder and TokenTradeInfo to public interface and fix a HttpClient comment 2017-11-29 11:27:34 -08:00
Fabio Berger
a75d547af6 Add TokenTradeInfo to public types 2017-11-29 10:33:09 -06:00
Fabio Berger
bdecb18e3e Merge pull request #244 from 0xProject/feature/connect-docs
Add Connect Docs
2017-11-29 09:03:42 -06:00
Fabio Berger
e2adcaa185 Merge branch 'development' into feature/connect-docs
* development:
  Fix connect documentation introduction and installation wording

# Conflicts:
#	packages/website/md/docs/connect/installation.md
#	packages/website/md/docs/connect/introduction.md
2017-11-29 09:03:27 -06:00
Fabio Berger
4193893349 Rename @0xproject/connect to 0x Connect 2017-11-29 08:59:57 -06:00
Fabio Berger
53522a98b9 Rename packageName to displayName for clarity 2017-11-29 08:52:49 -06:00
Fabio Berger
0e856ccfab Fix phantom Contracts section issue 2017-11-29 08:48:11 -06:00
Fabio Berger
6093ee7824 Add 0x Connect to footer 2017-11-29 08:47:55 -06:00
Fabio Berger
46f185bbeb Update 0x.js to 0.27.1 2017-11-29 08:30:31 -06:00
Brandon Millman
8bfa880371 Fix connect documentation introduction and installation wording 2017-11-28 16:28:57 -08:00
Fabio Berger
a7f0d03611 Lock the 0x.js version used in website 2017-11-28 16:22:18 -06:00
Fabio Berger
9ce899d3f3 Merge branch 'development' into feature/connect-docs
* development:
  rename for clarity
  remove unused code
  Publish
2017-11-28 16:06:44 -06:00
Fabio Berger
e71c7fdb16 Merge pull request #243 from 0xProject/fix/refactorDocs
Refactor docs
2017-11-28 16:06:09 -06:00
Fabio Berger
4258e6dab1 rename for clarity 2017-11-28 16:05:13 -06:00
Fabio Berger
e59b683047 remove unused code 2017-11-28 16:05:04 -06:00
Fabio Berger
3c3033586d Add 0x Connect Docs to the menu and topBar 2017-11-28 16:02:31 -06:00
Fabio Berger
166c741beb Add connect docs 2017-11-28 15:42:37 -06:00
Fabio Berger
629a0fa3a5 Add subPackageName and get rid of hard-coded 0x.js in sourceLink 2017-11-28 15:42:27 -06:00
Fabio Berger
15ce862334 Merge branch 'development' into fix/refactorDocs
* development: (30 commits)
  Export TransactionOpts type
  Make website private
  Publish
  Update CHANGELOG
  Change interval to 1h
  Rename
  Add ifExists to cleanupJobInterval
  Add a cleanup job to an order watcher
  Improve the comment
  Add CHANGELOG comment
  Add a HACK comment
  Normalise subprovider names
  Remove a comment
  Fix a typo
  Pin testrpc version
  Remove gas params from tests
  Add fake gas estimate suprovider for tests
  Revert "Fix website linter errors"
  Fix website linter errors
  Fix tests
  ...

# Conflicts:
#	packages/website/ts/utils/constants.ts
2017-11-28 15:21:15 -06:00
Leonid Logvinov
840557be0d Publish
- 0x.js@0.27.1
 - @0xproject/connect@0.1.2
 - website@0.0.0
2017-11-28 15:14:32 -06:00
Fabio Berger
72a00ac2df Refactor the topLevel documentation react components for 0x.js and Smart contracts into a single component 2017-11-28 15:11:04 -06:00
Leonid Logvinov
da0af12834 Export TransactionOpts type 2017-11-28 14:54:52 -06:00
Leonid Logvinov
7617b6681c Make website private 2017-11-28 14:51:38 -06:00
Leonid Logvinov
8e13c477a3 Publish
- 0x.js@0.27.0
 - @0xproject/assert@0.0.6
 - @0xproject/connect@0.1.1
 - @0xproject/json-schemas@0.6.9
 - @0xproject/tslint-config@0.2.0
 - website@0.0.0
2017-11-28 14:47:42 -06:00
Leonid Logvinov
ff334b0e53 Update CHANGELOG 2017-11-28 14:42:55 -06:00
Leonid
a98d6bf496 Merge pull request #235 from 0xProject/feature/gasPriceGasLimit
Add optional config for gasPrice and gasLimit for every transaction sending method
2017-11-28 14:37:33 -06:00
Leonid
bbcf669bd9 Merge pull request #242 from 0xProject/feature/orderWatcherCleanup
Add a cleanup job to an order watcher
2017-11-28 14:37:15 -06:00
Leonid Logvinov
328ecd0533 Change interval to 1h 2017-11-28 14:33:08 -06:00
Leonid Logvinov
ab91717199 Rename 2017-11-28 14:27:39 -06:00
Leonid Logvinov
e4dfdc6b5c Add ifExists to cleanupJobInterval 2017-11-28 14:27:16 -06:00
Leonid Logvinov
9e673f0073 Add a cleanup job to an order watcher 2017-11-28 14:11:00 -06:00
Leonid Logvinov
353abffba9 Improve the comment 2017-11-28 12:23:41 -06:00
Leonid Logvinov
bead76a5b7 Add CHANGELOG comment 2017-11-28 12:16:02 -06:00
Leonid Logvinov
9f5e724aec Add a HACK comment 2017-11-28 12:13:50 -06:00
Leonid Logvinov
50bf6a991d Normalise subprovider names 2017-11-28 12:12:25 -06:00
Leonid Logvinov
1d584b1329 Remove a comment 2017-11-28 12:10:06 -06:00
Leonid Logvinov
0c5a9fbc2c Fix a typo 2017-11-28 12:06:11 -06:00
Leonid Logvinov
d5e58ecdd8 Pin testrpc version 2017-11-28 12:05:32 -06:00
Leonid Logvinov
d6a9e7520d Remove gas params from tests 2017-11-28 11:51:10 -06:00
Leonid Logvinov
36b21e6e7b Add fake gas estimate suprovider for tests 2017-11-28 11:44:10 -06:00
Leonid Logvinov
977a6b2794 Revert "Fix website linter errors"
This reverts commit 6e2a69976b.
2017-11-28 11:43:42 -06:00
Fabio Berger
fcddd503b7 Fix tslint error 2017-11-28 11:16:42 -06:00
Fabio Berger
3472bdcfd4 Refactor docs to be more declarative, put all hard-coded doc-related data in one place so it easier to add new doc pages 2017-11-28 11:16:35 -06:00
Fabio Berger
78f0ab3682 Last remaining website fixes 2017-11-27 22:23:51 -06:00
Fabio Berger
5a59ac4c6b fix remaining tslint errors 2017-11-27 22:08:08 -06:00
Fabio Berger
0a19ba3014 Fix tslint issues 2017-11-27 21:38:09 -06:00
Fabio Berger
88bd0f5328 Add lint command to website sub-package 2017-11-27 19:58:53 -06:00
Leonid Logvinov
6e2a69976b Fix website linter errors 2017-11-27 18:06:15 -06:00
Leonid Logvinov
0500602ac3 Fix tests 2017-11-27 17:38:38 -06:00
Leonid Logvinov
e6887dc9d4 Fix a comment 2017-11-27 17:37:55 -06:00
Leonid Logvinov
082c5c375e Fix tests 2017-11-27 17:37:55 -06:00
Leonid Logvinov
5977fa881e Increase gas margin 2017-11-27 17:37:23 -06:00
Leonid Logvinov
128fccb763 Fix defaults for shouldValidate 2017-11-27 17:37:23 -06:00
Leonid Logvinov
65697f5896 Update MAX_REASONABLE_GAS_COST_IN_WEI 2017-11-27 17:37:23 -06:00
Leonid Logvinov
ee93f091ea Add gas margin and remove undefined values 2017-11-27 17:37:22 -06:00
Leonid Logvinov
33a8c7a9fb Update testrpc 2017-11-27 17:37:22 -06:00
Leonid Logvinov
d1065cd266 Add an initializer for txOpts in etherToken 2017-11-27 17:36:27 -06:00
Leonid Logvinov
0e44a630f0 Add CHANGELOG entry 2017-11-27 17:36:27 -06:00
Leonid Logvinov
7a21c6854b Add option config for gasPrice and gasLimit for every transaction sending method 2017-11-27 17:35:55 -06:00
Fabio Berger
54ef916b93 Merge pull request #233 from 0xProject/feature/passNetworkId
Forces the users of 0x.js to pass the network id
2017-11-27 17:15:18 -06:00
Brandon Millman
4a770dee84 Merge pull request #241 from 0xProject/fix/moveConnectTypes
Move all connect types into types.ts
2017-11-27 14:42:26 -08:00
Brandon Millman
426a412ba1 Move all connect types into types.ts 2017-11-27 14:34:34 -08:00
Leonid Logvinov
f862a2af6d Fix tests 2017-11-27 16:32:33 -06:00
Leonid Logvinov
32867c9a07 Fix merge conflicts 2017-11-27 16:03:57 -06:00
Leonid
cf0a8b2d05 Merge branch 'development' into feature/passNetworkId 2017-11-27 15:53:21 -06:00
Brandon Millman
4a17f5e820 Merge pull request #240 from 0xProject/fix/websiteMdDirectory
Add md directory to website package and change generated docs directory
2017-11-27 13:02:08 -08:00
Fabio Berger
694c37150c Merge pull request #239 from 0xProject/fix/docs
Fix 0x.js Doc Issues
2017-11-27 14:44:32 -06:00
Brandon Millman
b04d07815f Add md directory to website package and change generated docs directory 2017-11-27 12:12:19 -08:00
Fabio Berger
e7b523074a remove comment 2017-11-27 12:24:11 -06:00
Fabio Berger
4e03155588 Add link to Provider explanation 2017-11-27 12:06:03 -06:00
Fabio Berger
3e5abc60d3 Add "Web3" prefix to web3 alias types and link to the correct line in the web3 typings 2017-11-27 12:05:39 -06:00
Fabio Berger
edf80aba1a Fix overlapping arg names 2017-11-27 10:56:33 -06:00
Fabio Berger
25ec4cf7b0 Fix source links in 0x.js docs 2017-11-27 10:25:53 -06:00
Fabio Berger
48b3d85265 Merge pull request #237 from 0xProject/addWebsite
Add Website to Mono Repo
2017-11-27 10:05:47 -06:00
Fabio Berger
ecfee00fec Fix subscriptions given latest changes to 0x.js 2017-11-23 18:21:48 -06:00
Fabio Berger
b5ce876327 Update CHANGELOG.md 2017-11-23 17:35:53 -06:00
Fabio Berger
d1342c6326 Merge branch 'development' into addWebsite
* development: (41 commits)
  Add validation fix to changelog
  Fix tests now that we no longer fire duplicate orderWatcher events
  Add comment about BlockParamLiteral explaining the omission of Earliest
  Add missing type
  Pass 'latest' to ExchangeTransferSimulator when used for validating orders, and pass 'pending' when used in the order watcher.
  Remove `Earliest` from blockParamLiterals since specifying block 0 is trivial and this type can be reused in situations where the options are pending or latest
  Rename removed to isRemoved
  Add CHANGELOG entry
  Make DecodedLogEvent contain web3 log under a log subkey
  Update to Async call
  Fix nits
  Add @0xproject/connect to the main README
  Fix connect CHANGELOG version
  Publish
  Fix npm auth issues
  Perform the division last to not compound any errors
  add a test constant for ZRX decimals
  Add a test for when the ratio is < 1
  Remove only
  calculatedFillableAmountPlusFees
  ...
2017-11-23 17:08:20 -06:00
Fabio Berger
d3dcb2fd40 Add validation fix to changelog 2017-11-23 17:05:12 -06:00
Fabio Berger
c448d048fd Merge pull request #236 from 0xProject/fix/validateOrdersAgainstLatestBlock
Fix/validate orders against latest block
2017-11-23 17:02:57 -06:00
Fabio Berger
f0b3ee84b4 Fix tests now that we no longer fire duplicate orderWatcher events 2017-11-23 15:56:42 -06:00
Fabio Berger
ab78c54d6a Add comment about BlockParamLiteral explaining the omission of Earliest 2017-11-23 15:36:46 -06:00
Fabio Berger
cee0d2706f Add missing type 2017-11-23 15:32:00 -06:00
Fabio Berger
8dea47f038 Merge branch 'development' into validateOrdersAgainstLatestBlock
* development:
  Rename removed to isRemoved
  Add CHANGELOG entry
  Make DecodedLogEvent contain web3 log under a log subkey
2017-11-23 15:24:32 -06:00
Fabio Berger
b7b1721145 Pass 'latest' to ExchangeTransferSimulator when used for validating orders, and pass 'pending' when used in the order watcher. 2017-11-23 15:21:45 -06:00
Fabio Berger
5068f1666a Remove Earliest from blockParamLiterals since specifying block 0 is trivial and this type can be reused in situations where the options are pending or latest 2017-11-23 15:20:20 -06:00
Leonid Logvinov
37f0051d83 Update CHANGELOG.md 2017-11-23 15:16:04 -06:00
Leonid Logvinov
c780d04cee Remove ContractDoesNotExist error and replace it with more specific errors 2017-11-23 15:15:47 -06:00
Leonid Logvinov
8c54e9a873 Add a regression test 2017-11-23 15:15:47 -06:00
Leonid Logvinov
062f85e506 Pass networkId on provider update 2017-11-23 15:15:47 -06:00
Leonid Logvinov
b3c0d54acd Fix linter issue 2017-11-23 15:15:47 -06:00
Leonid Logvinov
3d11afd872 Remove outdated comment 2017-11-23 15:15:47 -06:00
Leonid Logvinov
96d15a8931 Improve a comment 2017-11-23 15:15:47 -06:00
Leonid Logvinov
50915e6007 Add a comment 2017-11-23 15:15:47 -06:00
Leonid Logvinov
52007e5864 Reuse the protected function to get contract address 2017-11-23 15:15:47 -06:00
Leonid Logvinov
0c74d5ba01 Move variable declaration inside the if 2017-11-23 15:15:47 -06:00
Leonid Logvinov
0cd1959706 Update CHANGELOG.md 2017-11-23 15:15:17 -06:00
Leonid Logvinov
55ddf62df2 Fix rebasing issues 2017-11-23 15:15:17 -06:00
Leonid Logvinov
7f69d26247 Add CHANGELOG entry 2017-11-23 15:15:17 -06:00
Leonid Logvinov
b3c01f6750 Revert "Remove redundant async"
This reverts commit 8d11ababd62d947e338757f57c41179510b11338.
2017-11-23 15:15:00 -06:00
Leonid Logvinov
34beee1edc Refactor getContractAddress to contractWrapper 2017-11-23 15:15:00 -06:00
Leonid Logvinov
7bc6a7b23f Remove redundant async 2017-11-23 15:13:38 -06:00
Leonid Logvinov
4a19655fb0 Fix the artifacts 2017-11-23 15:13:38 -06:00
Leonid Logvinov
e32c453bc3 Remove unused asyncs 2017-11-23 15:13:38 -06:00
Leonid Logvinov
7b8d9193e2 Auto-fix linter errors in other mono-repo packages 2017-11-23 15:13:37 -06:00
Leonid Logvinov
74633126ce Add type information for the linter 2017-11-23 15:13:37 -06:00
Leonid Logvinov
2fa5bb2028 Autofix json-schemas linter errors 2017-11-23 15:13:37 -06:00
Leonid Logvinov
010e6f8d7f Fix the imports order 2017-11-23 15:13:37 -06:00
Leonid Logvinov
3d5b6ec110 Enforce comments on public methods 2017-11-23 15:13:37 -06:00
Leonid Logvinov
db2917b01c Enable some new linter rules and fix the issues 2017-11-23 15:13:37 -06:00
Leonid Logvinov
87d34f9c7f Auto-fix linter errors 2017-11-23 15:13:37 -06:00
Leonid Logvinov
d20926e150 Don't reassign the parameter 2017-11-23 15:13:37 -06:00
Leonid Logvinov
c453099f6b Fix linter issues 2017-11-23 15:13:37 -06:00
Leonid Logvinov
08569dbe6c Await block reconcilation 2017-11-23 15:13:37 -06:00
Leonid Logvinov
a38ef3655b Remove even more asyncs 2017-11-23 15:13:37 -06:00
Leonid Logvinov
c586d3e81d Add project config to tslint which enables some type-dependent rules 2017-11-23 15:13:37 -06:00
Leonid Logvinov
c72745b0b2 Make zeroEx.tokenRegistry.getContractAddress non-async 2017-11-23 15:13:37 -06:00
Leonid Logvinov
8935146240 Make exchange subscriptions non-async 2017-11-23 15:13:37 -06:00
Leonid Logvinov
66aaceea91 Cleanup order watcher from redundant asyncs 2017-11-23 15:13:36 -06:00
Leonid Logvinov
4fe28ec53c Make zeroEx.exchange.getContractAddress non-async 2017-11-23 15:13:36 -06:00
Leonid Logvinov
efe8e07854 Add ZRX artifacts 2017-11-23 15:13:36 -06:00
Leonid Logvinov
63dc606a9c Make getZRXTokenAddress non async 2017-11-23 15:13:36 -06:00
Leonid Logvinov
131236305b Store networkId in web3Wrapper 2017-11-23 15:13:36 -06:00
Leonid Logvinov
45c9171a2c Add networkId to zeroExConfig schema 2017-11-23 15:13:36 -06:00
Leonid Logvinov
311d42626a Adjust the tests 2017-11-23 15:13:36 -06:00
Leonid Logvinov
cbf35de4c1 Fix CI tests 2017-11-23 15:13:36 -06:00
Leonid Logvinov
92efc65847 Add networkId to ZeroExConfig and make it required 2017-11-23 15:13:36 -06:00
Leonid
17e41f2391 Merge pull request #234 from 0xProject/feature/eventTypes
Make DecodedLogEvent contain web3 log under a log subkey
2017-11-23 15:13:07 -06:00
Leonid Logvinov
fcd37808d4 Rename removed to isRemoved 2017-11-23 15:12:34 -06:00
Leonid Logvinov
6323badc19 Add CHANGELOG entry 2017-11-23 15:12:34 -06:00
Leonid Logvinov
e01468b492 Make DecodedLogEvent contain web3 log under a log subkey 2017-11-23 15:12:34 -06:00
Fabio Berger
f7f2390ce1 Add exit code 0 because it is expected that uglifying the code throws an error 2017-11-23 14:01:23 -06:00
Fabio Berger
6118561bb5 update tokenByAddress after tokenStateByAddress to avoid race-condition 2017-11-23 13:58:27 -06:00
Fabio Berger
6a9f10cd36 Add error when unexpected condition hit 2017-11-23 13:57:01 -06:00
Fabio Berger
e7a4e03194 Fix alignment 2017-11-23 13:56:42 -06:00
Fabio Berger
a42e8ae873 Add missing keys 2017-11-23 13:56:34 -06:00
Fabio Berger
bcc5d63516 Fix bug 2017-11-23 13:56:16 -06:00
Fabio Berger
f97074dc84 Merge pull request #230 from 0xProject/feature/removeDuplicateEvents
Add an order state cache to filter out duplicate events
2017-11-23 12:35:18 -06:00
Fabio Berger
bd81124b5a Merge pull request #226 from dekz/feature/calculate-remaining-proportions
Calculate remaining proportions from fee to ratio proportions
2017-11-23 12:33:06 -06:00
Jacob Evans
5a18f43b51 Update to Async call 2017-11-23 15:17:11 +11:00
Jacob Evans
924b96ce2a Fix nits 2017-11-23 15:14:33 +11:00
Jacob Evans
47236dbaec Merge branch 'development' into feature/calculate-remaining-proportions 2017-11-23 14:38:10 +11:00
Jacob Evans
437ac301db Merge branch 'development' into feature/calculate-remaining-proportions 2017-11-23 14:37:34 +11:00
Brandon Millman
215740fab2 Add @0xproject/connect to the main README 2017-11-22 15:39:05 -08:00
Fabio Berger
c66fc63452 Merge branch 'development' into addWebsite
* development:
  Revert "Publish"
  Publish
  Add actual version to CHANGELOG
  Add blockchainLifecycle management to the ExpirationWatcher test
  Update connect CHANGELOG.md in preperation for publishing
  Add TODO comment before BigNumber.config() call
  Prepare connect package for publishing
2017-11-22 17:26:48 -06:00
Brandon Millman
02aefc40f3 Fix connect CHANGELOG version 2017-11-22 15:10:50 -08:00
Brandon Millman
cd42ca1bbd Publish
- 0x.js@0.26.1
     - @0xproject/connect@0.1.0
2017-11-22 15:07:34 -08:00
Brandon Millman
05bfd764b6 Fix npm auth issues
Related lerna issue: https://github.com/lerna/lerna/issues/896
2017-11-22 15:05:03 -08:00
Fabio Berger
99f2026ce2 Revert "Publish"
This reverts commit 6a8717b294.
2017-11-22 16:51:09 -06:00
Fabio Berger
6a8717b294 Publish
- 0x.js@0.26.1
 - @0xproject/connect@0.1.0
2017-11-22 16:50:16 -06:00
Fabio Berger
c3f24a9cea Add actual version to CHANGELOG 2017-11-22 16:47:24 -06:00
Fabio Berger
805a055946 Force the clearance of tradeHistory 2017-11-22 16:43:17 -06:00
Brandon Millman
c0e17f6136 Add blockchainLifecycle management to the ExpirationWatcher test 2017-11-22 14:20:45 -08:00
Brandon Millman
b38142ddb1 Update connect CHANGELOG.md in preperation for publishing 2017-11-22 13:54:07 -08:00
Brandon Millman
0b29514836 Merge pull request #232 from 0xProject/feature/prepareConnectForPublish
Prepare connect package for publishing
2017-11-22 13:31:16 -08:00
Brandon Millman
27ce87f652 Add TODO comment before BigNumber.config() call 2017-11-22 13:26:15 -08:00
Brandon Millman
a61a7b688a Prepare connect package for publishing 2017-11-22 13:12:17 -08:00
Fabio Berger
f74408f390 Merge branch 'development' into addWebsite
* development: (33 commits)
  Last renames
  Refactor while condition
  Fix tests
  Fix tests
  Fix a typo
  Fix test:circleci command
  Check if transactionReceipt exists before normalizing it
  Address nits
  Remove old comment
  Fix async callbacks
  Check if callback exists
  Rename
  Pass callback down
  Remove custom heap and use bintrees
  Add expirationMarginMs
  Add defaults
  Fix typos
  Rename orderLifetime to orderLifetimeS
  Reference types directly
  Add ifExists suffix
  ...
2017-11-22 14:22:22 -06:00
Fabio Berger
f5e0fd8de5 Upgrade to latest 0x.js version and refactor subscriptions to use latest interface 2017-11-22 14:21:07 -06:00
Fabio Berger
353b6f3d6d add bundles to gitignore 2017-11-22 14:20:35 -06:00
Fabio Berger
cb377f29c2 Fix build bug 2017-11-22 14:20:24 -06:00
Leonid
0e03ef385b Merge pull request #227 from 0xProject/feature/orderExpired
Add expirationWatcher
2017-11-22 12:02:31 -06:00
Leonid Logvinov
ac2c723ec9 Last renames 2017-11-22 11:56:34 -06:00
Leonid Logvinov
3fc0eae4c0 Refactor while condition 2017-11-22 11:44:34 -06:00
Leonid
beed223281 Merge branch 'development' into feature/orderExpired 2017-11-22 11:24:59 -06:00
Jacob Evans
9c9ce97525 Perform the division last to not compound any errors 2017-11-22 11:08:39 +11:00
Jacob Evans
4bfb1fcc71 add a test constant for ZRX decimals 2017-11-22 10:54:09 +11:00
Jacob Evans
15628a1206 Add a test for when the ratio is < 1 2017-11-22 10:43:38 +11:00
Jacob Evans
a1411e3d52 Remove only 2017-11-22 08:05:47 +11:00
Leonid Logvinov
66750f7349 Fix tests 2017-11-21 14:03:32 -06:00
Fabio Berger
f7f1397e52 Merge branch 'development' into addWebsite
* development:
  Fix a typo in  postpublish utils tags -> tag
  Publish
  Revert "Publish"
  Publish
  Add instanceOf assertion
  Rename toDecimal to hexToDecimal
  Add PR numbers
  Add postFormatter for logs
2017-11-21 14:03:26 -06:00
Fabio Berger
3660ba28d7 Add website to mono repo, update packages to align with existing sub-packages, use new subscribeAsync 0x.js method 2017-11-21 14:03:08 -06:00
Leonid Logvinov
e3cc283478 Fix a typo in postpublish utils tags -> tag 2017-11-21 13:43:39 -06:00
Leonid Logvinov
9a2735d035 Publish
- 0x.js@0.26.0
 - @0xproject/assert@0.0.5
 - @0xproject/connect@0.0.1
 - @0xproject/json-schemas@0.6.8
 - @0xproject/tslint-config@0.1.1
2017-11-21 13:34:33 -06:00
Leonid Logvinov
06cd2f1eb3 Revert "Publish"
This reverts commit 41315827c1.
2017-11-21 13:31:47 -06:00
Leonid Logvinov
41315827c1 Publish
- 0x.js@0.26.0
 - @0xproject/assert@0.0.5
 - @0xproject/connect@0.0.1
 - @0xproject/json-schemas@0.6.8
 - @0xproject/tslint-config@0.1.1
2017-11-21 13:27:42 -06:00
Leonid
415fd101d3 Merge pull request #231 from 0xProject/fix/logsPostFormatting
Add postFormatter for logs
2017-11-21 13:24:47 -06:00
Leonid Logvinov
0747e162fa Add instanceOf assertion 2017-11-21 13:18:29 -06:00
Leonid Logvinov
8d6ba6ee7a Rename toDecimal to hexToDecimal 2017-11-21 13:16:55 -06:00
Leonid Logvinov
173a707a2e Add PR numbers 2017-11-21 13:15:05 -06:00
Leonid Logvinov
c8c95b4bd2 Add postFormatter for logs 2017-11-21 13:09:23 -06:00
Leonid Logvinov
351b7557b6 Fix tests 2017-11-21 12:21:49 -06:00
Leonid Logvinov
4dc1962f9e Fix a typo 2017-11-21 11:59:34 -06:00
Jacob Evans
335b9629b8 calculatedFillableAmountPlusFees 2017-11-21 15:00:09 +11:00
Jacob Evans
d16f0508bd totalZRXTransferAmount -> totalZRXTransferAmountRequired 2017-11-21 14:57:08 +11:00
Jacob Evans
da03331015 Unit test edge case for ZRX and ZRX partial fill 2017-11-21 14:51:19 +11:00
Jacob Evans
43128234bb setting a failed test 2017-11-21 14:00:21 +11:00
Jacob Evans
bbcee8dfa7 Move to base units 2017-11-21 13:04:36 +11:00
Jacob Evans
5b8f84f59a Added unit test for calculator 2017-11-21 12:58:17 +11:00
Leonid Logvinov
cfcbf34305 Fix test:circleci command 2017-11-20 17:46:53 -06:00
Jacob Evans
4bd5789203 Refactor into a calculator class 2017-11-21 10:30:29 +11:00
Leonid Logvinov
c4669013ab Check if transactionReceipt exists before normalizing it 2017-11-20 17:24:30 -06:00
Leonid Logvinov
3ad6020e19 Address nits 2017-11-20 16:55:53 -06:00
Leonid Logvinov
3fc8645d92 Remove old comment 2017-11-20 16:52:53 -06:00
Jacob Evans
fb812d59b0 Fixes before refactor 2017-11-21 09:50:37 +11:00
Leonid Logvinov
3e0371685f Fix async callbacks 2017-11-20 16:39:34 -06:00
Leonid Logvinov
3bc3666215 Check if callback exists 2017-11-20 16:25:51 -06:00
Leonid Logvinov
b01a4af99e Rename 2017-11-20 16:17:23 -06:00
Leonid Logvinov
9745d5348c Pass callback down 2017-11-20 16:14:40 -06:00
Leonid Logvinov
c858ff61f7 Add an order state cache to filter out duplicate events 2017-11-20 16:07:16 -06:00
Leonid
d39c0bee39 Merge branch 'development' into feature/orderExpired 2017-11-20 14:46:53 -06:00
Leonid Logvinov
5788b90c52 Remove custom heap and use bintrees 2017-11-20 14:40:53 -06:00
Fabio Berger
037f466e1f Merge pull request #225 from dekz/feature/track-zrx-movements
Track ZRX Approval and Balance events
2017-11-20 13:54:07 -06:00
Leonid Logvinov
71475d3cea Add expirationMarginMs 2017-11-20 13:47:09 -06:00
Leonid Logvinov
a613c3b7e7 Add defaults 2017-11-20 13:02:24 -06:00
Leonid Logvinov
35668fe225 Fix typos 2017-11-20 12:54:22 -06:00
Leonid Logvinov
83a2abeee4 Rename orderLifetime to orderLifetimeS 2017-11-20 12:53:49 -06:00
Leonid Logvinov
49d926013c Reference types directly 2017-11-20 12:53:16 -06:00
Leonid Logvinov
c068ec5231 Add ifExists suffix 2017-11-20 12:49:55 -06:00
Leonid Logvinov
86d19657b1 Improve the comment 2017-11-20 11:17:53 -06:00
Leonid Logvinov
67ad07020d Remove comment 2017-11-20 11:16:40 -06:00
Leonid Logvinov
fa2c4160b5 Remove new line 2017-11-20 11:15:48 -06:00
Leonid Logvinov
a37f019806 Delete orderExpirationCheckingIntervalIdIfExists 2017-11-20 11:15:01 -06:00
Leonid Logvinov
20449a0cb2 Throw when subscription is already removed 2017-11-20 11:13:54 -06:00
Leonid Logvinov
856a5c3369 Throw when subscription is already present 2017-11-20 11:10:25 -06:00
Leonid Logvinov
2c193a1244 Remove redundant bind 2017-11-20 11:06:32 -06:00
Leonid Logvinov
c4d10a6f2d Do simple inits inline 2017-11-20 11:05:37 -06:00
Jacob Evans
d6589004c7 fix bug when fees and partial asymmetric 2017-11-20 11:10:50 +11:00
Jacob Evans
519f1318c6 remove import 2017-11-20 11:02:16 +11:00
Jacob Evans
7460a36ce2 calculate remaining maker token amount 2017-11-20 10:55:28 +11:00
Jacob Evans
c8f6e3f923 Remove only 2017-11-20 10:45:40 +11:00
Jacob Evans
7b373e29ea Split into Pooled and non-pooled 2017-11-20 10:45:01 +11:00
Jacob Evans
94ce7a54c3 Incorrect amount when is zero or non-zrx fee 2017-11-20 09:20:37 +11:00
Jacob Evans
3bb6d8871b Readability variable names 2017-11-20 09:04:26 +11:00
Fabio Berger
98394c6e37 Merge pull request #228 from 0xProject/feature/publishLifecycleScripts
Add postpublish scripts for sub-packages
2017-11-17 19:30:51 -05:00
Leonid Logvinov
e755ed927c Remove order on expiration 2017-11-17 17:25:58 -06:00
Fabio Berger
37a9b64503 Small fixes 2017-11-17 17:00:15 -06:00
Fabio Berger
0de00da753 Merge branch 'development' into feature/publishLifecycleScripts
* development:
  Remove clean step from test_umd.sh
  Update CHANGELOG.md
  vx.x.x
  Add CHANGELOG files to each sub-package
  Fix 0x.js CHANGELOG
  separate assignment and call
  Remove Async subscribe callbacks from OrderWatcher
  Update changelog
  Callback for subscribe no longer supports an Async Callback
2017-11-17 16:54:57 -06:00
Fabio Berger
a4ae3c1e14 Updated yarn.lock 2017-11-17 16:50:14 -06:00
Fabio Berger
7f595169c1 Put release name generation into postpublish_utils 2017-11-17 16:44:56 -06:00
Fabio Berger
abee7d25a4 Add back promisify 2017-11-17 16:43:15 -06:00
Fabio Berger
49ba456189 Set S3 bucket path to variable 2017-11-17 14:49:46 -06:00
Fabio Berger
6a83687f45 reset all sub-package versions to latest actually published 2017-11-17 14:44:44 -06:00
Fabio Berger
70f4453e3e Get package name from package.json 2017-11-17 14:33:43 -06:00
Fabio Berger
cd0f6716e8 remove unused imports 2017-11-17 14:33:28 -06:00
Brandon Millman
5042b85d21 Remove clean step from test_umd.sh 2017-11-17 12:32:58 -08:00
Fabio Berger
5015f2d7d7 Add postpublish scripts for all the subpackages so that they each publish a release to github 2017-11-17 14:10:18 -06:00
Fabio Berger
5277d4a266 Move most of code for getting latest tag/version and calling publish_release to postpublish_utils script in top-level dir 2017-11-17 14:09:48 -06:00
Fabio Berger
f25b2d9ab9 Set prerelease to true so that non of the releases are marked as "latest" 2017-11-17 13:19:33 -06:00
Fabio Berger
0402d3de80 Move upload_docs_json back to npm script and pass in vars properly. 2017-11-17 13:19:12 -06:00
Leonid Logvinov
d3e03744cd Improve the comment 2017-11-17 13:06:10 -06:00
Leonid Logvinov
34926eb66a Add tests for expirationWatcher 2017-11-17 13:02:37 -06:00
Leonid Logvinov
b7585318c7 Fix heap implementation 2017-11-17 13:02:17 -06:00
Fabio Berger
e70c3976db Use yarn docs:json command 2017-11-17 13:30:26 -05:00
Fabio Berger
2c055db0d7 update yarn.lock 2017-11-17 13:24:49 -05:00
Fabio Berger
50dc1d3db3 specify the current working directory in which to run the yarn command 2017-11-17 13:24:36 -05:00
Fabio Berger
2e368b50eb print out file name in console 2017-11-17 13:24:15 -05:00
Fabio Berger
7b61ad639b small fixes 2017-11-17 12:23:27 -05:00
Fabio Berger
741774c4a7 Update CHANGELOG.md 2017-11-17 12:13:40 -05:00
Jacob Evans
33c1259fa2 Merge branch 'development' into feature/track-zrx-movements 2017-11-15 19:31:45 -05:00
Jacob Evans
9ee04fb14c Merge branch 'development' into feature/track-zrx-movements 2017-11-15 19:31:08 -05:00
Jacob Evans
e9a5ae21e0 Fix nits 2017-11-15 19:30:18 -05:00
Jacob Evans
0bcf7e56c2 Change to Async suffix convention 2017-11-15 19:10:44 -05:00
Fabio Berger
141f185c72 Merge pull request #222 from dekz/syncSubscribe
Remove support for Async callback types when used in Subscribe functions
2017-11-15 18:57:17 -05:00
Jacob Evans
e1b2c64654 Merge branch 'development' into syncSubscribe 2017-11-15 18:25:41 -05:00
Jacob Evans
d7e5c6f9b5 Merge branch 'development' into syncSubscribe 2017-11-15 18:25:09 -05:00
Brandon Millman
1e5cc3b0e5 experiment with calling typedoc programatically 2017-11-15 18:17:41 -05:00
Jacob Evans
85c3b2996d vx.x.x 2017-11-15 16:48:30 -05:00
Fabio Berger
9a57f71ee6 improve script 2017-11-15 16:47:35 -05:00
Jacob Evans
cf7727debc refactor up 2017-11-15 16:37:02 -05:00
Jacob Evans
9133e764a5 Use 18 decimal place units 2017-11-15 16:22:35 -05:00
Jacob Evans
c32938fa43 Shortcut if everything satisfies in the non dependent use case 2017-11-15 16:20:39 -05:00
Fabio Berger
827c245777 postpublish script fixes 2017-11-15 16:19:33 -05:00
Leonid Logvinov
88d020f9f2 Add initial implementation of expiration watcher 2017-11-15 14:54:56 -06:00
Jacob Evans
54c891a447 Fix test 2017-11-15 15:52:23 -05:00
Brandon Millman
6096fe75d3 WIP 2017-11-15 15:46:58 -05:00
Jacob Evans
a2e1d28efc Remove comments 2017-11-15 15:26:22 -05:00
Brandon Millman
a9fbe921a0 WIP 2017-11-15 15:14:20 -05:00
Jacob Evans
ee8042b458 Add return type 2017-11-15 14:40:43 -05:00
Jacob Evans
1e1b14edc5 test wording 2017-11-15 12:12:01 -05:00
Jacob Evans
4c505b6470 Add a pending changelog 2017-11-15 12:09:27 -05:00
Jacob Evans
471abfa760 Add and Remove Fee Token with Maker Token 2017-11-15 12:08:12 -05:00
Jacob Evans
590552d3e0 Initial tests 2017-11-15 11:12:40 -05:00
Fabio Berger
557faba31b Add CHANGELOG files to each sub-package 2017-11-15 10:11:04 -05:00
Fabio Berger
2411749594 Fix 0x.js CHANGELOG 2017-11-15 10:10:45 -05:00
Fabio Berger
4e39a957c7 Merge branch 'development' of github.com:0xProject/0x.js into development
* 'development' of github.com:0xProject/0x.js:
  Add lodash noop to emptyOrderbookChannelHandler
  Fix lint error
  Add connect to monorepo
2017-11-14 22:50:10 -05:00
Fabio Berger
0cf719a744 Add title and install instructions to all sub-package READMEs 2017-11-14 22:46:10 -05:00
Brandon Millman
fe7ad22cc1 Merge pull request #224 from 0xProject/feature/addConnect
Add connect to monorepo
2017-11-14 22:43:29 -05:00
Fabio Berger
59f82c5bfb Add rocket.chat badge and remove 0x.js npm badge 2017-11-14 22:41:42 -05:00
Brandon Millman
a2b8933129 Add lodash noop to emptyOrderbookChannelHandler 2017-11-14 22:37:20 -05:00
Fabio Berger
031b07264a Merge branch 'development' of github.com:0xProject/0x.js into development
* 'development' of github.com:0xProject/0x.js:
  Change the way 0x.js assert extends the @0xproject/assert module
2017-11-14 22:31:42 -05:00
Fabio Berger
87f8e93e12 Add core packes to README 2017-11-14 22:31:37 -05:00
Brandon Millman
5b5c31861a Change the way 0x.js assert extends the @0xproject/assert module 2017-11-14 22:23:41 -05:00
Brandon Millman
c315ca6c0c Fix lint error 2017-11-14 22:10:43 -05:00
Brandon Millman
655b0636fa Add connect to monorepo 2017-11-14 21:55:29 -05:00
Fabio Berger
5bd8e172c9 Merge pull request #223 from dekz/bug/fix-readme-links
Fix README links
2017-11-14 21:42:15 -05:00
Jacob Evans
ebb35fd65e Doubled up 2017-11-14 21:41:36 -05:00
Jacob Evans
df7195bda4 Change Slack to Rocket 2017-11-14 21:40:20 -05:00
Jacob Evans
4bd950bb6f Fix README links 2017-11-14 21:31:41 -05:00
Jacob Evans
3f39b22a68 separate assignment and call 2017-11-14 21:20:31 -05:00
Brandon Millman
c019280e85 Merge pull request #219 from 0xProject/feature/rounding-validation
Rounding validation
2017-11-14 18:15:54 -05:00
Fabio Berger
ff0b0ae1ab re-add commonjs build 2017-11-14 18:04:29 -05:00
Fabio Berger
823015435d Publish
- 0x.js@0.25.1
2017-11-14 16:27:34 -05:00
Fabio Berger
99854d7ecf Publish
- 0x.js@0.25.0
2017-11-14 15:59:13 -05:00
Fabio Berger
bb7d9656a5 Publish
- 0x.js@0.24.0
2017-11-14 15:56:14 -05:00
Fabio Berger
e41994a064 revert 0x.js version and change name so matches existing npm package name 2017-11-14 15:51:59 -05:00
Jacob Evans
752603284d Remove Async subscribe callbacks from OrderWatcher 2017-11-14 11:21:00 -05:00
Leonid Logvinov
dcfe8bae1c Name a constant 2017-11-14 11:11:09 -05:00
Jacob Evans
8f4be963b2 Update changelog 2017-11-14 11:09:37 -05:00
Leonid Logvinov
61496d77a5 Fix namings 2017-11-14 11:03:01 -05:00
Jacob Evans
a12069f03f Callback for subscribe no longer supports an Async Callback 2017-11-14 10:56:57 -05:00
Leonid Logvinov
24493a4556 Fix tests 2017-11-13 20:32:39 -05:00
Leonid Logvinov
02bbcf6b0e Add a test for rounding error 2017-11-13 18:57:38 -05:00
Leonid Logvinov
33f479c271 Add assertions for fillableTakerAmount 2017-11-13 18:10:00 -05:00
Leonid Logvinov
f936363440 Add validation for rounding error 2017-11-13 18:09:18 -05:00
Leonid Logvinov
315e4015de Return remainingFillableTakerAmount 2017-11-13 17:59:18 -05:00
Leonid Logvinov
0c91b66f45 Add remainingFillableMakerAmount to types 2017-11-13 17:58:41 -05:00
581 changed files with 48459 additions and 2823 deletions

View File

@@ -19,7 +19,7 @@ jobs:
- 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 bootstrap
- run: yarn lerna:run build
- run:
name: testrpc
command: npm run testrpc -- --db testrpc_snapshot

6
.gitignore vendored
View File

@@ -63,4 +63,8 @@ lib/
_bundles
# generated documentation
docs/
generated_docs/
TODO.md
packages/website/public/bundle*

View File

@@ -6,33 +6,23 @@
This repository contains all the 0x developer tools written in TypeScript. Our hope is that these tools make it easy to build Relayers and other DApps that use the 0x protocol.
[website-url]: https://0xproject.com/
[whitepaper-url]: https://0xproject.com/pdfs/0x_white_paper.pdf
[![CircleCI](https://circleci.com/gh/0xProject/0x.js.svg?style=svg&circle-token=61bf7cd8c9b4e11b132089dfcffdd1be277d1e0c)](https://circleci.com/gh/0xProject/0x.js)
[![npm version](https://badge.fury.io/js/0x.js.svg)](https://badge.fury.io/js/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)
[![Slack Status](http://slack.0xProject.com/badge.svg)](http://slack.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/)
Instructions
------------
### Core Packages
Make sure you have `yarn@1.x` installed locally.
### Creating a new sub-package
1. Make sure the `name` field in the sub-package's `package.json` starts with `@0xproject/` and has a unique name (e.g `@0xproject/assert`).
2. Run `yarn install` to install all it's dependencies.
### How to add a sub-package as a dependency to another sub-package:
1. Add the sub-packages name (declared in it's `package.json`) to your sub-packages `package.json` under `dependencies` or `devDependencies`.
2. Run `yarn install` from anywhere in the mono repo.
3. Import the sub-package as:
```
import {myPkg} from '@0xproject/myPkg';
```
| 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 |

View File

@@ -6,12 +6,17 @@
],
"scripts": {
"testrpc": "testrpc -p 8545 --networkId 50 -m \"${npm_package_config_mnemonic}\"",
"lerna:run": "lerna run"
"lerna:run": "lerna run",
"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"
},
"devDependencies": {
"lerna": "^2.5.1"
"lerna": "^2.5.1",
"async-child-process": "^1.1.1",
"semver-sort": "^0.0.4",
"publish-release": "0xproject/publish-release",
"ethereumjs-testrpc": "6.0.3"
}
}

View File

@@ -1,14 +1,37 @@
# CHANGELOG
v0.24.0 - _November 13, 2017_
v0.27.1 - _November 28, 2017_
------------------------
* Standardise on Cancelled over Canceled
* Add missing `DecodedLogEvent` type to exported types
* Export `TransactionOpts` type
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)
* Remove `ZeroExError.ContractNotFound` and replace it with contract-specific errors (#233)
* Make `DecodedLogEvent<A>` contain `LogWithDecodedArgs<A>` under log key instead of merging it in like web3 does (#234)
* Rename `removed` to `isRemoved` in `DecodedLogEvent<A>` (#234)
* Add config allowing to specify gasPrice and gasLimit for every transaction sending method (#235)
* 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_
------------------------
* 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_
------------------------
* 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_
------------------------
* Fixed unhandled promise rejection error in subscribe methods (#209)
* Subscribe callbacks now receive an error object as their first argument
* 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_
------------------------

View File

@@ -1,3 +1,6 @@
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.

View File

@@ -1,6 +1,6 @@
{
"name": "@0xproject/0x.js",
"version": "0.24.0",
"name": "0x.js",
"version": "0.27.2",
"description": "A javascript library for interacting with the 0x protocol",
"keywords": [
"0x.js",
@@ -14,20 +14,16 @@
"scripts": {
"prebuild": "npm run clean",
"build": "run-p build:umd:prod build:commonjs; exit 0;",
"prepublishOnly": "run-p build",
"postpublish": "run-s release docs:json upload_docs_json",
"release": "publish-release --assets _bundles/index.js,_bundles/index.min.js --tag $(git describe --tags) --owner 0xProject --repo 0x.js",
"upload_docs_json": "aws s3 cp docs/index.json s3://0xjs-docs-jsons/$(git describe --tags).json --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type aplication/json",
"lint": "tslint src/**/*.ts test/**/*.ts",
"test:circleci": "run-s test:coverage report_test_coverage; if [ $CIRCLE_BRANCH = \"development\" ]; then yarn test:umd; fi",
"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;",
"docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json docs/index.json .",
"docs:generate": "typedoc --out docs .",
"docs:open": "opn docs/index.html",
"clean": "shx rm -rf _bundles lib test_temp",
"build:umd:dev": "webpack",
"build:umd:prod": "NODE_ENV=production webpack",
@@ -49,26 +45,29 @@
"node": ">=6.0.0"
},
"devDependencies": {
"@0xproject/tslint-config": "^0.1.0",
"@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.64",
"@types/mocha": "^2.2.41",
"@types/node": "^8.0.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-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",
"ethereumjs-testrpc": "4.0.1",
"json-loader": "^0.5.4",
"mocha": "^4.0.0",
"npm-run-all": "^4.0.2",
"mocha": "^4.0.1",
"npm-run-all": "^4.1.2",
"nyc": "^11.0.1",
"opn-cli": "^3.1.0",
"request": "^2.81.0",
@@ -83,23 +82,24 @@
"types-ethereumjs-util": "0xProject/types-ethereumjs-util",
"typescript": "~2.6.1",
"web3-provider-engine": "^13.0.1",
"web3-typescript-typings": "^0.7.1",
"web3-typescript-typings": "^0.7.2",
"webpack": "^3.1.0"
},
"dependencies": {
"@0xproject/assert": "^0.0.4",
"@0xproject/json-schemas": "^0.6.7",
"@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",
"bn.js": "4.11.8",
"bintrees": "^1.0.2",
"bn.js": "^4.11.8",
"compare-versions": "^3.0.1",
"es6-promisify": "^5.0.0",
"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",
"publish-release": "^1.3.3",
"uuid": "^3.1.0",
"web3": "^0.20.0"
}

View File

@@ -0,0 +1,44 @@
const execAsync = require('async-child-process').execAsync;
const postpublish_utils = require('../../../scripts/postpublish_utils');
const packageJSON = require('../package.json');
const cwd = __dirname + '/..';
const subPackageName = packageJSON.name;
const S3BucketPath = 's3://0xjs-docs-jsons/';
let tag;
let version;
postpublish_utils.getLatestTagAndVersionAsync(subPackageName)
.then(function(result) {
tag = result.tag;
version = result.version;
const releaseName = postpublish_utils.getReleaseName(subPackageName, version);
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,
}
);
})
.then(function(result) {
if (result.stderr !== '') {
throw new Error(result.stderr);
}
const fileName = 'v' + version + '.json';
console.log('POSTPUBLISH: Doc generation successful, uploading docs... as ', fileName);
const s3Url = S3BucketPath + fileName;
return execAsync('S3_URL=' + s3Url + ' yarn upload_docs_json', {
cwd,
});
}).catch (function(err) {
throw err;
});

View File

@@ -3,5 +3,4 @@
# 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=$?
npm run clean
exit $return_code

View File

@@ -1,34 +1,35 @@
import * as _ from 'lodash';
import {schemas, SchemaValidator} from '@0xproject/json-schemas';
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import BigNumber from 'bignumber.js';
import {SchemaValidator, schemas} from '@0xproject/json-schemas';
import {bigNumberConfigs} from './bignumber_config';
import * as ethUtil from 'ethereumjs-util';
import {Web3Wrapper} from './web3_wrapper';
import {constants} from './utils/constants';
import {utils} from './utils/utils';
import {signatureUtils} from './utils/signature_utils';
import {assert} from './utils/assert';
import {AbiDecoder} from './utils/abi_decoder';
import {intervalUtils} from './utils/interval_utils';
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 {EtherTokenWrapper} from './contract_wrappers/ether_token_wrapper';
import {TokenWrapper} from './contract_wrappers/token_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 {OrderStateUtils} from './utils/order_state_utils';
import {zeroExConfigSchema} from './schemas/zero_ex_config_schema';
import {
ECSignature,
ZeroExError,
Order,
OrderStateWatcherConfig,
SignedOrder,
TransactionReceiptWithDecodedLogs,
Web3Provider,
ZeroExConfig,
OrderStateWatcherConfig,
TransactionReceiptWithDecodedLogs,
ZeroExError,
} from './types';
import {zeroExConfigSchema} from './schemas/zero_ex_config_schema';
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();
@@ -169,56 +170,55 @@ export class ZeroEx {
* @param config The configuration object. Look up the type for the description.
* @return An instance of the 0x.js ZeroEx class.
*/
constructor(provider: Web3Provider, config?: ZeroExConfig) {
constructor(provider: Web3Provider, config: ZeroExConfig) {
assert.isWeb3Provider('provider', provider);
if (!_.isUndefined(config)) {
assert.doesConformToSchema('config', config, zeroExConfigSchema);
}
assert.doesConformToSchema('config', config, zeroExConfigSchema);
const artifactJSONs = _.values(artifacts);
const abiArrays = _.map(artifactJSONs, artifact => artifact.abi);
this._abiDecoder = new AbiDecoder(abiArrays);
const gasPrice = _.isUndefined(config) ? undefined : config.gasPrice;
const defaults = {
gasPrice,
gasPrice: config.gasPrice,
};
this._web3Wrapper = new Web3Wrapper(provider, defaults);
this.token = new TokenWrapper(
this._web3Wrapper,
this._abiDecoder,
this._getTokenTransferProxyAddressAsync.bind(this),
);
const exchageContractAddressIfExists = _.isUndefined(config) ? undefined : config.exchangeContractAddress;
this.exchange = new ExchangeWrapper(
this._web3Wrapper,
this._abiDecoder,
this.token,
exchageContractAddressIfExists,
);
this.proxy = new TokenTransferProxyWrapper(
this._web3Wrapper,
this._getTokenTransferProxyAddressAsync.bind(this),
config.networkId,
config.tokenTransferProxyContractAddress,
);
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,
);
this.tokenRegistry = new TokenRegistryWrapper(
this._web3Wrapper, config.networkId, config.tokenRegistryContractAddress,
);
this.etherToken = new EtherTokenWrapper(
this._web3Wrapper, config.networkId, this.token, config.etherTokenContractAddress,
);
const tokenRegistryContractAddressIfExists = _.isUndefined(config) ?
undefined :
config.tokenRegistryContractAddress;
this.tokenRegistry = new TokenRegistryWrapper(this._web3Wrapper, tokenRegistryContractAddressIfExists);
const etherTokenContractAddressIfExists = _.isUndefined(config) ? undefined : config.etherTokenContractAddress;
this.etherToken = new EtherTokenWrapper(this._web3Wrapper, this.token, etherTokenContractAddressIfExists);
const orderWatcherConfig = _.isUndefined(config) ? undefined : config.orderWatcherConfig;
this.orderStateWatcher = new OrderStateWatcher(
this._web3Wrapper, this._abiDecoder, this.token, this.exchange, orderWatcherConfig,
this._web3Wrapper, this._abiDecoder, this.token, this.exchange, config.orderWatcherConfig,
);
}
/**
* Sets a new web3 provider for 0x.js. Updating the provider will stop all
* subscriptions so you will need to re-subscribe to all events relevant to your app after this call.
* @param provider The Web3Provider you would like the 0x.js library to use from now on.
* @param networkId The id of the network your provider is connected to
*/
public async setProviderAsync(provider: Web3Provider) {
this._web3Wrapper.setProvider(provider);
await (this.exchange as any)._invalidateContractInstancesAsync();
public setProvider(provider: Web3Provider, networkId: number): void {
this._web3Wrapper.setProvider(provider, networkId);
(this.exchange as any)._invalidateContractInstances();
(this.tokenRegistry as any)._invalidateContractInstance();
await (this.token as any)._invalidateContractInstancesAsync();
(this.token as any)._invalidateContractInstances();
(this.proxy as any)._invalidateContractInstance();
(this.etherToken as any)._invalidateContractInstance();
}

View File

@@ -1,11 +1,13 @@
import {Artifact} from './types';
import * as TokenArtifact from './artifacts/Token.json';
import * as ExchangeArtifact from './artifacts/Exchange.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';
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,

View File

@@ -233,213 +233,18 @@
"type": "event"
}
],
"unlinked_binary": "0x6060604052341561000c57fe5b5b6107598061001c6000396000f300606060405236156100935763ffffffff60e060020a60003504166306fdde0381146100a4578063095ea7b31461013457806318160ddd1461016757806323b872dd146101895780632e1a7d4d146101c2578063313ce567146101d757806370a08231146101fd57806395d89b411461022b578063a9059cbb146102bb578063d0e30db0146102ee578063dd62ed3e146102f8575b6100a25b61009f61032c565b5b565b005b34156100ac57fe5b6100b461037b565b6040805160208082528351818301528351919283929083019185019080838382156100fa575b8051825260208311156100fa57601f1990920191602091820191016100da565b505050905090810190601f1680156101265780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561013c57fe5b610153600160a060020a03600435166024356103a3565b604080519115158252519081900360200190f35b341561016f57fe5b61017761040e565b60408051918252519081900360200190f35b341561019157fe5b610153600160a060020a0360043581169060243516604435610414565b604080519115158252519081900360200190f35b34156101ca57fe5b6100a2600435610537565b005b34156101df57fe5b6101e76105b8565b6040805160ff9092168252519081900360200190f35b341561020557fe5b610177600160a060020a03600435166105bd565b60408051918252519081900360200190f35b341561023357fe5b6100b46105dc565b6040805160208082528351818301528351919283929083019185019080838382156100fa575b8051825260208311156100fa57601f1990920191602091820191016100da565b505050905090810190601f1680156101265780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156102c357fe5b610153600160a060020a03600435166024356105fd565b604080519115158252519081900360200190f35b6100a261032c565b005b341561030057fe5b610177600160a060020a03600435811690602435166106af565b60408051918252519081900360200190f35b600160a060020a03331660009081526020819052604090205461034f90346106dc565b600160a060020a03331660009081526020819052604090205560025461037590346106dc565b6002555b565b60408051808201909152600b815260a960020a6a22ba3432b9102a37b5b2b702602082015281565b600160a060020a03338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60025481565b600160a060020a03808416600081815260016020908152604080832033909516835293815283822054928252819052918220548390108015906104575750828110155b801561047d5750600160a060020a03841660009081526020819052604090205483810110155b1561052957600160a060020a03808516600090815260208190526040808220805487019055918716815220805484900390556000198110156104e757600160a060020a03808616600090815260016020908152604080832033909416835292905220805484900390555b83600160a060020a031685600160a060020a031660008051602061070e833981519152856040518082815260200191505060405180910390a36001915061052e565b600091505b5b509392505050565b600160a060020a03331660009081526020819052604090205461055a90826106f6565b600160a060020a03331660009081526020819052604090205560025461058090826106f6565b600255604051600160a060020a0333169082156108fc029083906000818181858888f1935050505015156105b45760006000fd5b5b50565b601281565b600160a060020a0381166000908152602081905260409020545b919050565b604080518082019091526004815260e360020a630ae8aa8902602082015281565b600160a060020a0333166000908152602081905260408120548290108015906106405750600160a060020a03831660009081526020819052604090205482810110155b156106a057600160a060020a03338116600081815260208181526040808320805488900390559387168083529184902080548701905583518681529351919360008051602061070e833981519152929081900390910190a3506001610408565b506000610408565b5b92915050565b600160a060020a038083166000908152600160209081526040808320938516835292905220545b92915050565b6000828201838110156106eb57fe5b8091505b5092915050565b60008282111561070257fe5b508082035b929150505600ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a72305820ec42c469bb8ddd5de28c55b9cc393c812397c063a57fb88926e3f6de246318b70029",
"networks": {
"1": {
"links": {},
"events": {
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef": {
"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"
},
"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925": {
"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"
}
},
"updated_at": 1502488087000,
"address": "0x2956356cd2a2bf3202f771f50d3d14a367b48070"
},
"3": {
"links": {},
"events": {
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef": {
"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"
},
"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925": {
"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"
}
},
"updated_at": 1506602007000,
"address": "0xc00fd9820cd2898cc4c054b7bf142de637ad129a"
},
"42": {
"links": {},
"events": {
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef": {
"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"
},
"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925": {
"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"
}
},
"updated_at": 1502391794392,
"address": "0x05d090b51c40b020eab3bfcb6a2dff130df22e9c"
},
"50": {
"links": {},
"events": {
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef": {
"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"
},
"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925": {
"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"
}
},
"updated_at": 1503318938233,
"address": "0x48bacb9266a570d521063ef5dd96e61686dbe788"
}
},
"schema_version": "0.0.5",
"updated_at": 1503318938233
}
}

File diff suppressed because one or more lines are too long

View File

@@ -168,9 +168,5 @@
"name": "Approval",
"type": "event"
}
],
"unlinked_binary": "0x6060604052341561000c57fe5b5b6101e08061001c6000396000f3006060604052361561005c5763ffffffff60e060020a600035041663095ea7b3811461005e57806318160ddd1461009157806323b872dd146100b357806370a08231146100ec578063a9059cbb1461005e578063dd62ed3e1461014d575bfe5b341561006657fe5b61007d600160a060020a0360043516602435610181565b604080519115158252519081900360200190f35b341561009957fe5b6100a161018a565b60408051918252519081900360200190f35b34156100bb57fe5b61007d600160a060020a0360043581169060243516604435610190565b604080519115158252519081900360200190f35b34156100f457fe5b6100a1600160a060020a036004351661019a565b60408051918252519081900360200190f35b341561006657fe5b61007d600160a060020a0360043516602435610181565b604080519115158252519081900360200190f35b341561015557fe5b6100a1600160a060020a0360043581169060243516610181565b60408051918252519081900360200190f35b60005b92915050565b60005b90565b60005b9392505050565b60005b919050565b60005b92915050565b60005b929150505600a165627a7a723058202e3f7ac17048343c0d0ea24fccb64620577374eeeed61539e543df4025d7d0db0029",
"networks": {},
"schema_version": "0.0.5",
"updated_at": 1503317882695
}
]
}

File diff suppressed because one or more lines are too long

View File

@@ -167,8 +167,18 @@
"type": "event"
}
],
"unlinked_binary": "0x60606040525b60008054600160a060020a03191633600160a060020a03161790555b5b6106e6806100316000396000f300606060405236156100725763ffffffff60e060020a60003504166315dacbea811461007457806342f1181e146100b3578063494503d4146100d157806370712939146101005780638da5cb5b1461011e578063b91816111461014a578063d39de6e91461017a578063f2fde38b146101e5575bfe5b341561007c57fe5b61009f600160a060020a0360043581169060243581169060443516606435610203565b604080519115158252519081900360200190f35b34156100bb57fe5b6100cf600160a060020a03600435166102ae565b005b34156100d957fe5b6100e4600435610390565b60408051600160a060020a039092168252519081900360200190f35b341561010857fe5b6100cf600160a060020a03600435166103c2565b005b341561012657fe5b6100e461055a565b60408051600160a060020a039092168252519081900360200190f35b341561015257fe5b61009f600160a060020a0360043516610569565b604080519115158252519081900360200190f35b341561018257fe5b61018a61057e565b60408051602080825283518183015283519192839290830191858101910280838382156101d2575b8051825260208311156101d257601f1990920191602091820191016101b2565b5050509050019250505060405180910390f35b34156101ed57fe5b6100cf600160a060020a03600435166105e7565b005b600160a060020a03331660009081526001602052604081205460ff16151561022b5760006000fd5b6040805160006020918201819052825160e060020a6323b872dd028152600160a060020a0388811660048301528781166024830152604482018790529351938916936323b872dd9360648084019491938390030190829087803b151561028d57fe5b6102c65a03f1151561029b57fe5b5050604051519150505b5b949350505050565b60005433600160a060020a039081169116146102ca5760006000fd5b600160a060020a038116600090815260016020526040902054819060ff16156102f35760006000fd5b600160a060020a0382166000908152600160208190526040909120805460ff191682179055600280549091810161032a8382610633565b916000526020600020900160005b81546101009190910a600160a060020a0381810219909216868316918202179092556040513390911692507f94bb87f4c15c4587ff559a7584006fa01ddf9299359be6b512b94527aa961aca90600090a35b5b505b50565b600280548290811061039e57fe5b906000526020600020900160005b915054906101000a9004600160a060020a031681565b6000805433600160a060020a039081169116146103df5760006000fd5b600160a060020a038216600090815260016020526040902054829060ff1615156104095760006000fd5b600160a060020a0383166000908152600160205260408120805460ff1916905591505b6002548210156105195782600160a060020a031660028381548110151561044f57fe5b906000526020600020900160005b9054906101000a9004600160a060020a0316600160a060020a0316141561050d5760028054600019810190811061049057fe5b906000526020600020900160005b9054906101000a9004600160a060020a03166002838154811015156104bf57fe5b906000526020600020900160005b6101000a815481600160a060020a030219169083600160a060020a0316021790555060016002818180549050039150816105079190610633565b50610519565b5b60019091019061042c565b604051600160a060020a0333811691908516907ff5b347a1e40749dd050f5f07fbdbeb7e3efa9756903044dd29401fd1d4bb4a1c90600090a35b5b505b5050565b600054600160a060020a031681565b60016020526000908152604090205460ff1681565b610586610687565b60028054806020026020016040519081016040528092919081815260200182805480156105dc57602002820191906000526020600020905b8154600160a060020a031681526001909101906020018083116105be575b505050505090505b90565b60005433600160a060020a039081169116146106035760006000fd5b600160a060020a0381161561038d5760008054600160a060020a031916600160a060020a0383161790555b5b5b50565b81548183558181151161055357600083815260209020610553918101908301610699565b5b505050565b81548183558181151161055357600083815260209020610553918101908301610699565b5b505050565b60408051602081019091526000815290565b6105e491905b808211156106b3576000815560010161069f565b5090565b905600a165627a7a72305820d2924957bb88a128789172e164d874fe5445218fc2dde2f5eb265839a1f341a20029",
"networks": {},
"schema_version": "0.0.5",
"updated_at": 1503318938227
"networks": {
"1": {
"address": "0x8da0d80f5007ef1e431dd2127178d224e32c2ef4"
},
"3": {
"address": "0x4e9aad8184de8833365fea970cd9149372fdf1e6"
},
"42": {
"address": "0x087eed4bc1ee3de49befbd66c662b434b15d49d4"
},
"50": {
"address": "0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c"
}
}
}

View File

@@ -0,0 +1,17 @@
{
"contract_name": "ZRX",
"networks": {
"1": {
"address": "0xe41d2489571d322189246dafa5ebde1f4699f498"
},
"3": {
"address": "0xa8e9fa8f91e5ae138c74648c9c304f1c75003a8d"
},
"42": {
"address": "0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570"
},
"50": {
"address": "0x25b8fe1de9daf8ba351890744ff28cf7dfa8f5e3"
}
}
}

View File

@@ -1,27 +1,38 @@
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import {Block, BlockAndLogStreamer} from 'ethereumjs-blockstream';
import * as _ from 'lodash';
import * as Web3 from 'web3';
import {BlockAndLogStreamer, Block} from 'ethereumjs-blockstream';
import {Web3Wrapper} from '../web3_wrapper';
import {AbiDecoder} from '../utils/abi_decoder';
import {
ZeroExError,
InternalZeroExError,
Artifact,
LogWithDecodedArgs,
RawLog,
ContractEvents,
SubscriptionOpts,
IndexedFilterValues,
EventCallback,
BlockParamLiteral,
ContractEventArgs,
ContractEvents,
EventCallback,
IndexedFilterValues,
InternalZeroExError,
LogWithDecodedArgs,
RawLog,
SubscriptionOpts,
ZeroExError,
} from '../types';
import {AbiDecoder} from '../utils/abi_decoder';
import {constants} from '../utils/constants';
import {intervalUtils} from '../utils/interval_utils';
import {filterUtils} from '../utils/filter_utils';
import {intervalUtils} from '../utils/interval_utils';
const CONTRACT_NAME_TO_NOT_FOUND_ERROR: {[contractName: string]: ZeroExError} = {
ZRX: ZeroExError.ZRXContractDoesNotExist,
EtherToken: ZeroExError.EtherTokenContractDoesNotExist,
Token: ZeroExError.TokenContractDoesNotExist,
TokenRegistry: ZeroExError.TokenRegistryContractDoesNotExist,
TokenTransferProxy: ZeroExError.TokenTransferProxyContractDoesNotExist,
Exchange: ZeroExError.ExchangeContractDoesNotExist,
};
export class ContractWrapper {
protected _web3Wrapper: Web3Wrapper;
private _networkId: number;
private _abiDecoder?: AbiDecoder;
private _blockAndLogStreamer: BlockAndLogStreamer|undefined;
private _blockAndLogStreamInterval: NodeJS.Timer;
@@ -29,8 +40,9 @@ export class ContractWrapper {
private _filterCallbacks: {[filterToken: string]: EventCallback<ContractEventArgs>};
private _onLogAddedSubscriptionToken: string|undefined;
private _onLogRemovedSubscriptionToken: string|undefined;
constructor(web3Wrapper: Web3Wrapper, abiDecoder?: AbiDecoder) {
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder?: AbiDecoder) {
this._web3Wrapper = web3Wrapper;
this._networkId = networkId;
this._abiDecoder = abiDecoder;
this._filters = {};
this._filterCallbacks = {};
@@ -89,19 +101,45 @@ export class ContractWrapper {
const logWithDecodedArgs = this._abiDecoder.tryToDecodeLogOrNoop(log);
return logWithDecodedArgs;
}
protected async _instantiateContractIfExistsAsync<ContractType extends Web3.ContractInstance>(
artifact: Artifact, addressIfExists?: string): Promise<ContractType> {
const contractInstance =
await this._web3Wrapper.getContractInstanceFromArtifactAsync<ContractType>(artifact, addressIfExists);
protected async _instantiateContractIfExistsAsync(
artifact: Artifact, addressIfExists?: string,
): Promise<Web3.ContractInstance> {
let contractAddress: string;
if (_.isUndefined(addressIfExists)) {
if (_.isUndefined(artifact.networks[this._networkId])) {
throw new Error(ZeroExError.ContractNotDeployedOnNetwork);
}
contractAddress = artifact.networks[this._networkId].address.toLowerCase();
} else {
contractAddress = addressIfExists;
}
const doesContractExist = await this._web3Wrapper.doesContractExistAtAddressAsync(contractAddress);
if (!doesContractExist) {
throw new Error(CONTRACT_NAME_TO_NOT_FOUND_ERROR[artifact.contract_name]);
}
const contractInstance = this._web3Wrapper.getContractInstance(
artifact.abi, contractAddress,
);
return contractInstance;
}
private _onLogStateChanged<ArgsType extends ContractEventArgs>(removed: boolean, log: Web3.LogEntry): void {
protected _getContractAddress(artifact: Artifact, addressIfExists?: string): string {
if (_.isUndefined(addressIfExists)) {
const contractAddress = artifact.networks[this._networkId].address;
if (_.isUndefined(contractAddress)) {
throw new Error(ZeroExError.ExchangeContractDoesNotExist);
}
return contractAddress;
} else {
return addressIfExists;
}
}
private _onLogStateChanged<ArgsType extends ContractEventArgs>(isRemoved: boolean, log: Web3.LogEntry): void {
_.forEach(this._filters, (filter: Web3.FilterObject, filterToken: string) => {
if (filterUtils.matchesFilter(log, filter)) {
const decodedLog = this._tryToDecodeLogOrNoop(log) as LogWithDecodedArgs<ArgsType>;
const logEvent = {
...decodedLog,
removed,
log: decodedLog,
isRemoved,
};
this._filterCallbacks[filterToken](null, logEvent);
}
@@ -117,13 +155,13 @@ export class ContractWrapper {
this._blockAndLogStreamInterval = intervalUtils.setAsyncExcludingInterval(
this._reconcileBlockAsync.bind(this), constants.DEFAULT_BLOCK_POLLING_INTERVAL,
);
let removed = false;
let isRemoved = false;
this._onLogAddedSubscriptionToken = this._blockAndLogStreamer.subscribeToOnLogAdded(
this._onLogStateChanged.bind(this, removed),
this._onLogStateChanged.bind(this, isRemoved),
);
removed = true;
isRemoved = true;
this._onLogRemovedSubscriptionToken = this._blockAndLogStreamer.subscribeToOnLogRemoved(
this._onLogStateChanged.bind(this, removed),
this._onLogStateChanged.bind(this, isRemoved),
);
}
private _stopBlockAndLogStream(): void {
@@ -140,7 +178,7 @@ export class ContractWrapper {
// 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
this._blockAndLogStreamer.reconcileNewBlock(latestBlock as any as Block);
await this._blockAndLogStreamer.reconcileNewBlock(latestBlock as any as Block);
}
} catch (err) {
const filterTokens = _.keys(this._filterCallbacks);

View File

@@ -1,11 +1,14 @@
import * as _ from 'lodash';
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import BigNumber from 'bignumber.js';
import {Web3Wrapper} from '../web3_wrapper';
import {ContractWrapper} from './contract_wrapper';
import {TokenWrapper} from './token_wrapper';
import {EtherTokenContract, ZeroExError} from '../types';
import {assert} from '../utils/assert';
import * as _ from 'lodash';
import {artifacts} from '../artifacts';
import {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';
/**
* This class includes all the functionality related to interacting with a wrapped Ether ERC20 token contract.
@@ -15,8 +18,9 @@ export class EtherTokenWrapper extends ContractWrapper {
private _etherTokenContractIfExists?: EtherTokenContract;
private _tokenWrapper: TokenWrapper;
private _contractAddressIfExists?: string;
constructor(web3Wrapper: Web3Wrapper, tokenWrapper: TokenWrapper, contractAddressIfExists?: string) {
super(web3Wrapper);
constructor(web3Wrapper: Web3Wrapper, networkId: number, tokenWrapper: TokenWrapper,
contractAddressIfExists?: string) {
super(web3Wrapper, networkId);
this._tokenWrapper = tokenWrapper;
this._contractAddressIfExists = contractAddressIfExists;
}
@@ -25,10 +29,13 @@ export class EtherTokenWrapper extends ContractWrapper {
* 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 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): Promise<string> {
public async depositAsync(
amountInWei: BigNumber, depositor: string, txOpts: TransactionOpts = {},
): Promise<string> {
assert.isValidBaseUnitAmount('amountInWei', amountInWei);
await assert.isSenderAddressAsync('depositor', depositor, this._web3Wrapper);
@@ -39,6 +46,8 @@ export class EtherTokenWrapper extends ContractWrapper {
const txHash = await wethContract.deposit.sendTransactionAsync({
from: depositor,
value: amountInWei,
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
});
return txHash;
}
@@ -47,19 +56,24 @@ export class EtherTokenWrapper extends ContractWrapper {
* equivalent number of wrapped ETH tokens.
* @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): Promise<string> {
public async withdrawAsync(
amountInWei: BigNumber, withdrawer: string, txOpts: TransactionOpts = {},
): Promise<string> {
assert.isValidBaseUnitAmount('amountInWei', amountInWei);
await assert.isSenderAddressAsync('withdrawer', withdrawer, this._web3Wrapper);
const wethContractAddress = await this.getContractAddressAsync();
const wethContractAddress = this.getContractAddress();
const WETHBalanceInBaseUnits = await this._tokenWrapper.getBalanceAsync(wethContractAddress, withdrawer);
assert.assert(WETHBalanceInBaseUnits.gte(amountInWei), ZeroExError.InsufficientWEthBalanceForWithdrawal);
const wethContract = await this._getEtherTokenContractAsync();
const txHash = await wethContract.withdraw.sendTransactionAsync(amountInWei, {
from: withdrawer,
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
});
return txHash;
}
@@ -67,9 +81,11 @@ export class EtherTokenWrapper extends ContractWrapper {
* Retrieves the Wrapped Ether token contract address
* @return The Wrapped Ether token contract address
*/
public async getContractAddressAsync(): Promise<string> {
const wethContract = await this._getEtherTokenContractAsync();
return wethContract.address;
public getContractAddress(): string {
const contractAddress = this._getContractAddress(
artifacts.EtherTokenArtifact, this._contractAddressIfExists,
);
return contractAddress;
}
private _invalidateContractInstance(): void {
delete this._etherTokenContractIfExists;
@@ -78,10 +94,11 @@ export class EtherTokenWrapper extends ContractWrapper {
if (!_.isUndefined(this._etherTokenContractIfExists)) {
return this._etherTokenContractIfExists;
}
const contractInstance = await this._instantiateContractIfExistsAsync<EtherTokenContract>(
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
artifacts.EtherTokenArtifact, this._contractAddressIfExists,
);
this._etherTokenContractIfExists = contractInstance as EtherTokenContract;
const contractInstance = new EtherTokenContract(web3ContractInstance, this._web3Wrapper.getContractDefaults());
this._etherTokenContractIfExists = contractInstance;
return this._etherTokenContractIfExists;
}
}

View File

@@ -1,44 +1,46 @@
import {schemas} from '@0xproject/json-schemas';
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import BigNumber from 'bignumber.js';
import * as _ from 'lodash';
import * as Web3 from 'web3';
import BigNumber from 'bignumber.js';
import {schemas} from '@0xproject/json-schemas';
import {Web3Wrapper} from '../web3_wrapper';
import {artifacts} from '../artifacts';
import {
BlockParamLiteral,
DecodedLogArgs,
ECSignature,
ExchangeContract,
EventCallback,
ExchangeContractErrCodes,
ExchangeContractErrs,
ZeroExError,
OrderValues,
OrderAddresses,
Order,
SignedOrder,
ExchangeContractEventArgs,
ExchangeEvents,
SubscriptionOpts,
IndexedFilterValues,
OrderCancellationRequest,
OrderFillRequest,
LogCancelContractEventArgs,
LogErrorContractEventArgs,
LogFillContractEventArgs,
LogCancelContractEventArgs,
LogWithDecodedArgs,
MethodOpts,
ValidateOrderFillableOpts,
Order,
OrderAddresses,
OrderCancellationRequest,
OrderFillRequest,
OrderTransactionOpts,
OrderValues,
RawLog,
EventCallback,
ExchangeContractEventArgs,
DecodedLogArgs,
SignedOrder,
SubscriptionOpts,
ValidateOrderFillableOpts,
} from '../types';
import {assert} from '../utils/assert';
import {utils} from '../utils/utils';
import {OrderValidationUtils} from '../utils/order_validation_utils';
import {ContractWrapper} from './contract_wrapper';
import {TokenWrapper} from './token_wrapper';
import {decorators} from '../utils/decorators';
import {AbiDecoder} from '../utils/abi_decoder';
import {assert} from '../utils/assert';
import {decorators} from '../utils/decorators';
import {ExchangeTransferSimulator} from '../utils/exchange_transfer_simulator';
import {artifacts} from '../artifacts';
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';
const SHOULD_VALIDATE_BY_DEFAULT = true;
@@ -63,6 +65,7 @@ export class ExchangeWrapper extends ContractWrapper {
[ExchangeContractErrCodes.ERROR_FILL_BALANCE_ALLOWANCE]: ExchangeContractErrs.FillBalanceAllowanceError,
};
private _contractAddressIfExists?: string;
private _zrxContractAddressIfExists?: string;
private static _getOrderAddressesAndValues(order: Order): [OrderAddresses, OrderValues] {
const orderAddresses: OrderAddresses = [
order.maker,
@@ -81,9 +84,9 @@ export class ExchangeWrapper extends ContractWrapper {
];
return [orderAddresses, orderValues];
}
constructor(web3Wrapper: Web3Wrapper, abiDecoder: AbiDecoder,
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder: AbiDecoder,
tokenWrapper: TokenWrapper, contractAddressIfExists?: string) {
super(web3Wrapper, abiDecoder);
super(web3Wrapper, networkId, abiDecoder);
this._tokenWrapper = tokenWrapper;
this._orderValidationUtils = new OrderValidationUtils(tokenWrapper, this);
this._contractAddressIfExists = contractAddressIfExists;
@@ -166,37 +169,25 @@ export class ExchangeWrapper extends ContractWrapper {
public async fillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber,
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
takerAddress: string,
orderTransactionOpts?: OrderTransactionOpts): Promise<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) ?
SHOULD_VALIDATE_BY_DEFAULT :
orderTransactionOpts.shouldValidate;
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
SHOULD_VALIDATE_BY_DEFAULT :
orderTransactionOpts.shouldValidate;
if (shouldValidate) {
const zrxTokenAddress = await this.getZRXTokenAddressAsync();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper);
const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress);
}
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder);
const gas = await exchangeInstance.fillOrder.estimateGasAsync(
orderAddresses,
orderValues,
fillTakerTokenAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
signedOrder.ecSignature.v,
signedOrder.ecSignature.r,
signedOrder.ecSignature.s,
{
from: takerAddress,
},
);
const txHash: string = await exchangeInstance.fillOrder.sendTransactionAsync(
orderAddresses,
orderValues,
@@ -207,7 +198,8 @@ export class ExchangeWrapper extends ContractWrapper {
signedOrder.ecSignature.s,
{
from: takerAddress,
gas,
gas: orderTransactionOpts.gasLimit,
gasPrice: orderTransactionOpts.gasPrice,
},
);
return txHash;
@@ -233,7 +225,7 @@ export class ExchangeWrapper extends ContractWrapper {
public async fillOrdersUpToAsync(signedOrders: SignedOrder[], fillTakerTokenAmount: BigNumber,
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
takerAddress: string,
orderTransactionOpts?: OrderTransactionOpts): Promise<string> {
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema);
const takerTokenAddresses = _.map(signedOrders, signedOrder => signedOrder.takerTokenAddress);
assert.hasAtMostOneUniqueValue(takerTokenAddresses,
@@ -245,12 +237,12 @@ export class ExchangeWrapper extends ContractWrapper {
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
const shouldValidate = _.isUndefined(orderTransactionOpts) ?
SHOULD_VALIDATE_BY_DEFAULT :
orderTransactionOpts.shouldValidate;
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
SHOULD_VALIDATE_BY_DEFAULT :
orderTransactionOpts.shouldValidate;
if (shouldValidate) {
const zrxTokenAddress = await this.getZRXTokenAddressAsync();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper);
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);
@@ -275,18 +267,6 @@ export class ExchangeWrapper extends ContractWrapper {
);
const exchangeInstance = await this._getExchangeContractAsync();
const gas = await exchangeInstance.fillOrdersUpTo.estimateGasAsync(
orderAddressesArray,
orderValuesArray,
fillTakerTokenAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
vArray,
rArray,
sArray,
{
from: takerAddress,
},
);
const txHash = await exchangeInstance.fillOrdersUpTo.sendTransactionAsync(
orderAddressesArray,
orderValuesArray,
@@ -297,7 +277,8 @@ export class ExchangeWrapper extends ContractWrapper {
sArray,
{
from: takerAddress,
gas,
gas: orderTransactionOpts.gasLimit,
gasPrice: orderTransactionOpts.gasPrice,
},
);
return txHash;
@@ -325,7 +306,7 @@ export class ExchangeWrapper extends ContractWrapper {
public async batchFillOrdersAsync(orderFillRequests: OrderFillRequest[],
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
takerAddress: string,
orderTransactionOpts?: OrderTransactionOpts): Promise<string> {
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema);
const exchangeContractAddresses = _.map(
orderFillRequests,
@@ -335,12 +316,12 @@ export class ExchangeWrapper extends ContractWrapper {
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress);
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
const shouldValidate = _.isUndefined(orderTransactionOpts) ?
SHOULD_VALIDATE_BY_DEFAULT :
orderTransactionOpts.shouldValidate;
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
SHOULD_VALIDATE_BY_DEFAULT :
orderTransactionOpts.shouldValidate;
if (shouldValidate) {
const zrxTokenAddress = await this.getZRXTokenAddressAsync();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper);
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,
@@ -367,18 +348,6 @@ export class ExchangeWrapper extends ContractWrapper {
);
const exchangeInstance = await this._getExchangeContractAsync();
const gas = await exchangeInstance.batchFillOrders.estimateGasAsync(
orderAddressesArray,
orderValuesArray,
fillTakerTokenAmounts,
shouldThrowOnInsufficientBalanceOrAllowance,
vArray,
rArray,
sArray,
{
from: takerAddress,
},
);
const txHash = await exchangeInstance.batchFillOrders.sendTransactionAsync(
orderAddressesArray,
orderValuesArray,
@@ -389,7 +358,8 @@ export class ExchangeWrapper extends ContractWrapper {
sArray,
{
from: takerAddress,
gas,
gas: orderTransactionOpts.gasLimit,
gasPrice: orderTransactionOpts.gasPrice,
},
);
return txHash;
@@ -408,36 +378,24 @@ export class ExchangeWrapper extends ContractWrapper {
@decorators.contractCallErrorHandler
public async fillOrKillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber,
takerAddress: string,
orderTransactionOpts?: OrderTransactionOpts): Promise<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) ?
SHOULD_VALIDATE_BY_DEFAULT :
orderTransactionOpts.shouldValidate;
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
SHOULD_VALIDATE_BY_DEFAULT :
orderTransactionOpts.shouldValidate;
if (shouldValidate) {
const zrxTokenAddress = await this.getZRXTokenAddressAsync();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper);
const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress);
}
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder);
const gas = await exchangeInstance.fillOrKillOrder.estimateGasAsync(
orderAddresses,
orderValues,
fillTakerTokenAmount,
signedOrder.ecSignature.v,
signedOrder.ecSignature.r,
signedOrder.ecSignature.s,
{
from: takerAddress,
},
);
const txHash = await exchangeInstance.fillOrKillOrder.sendTransactionAsync(
orderAddresses,
orderValues,
@@ -447,7 +405,8 @@ export class ExchangeWrapper extends ContractWrapper {
signedOrder.ecSignature.s,
{
from: takerAddress,
gas,
gas: orderTransactionOpts.gasLimit,
gasPrice: orderTransactionOpts.gasPrice,
},
);
return txHash;
@@ -464,7 +423,7 @@ export class ExchangeWrapper extends ContractWrapper {
@decorators.contractCallErrorHandler
public async batchFillOrKillAsync(orderFillRequests: OrderFillRequest[],
takerAddress: string,
orderTransactionOpts?: OrderTransactionOpts): Promise<string> {
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
assert.doesConformToSchema('orderFillRequests', orderFillRequests,
schemas.orderFillRequestsSchema);
const exchangeContractAddresses = _.map(
@@ -479,12 +438,12 @@ export class ExchangeWrapper extends ContractWrapper {
}
const exchangeInstance = await this._getExchangeContractAsync();
const shouldValidate = _.isUndefined(orderTransactionOpts) ?
SHOULD_VALIDATE_BY_DEFAULT :
orderTransactionOpts.shouldValidate;
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
SHOULD_VALIDATE_BY_DEFAULT :
orderTransactionOpts.shouldValidate;
if (shouldValidate) {
const zrxTokenAddress = await this.getZRXTokenAddressAsync();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper);
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,
@@ -506,18 +465,6 @@ 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 gas = await exchangeInstance.batchFillOrKillOrders.estimateGasAsync(
orderAddresses,
orderValues,
fillTakerTokenAmounts,
vParams,
rParams,
sParams,
{
from: takerAddress,
},
);
const txHash = await exchangeInstance.batchFillOrKillOrders.sendTransactionAsync(
orderAddresses,
orderValues,
@@ -527,7 +474,8 @@ export class ExchangeWrapper extends ContractWrapper {
sParams,
{
from: takerAddress,
gas,
gas: orderTransactionOpts.gasLimit,
gasPrice: orderTransactionOpts.gasPrice,
},
);
return txHash;
@@ -543,39 +491,32 @@ export class ExchangeWrapper extends ContractWrapper {
@decorators.contractCallErrorHandler
public async cancelOrderAsync(order: Order|SignedOrder,
cancelTakerTokenAmount: BigNumber,
orderTransactionOpts?: OrderTransactionOpts): Promise<string> {
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) ?
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);
await this._orderValidationUtils.validateCancelOrderThrowIfInvalidAsync(
OrderValidationUtils.validateCancelOrderThrowIfInvalid(
order, cancelTakerTokenAmount, unavailableTakerTokenAmount);
}
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order);
const gas = await exchangeInstance.cancelOrder.estimateGasAsync(
orderAddresses,
orderValues,
cancelTakerTokenAmount,
{
from: order.maker,
},
);
const txHash = await exchangeInstance.cancelOrder.sendTransactionAsync(
orderAddresses,
orderValues,
cancelTakerTokenAmount,
{
from: order.maker,
gas,
gas: orderTransactionOpts.gasLimit,
gasPrice: orderTransactionOpts.gasPrice,
},
);
return txHash;
@@ -590,7 +531,7 @@ export class ExchangeWrapper extends ContractWrapper {
*/
@decorators.contractCallErrorHandler
public async batchCancelOrdersAsync(orderCancellationRequests: OrderCancellationRequest[],
orderTransactionOpts?: OrderTransactionOpts): Promise<string> {
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
assert.doesConformToSchema('orderCancellationRequests', orderCancellationRequests,
schemas.orderCancellationRequestsSchema);
const exchangeContractAddresses = _.map(
@@ -603,14 +544,14 @@ export class ExchangeWrapper extends ContractWrapper {
assert.hasAtMostOneUniqueValue(makers, ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed);
const maker = makers[0];
await assert.isSenderAddressAsync('maker', maker, this._web3Wrapper);
const shouldValidate = _.isUndefined(orderTransactionOpts) ?
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);
await this._orderValidationUtils.validateCancelOrderThrowIfInvalidAsync(
OrderValidationUtils.validateCancelOrderThrowIfInvalid(
orderCancellationRequest.order, orderCancellationRequest.takerTokenCancelAmount,
unavailableTakerTokenAmount,
);
@@ -630,21 +571,14 @@ 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 gas = await exchangeInstance.batchCancelOrders.estimateGasAsync(
orderAddresses,
orderValues,
cancelTakerTokenAmounts,
{
from: maker,
},
);
const txHash = await exchangeInstance.batchCancelOrders.sendTransactionAsync(
orderAddresses,
orderValues,
cancelTakerTokenAmounts,
{
from: maker,
gas,
gas: orderTransactionOpts.gasLimit,
gasPrice: orderTransactionOpts.gasPrice,
},
);
return txHash;
@@ -657,13 +591,13 @@ export class ExchangeWrapper extends ContractWrapper {
* @param callback Callback that gets called when a log is added/removed
* @return Subscription token used later to unsubscribe
*/
public async subscribeAsync<ArgsType extends ExchangeContractEventArgs>(
public subscribe<ArgsType extends ExchangeContractEventArgs>(
eventName: ExchangeEvents, indexFilterValues: IndexedFilterValues,
callback: EventCallback<ArgsType>): Promise<string> {
callback: EventCallback<ArgsType>): string {
assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
assert.isFunction('callback', callback);
const exchangeContractAddress = await this.getContractAddressAsync();
const exchangeContractAddress = this.getContractAddress();
const subscriptionToken = this._subscribe<ArgsType>(
exchangeContractAddress, eventName, indexFilterValues, artifacts.ExchangeArtifact.abi, callback,
);
@@ -690,7 +624,7 @@ export class ExchangeWrapper extends ContractWrapper {
assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
assert.doesConformToSchema('subscriptionOpts', subscriptionOpts, schemas.subscriptionOptsSchema);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
const exchangeContractAddress = await this.getContractAddressAsync();
const exchangeContractAddress = this.getContractAddress();
const logs = await this._getLogsAsync<ArgsType>(
exchangeContractAddress, eventName, subscriptionOpts, indexFilterValues, artifacts.ExchangeArtifact.abi,
);
@@ -701,10 +635,9 @@ export class ExchangeWrapper extends ContractWrapper {
* that the user-passed web3 provider is connected to.
* @returns The Ethereum address of the Exchange contract being used.
*/
public async getContractAddressAsync(): Promise<string> {
const exchangeInstance = await this._getExchangeContractAsync();
const exchangeAddress = exchangeInstance.address;
return exchangeAddress;
public getContractAddress(): string {
const contractAddress = this._getContractAddress(artifacts.ExchangeArtifact, this._contractAddressIfExists);
return contractAddress;
}
/**
* Checks if order is still fillable and throws an error otherwise. Useful for orderbook
@@ -719,9 +652,9 @@ export class ExchangeWrapper extends ContractWrapper {
signedOrder: SignedOrder, opts?: ValidateOrderFillableOpts,
): Promise<void> {
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
const zrxTokenAddress = await this.getZRXTokenAddressAsync();
const zrxTokenAddress = this.getZRXTokenAddress();
const expectedFillTakerTokenAmount = !_.isUndefined(opts) ? opts.expectedFillTakerTokenAmount : undefined;
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper);
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
await this._orderValidationUtils.validateOrderFillableOrThrowAsync(
exchangeTradeEmulator, signedOrder, zrxTokenAddress, expectedFillTakerTokenAmount,
);
@@ -740,8 +673,8 @@ export class ExchangeWrapper extends ContractWrapper {
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
const zrxTokenAddress = await this.getZRXTokenAddressAsync();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper);
const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress);
}
@@ -757,7 +690,7 @@ export class ExchangeWrapper extends ContractWrapper {
assert.isValidBaseUnitAmount('cancelTakerTokenAmount', cancelTakerTokenAmount);
const orderHash = utils.getOrderHashHex(order);
const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
await this._orderValidationUtils.validateCancelOrderThrowIfInvalidAsync(
OrderValidationUtils.validateCancelOrderThrowIfInvalid(
order, cancelTakerTokenAmount, unavailableTakerTokenAmount);
}
/**
@@ -774,8 +707,8 @@ export class ExchangeWrapper extends ContractWrapper {
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
const zrxTokenAddress = await this.getZRXTokenAddressAsync();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper);
const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress);
}
@@ -819,12 +752,13 @@ export class ExchangeWrapper extends ContractWrapper {
* Returns the ZRX token address used by the exchange contract.
* @return Address of ZRX token
*/
public async getZRXTokenAddressAsync(): Promise<string> {
const exchangeInstance = await this._getExchangeContractAsync();
const ZRXtokenAddress = await exchangeInstance.ZRX_TOKEN_CONTRACT.callAsync();
return ZRXtokenAddress;
public getZRXTokenAddress(): string {
const contractAddress = this._getContractAddress(
artifacts.ZRXArtifact, this._zrxContractAddressIfExists,
);
return contractAddress;
}
private async _invalidateContractInstancesAsync(): Promise<void> {
private _invalidateContractInstances(): void {
this.unsubscribeAll();
delete this._exchangeContractIfExists;
}
@@ -855,10 +789,11 @@ export class ExchangeWrapper extends ContractWrapper {
if (!_.isUndefined(this._exchangeContractIfExists)) {
return this._exchangeContractIfExists;
}
const contractInstance = await this._instantiateContractIfExistsAsync<ExchangeContract>(
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
artifacts.ExchangeArtifact, this._contractAddressIfExists,
);
this._exchangeContractIfExists = contractInstance as ExchangeContract;
const contractInstance = new ExchangeContract(web3ContractInstance, this._web3Wrapper.getContractDefaults());
this._exchangeContractIfExists = contractInstance;
return this._exchangeContractIfExists;
}
private async _getTokenTransferProxyAddressAsync(): Promise<string> {
@@ -867,4 +802,4 @@ export class ExchangeWrapper extends ContractWrapper {
const tokenTransferProxyAddressLowerCase = tokenTransferProxyAddress.toLowerCase();
return tokenTransferProxyAddressLowerCase;
}
}
} // tslint:disable:max-file-line-count

View File

@@ -0,0 +1,34 @@
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>(
txData: T,
estimateGasAsync?: (txData: T) => Promise<number>,
): Promise<TxData> {
// Gas amount sourced with the following priorities:
// 1. Optional param passed in to public method call
// 2. Global config passed in at library instantiation
// 3. Gas estimate calculation + safety margin
const removeUndefinedProperties = _.pickBy;
const txDataWithDefaults = {
...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
};
if (_.isUndefined(txDataWithDefaults.gas) && !_.isUndefined(estimateGasAsync)) {
const estimatedGas = await estimateGasAsync(txData);
txDataWithDefaults.gas = estimatedGas;
}
return txDataWithDefaults;
}
constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) {
this.web3ContractInstance = web3ContractInstance;
this.defaults = defaults;
}
}

View File

@@ -0,0 +1,363 @@
/**
* 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

@@ -0,0 +1,730 @@
/**
* 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

@@ -0,0 +1,232 @@
/**
* 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

@@ -0,0 +1,550 @@
/**
* 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

@@ -0,0 +1,285 @@
/**
* 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,10 +1,13 @@
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import * as _ from 'lodash';
import {Web3Wrapper} from '../web3_wrapper';
import {assert} from '../utils/assert';
import {Token, TokenRegistryContract, TokenMetadata} from '../types';
import {constants} from '../utils/constants';
import {ContractWrapper} from './contract_wrapper';
import {artifacts} from '../artifacts';
import {Token, TokenMetadata, ZeroExError} from '../types';
import {assert} from '../utils/assert';
import {constants} from '../utils/constants';
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.
@@ -12,8 +15,20 @@ import {artifacts} from '../artifacts';
export class TokenRegistryWrapper extends ContractWrapper {
private _tokenRegistryContractIfExists?: TokenRegistryContract;
private _contractAddressIfExists?: string;
constructor(web3Wrapper: Web3Wrapper, contractAddressIfExists?: string) {
super(web3Wrapper);
private static _createTokenFromMetadata(metadata: TokenMetadata): Token|undefined {
if (metadata[0] === constants.NULL_ADDRESS) {
return undefined;
}
const token = {
address: metadata[0],
name: metadata[1],
symbol: metadata[2],
decimals: metadata[3].toNumber(),
};
return token;
}
constructor(web3Wrapper: Web3Wrapper, networkId: number, contractAddressIfExists?: string) {
super(web3Wrapper, networkId);
this._contractAddressIfExists = contractAddressIfExists;
}
/**
@@ -26,7 +41,7 @@ export class TokenRegistryWrapper extends ContractWrapper {
const addresses = await this.getTokenAddressesAsync();
const tokenPromises: Array<Promise<Token|undefined>> = _.map(
addresses,
(address: string) => (this.getTokenIfExistsAsync(address)),
async (address: string) => this.getTokenIfExistsAsync(address),
);
const tokens = await Promise.all(tokenPromises);
return tokens as Token[];
@@ -49,7 +64,7 @@ export class TokenRegistryWrapper extends ContractWrapper {
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
const metadata = await tokenRegistryContract.getTokenMetaData.callAsync(address);
const token = this._createTokenFromMetadata(metadata);
const token = TokenRegistryWrapper._createTokenFromMetadata(metadata);
return token;
}
public async getTokenAddressBySymbolIfExistsAsync(symbol: string): Promise<string|undefined> {
@@ -74,14 +89,14 @@ export class TokenRegistryWrapper extends ContractWrapper {
assert.isString('symbol', symbol);
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
const metadata = await tokenRegistryContract.getTokenBySymbol.callAsync(symbol);
const token = this._createTokenFromMetadata(metadata);
const token = TokenRegistryWrapper._createTokenFromMetadata(metadata);
return token;
}
public async getTokenByNameIfExistsAsync(name: string): Promise<Token|undefined> {
assert.isString('name', name);
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
const metadata = await tokenRegistryContract.getTokenByName.callAsync(name);
const token = this._createTokenFromMetadata(metadata);
const token = TokenRegistryWrapper._createTokenFromMetadata(metadata);
return token;
}
/**
@@ -89,22 +104,11 @@ export class TokenRegistryWrapper extends ContractWrapper {
* that the user-passed web3 provider is connected to.
* @returns The Ethereum address of the TokenRegistry contract being used.
*/
public async getContractAddressAsync(): Promise<string> {
const tokenRegistryInstance = await this._getTokenRegistryContractAsync();
const tokenRegistryAddress = tokenRegistryInstance.address;
return tokenRegistryAddress;
}
private _createTokenFromMetadata(metadata: TokenMetadata): Token|undefined {
if (metadata[0] === constants.NULL_ADDRESS) {
return undefined;
}
const token = {
address: metadata[0],
name: metadata[1],
symbol: metadata[2],
decimals: metadata[3].toNumber(),
};
return token;
public getContractAddress(): string {
const contractAddress = this._getContractAddress(
artifacts.TokenRegistryArtifact, this._contractAddressIfExists,
);
return contractAddress;
}
private _invalidateContractInstance(): void {
delete this._tokenRegistryContractIfExists;
@@ -113,10 +117,13 @@ export class TokenRegistryWrapper extends ContractWrapper {
if (!_.isUndefined(this._tokenRegistryContractIfExists)) {
return this._tokenRegistryContractIfExists;
}
const contractInstance = await this._instantiateContractIfExistsAsync<TokenRegistryContract>(
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
artifacts.TokenRegistryArtifact, this._contractAddressIfExists,
);
this._tokenRegistryContractIfExists = contractInstance as TokenRegistryContract;
const contractInstance = new TokenRegistryContract(
web3ContractInstance, this._web3Wrapper.getContractDefaults(),
);
this._tokenRegistryContractIfExists = contractInstance;
return this._tokenRegistryContractIfExists;
}
}

View File

@@ -1,18 +1,21 @@
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import * as _ from 'lodash';
import {Web3Wrapper} from '../web3_wrapper';
import {ContractWrapper} from './contract_wrapper';
import {artifacts} from '../artifacts';
import {TokenTransferProxyContract} from '../types';
import {ZeroExError} from '../types';
import {ContractWrapper} from './contract_wrapper';
import {TokenTransferProxyContract} from './generated/token_transfer_proxy';
/**
* This class includes the functionality related to interacting with the TokenTransferProxy contract.
*/
export class TokenTransferProxyWrapper extends ContractWrapper {
private _tokenTransferProxyContractIfExists?: TokenTransferProxyContract;
private _tokenTransferProxyContractAddressFetcher: () => Promise<string>;
constructor(web3Wrapper: Web3Wrapper, tokenTransferProxyContractAddressFetcher: () => Promise<string>) {
super(web3Wrapper);
this._tokenTransferProxyContractAddressFetcher = tokenTransferProxyContractAddressFetcher;
private _contractAddressIfExists?: string;
constructor(web3Wrapper: Web3Wrapper, networkId: number, contractAddressIfExists?: string) {
super(web3Wrapper, networkId);
this._contractAddressIfExists = contractAddressIfExists;
}
/**
* Check if the Exchange contract address is authorized by the TokenTransferProxy contract.
@@ -38,10 +41,11 @@ export class TokenTransferProxyWrapper extends ContractWrapper {
* that the user-passed web3 provider is connected to.
* @returns The Ethereum address of the TokenTransferProxy contract being used.
*/
public async getContractAddressAsync(): Promise<string> {
const proxyInstance = await this._getTokenTransferProxyContractAsync();
const proxyAddress = proxyInstance.address;
return proxyAddress;
public getContractAddress(): string {
const contractAddress = this._getContractAddress(
artifacts.TokenTransferProxyArtifact, this._contractAddressIfExists,
);
return contractAddress;
}
private _invalidateContractInstance(): void {
delete this._tokenTransferProxyContractIfExists;
@@ -50,11 +54,13 @@ export class TokenTransferProxyWrapper extends ContractWrapper {
if (!_.isUndefined(this._tokenTransferProxyContractIfExists)) {
return this._tokenTransferProxyContractIfExists;
}
const contractAddress = await this._tokenTransferProxyContractAddressFetcher();
const contractInstance = await this._instantiateContractIfExistsAsync<TokenTransferProxyContract>(
artifacts.TokenTransferProxyArtifact, contractAddress,
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
artifacts.TokenTransferProxyArtifact, this._contractAddressIfExists,
);
this._tokenTransferProxyContractIfExists = contractInstance as TokenTransferProxyContract;
const contractInstance = new TokenTransferProxyContract(
web3ContractInstance, this._web3Wrapper.getContractDefaults(),
);
this._tokenTransferProxyContractIfExists = contractInstance;
return this._tokenTransferProxyContractIfExists;
}
}

View File

@@ -1,23 +1,27 @@
import * as _ from 'lodash';
import BigNumber from 'bignumber.js';
import {schemas} from '@0xproject/json-schemas';
import {Web3Wrapper} from '../web3_wrapper';
import {assert} from '../utils/assert';
import {constants} from '../utils/constants';
import {ContractWrapper} from './contract_wrapper';
import {AbiDecoder} from '../utils/abi_decoder';
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import BigNumber from 'bignumber.js';
import * as _ from 'lodash';
import {artifacts} from '../artifacts';
import {
TokenContract,
ZeroExError,
TokenEvents,
IndexedFilterValues,
SubscriptionOpts,
MethodOpts,
LogWithDecodedArgs,
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 {ContractWrapper} from './contract_wrapper';
import {TokenContract} from './generated/token';
import {TokenTransferProxyWrapper} from './token_transfer_proxy_wrapper';
const ALLOWANCE_TO_ZERO_GAS_AMOUNT = 47275;
@@ -29,12 +33,12 @@ 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 _tokenTransferProxyContractAddressFetcher: () => Promise<string>;
constructor(web3Wrapper: Web3Wrapper, abiDecoder: AbiDecoder,
tokenTransferProxyContractAddressFetcher: () => Promise<string>) {
super(web3Wrapper, abiDecoder);
private _tokenTransferProxyWrapper: TokenTransferProxyWrapper;
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder: AbiDecoder,
tokenTransferProxyWrapper: TokenTransferProxyWrapper) {
super(web3Wrapper, networkId, abiDecoder);
this._tokenContractsByAddress = {};
this._tokenTransferProxyContractAddressFetcher = tokenTransferProxyContractAddressFetcher;
this._tokenTransferProxyWrapper = tokenTransferProxyWrapper;
}
/**
* Retrieves an owner's ERC20 token balance.
@@ -63,24 +67,21 @@ export class TokenWrapper extends ContractWrapper {
* for spenderAddress.
* @param spenderAddress The hex encoded user Ethereum address who will be able to spend the set allowance.
* @param amountInBaseUnits The allowance amount you would like to set.
* @param txOpts Transaction parameters.
* @return Transaction hash.
*/
public async setAllowanceAsync(tokenAddress: string, ownerAddress: string, spenderAddress: string,
amountInBaseUnits: BigNumber): Promise<string> {
amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise<string> {
await assert.isSenderAddressAsync('ownerAddress', ownerAddress, this._web3Wrapper);
assert.isETHAddressHex('spenderAddress', spenderAddress);
assert.isETHAddressHex('tokenAddress', tokenAddress);
assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
const tokenContract = await this._getTokenContractAsync(tokenAddress);
// Hack: for some reason default estimated gas amount causes `base fee exceeds gas limit` exception
// on testrpc. Probably related to https://github.com/ethereumjs/testrpc/issues/294
// TODO: Debug issue in testrpc and submit a PR, then remove this hack
const networkIdIfExists = await this._web3Wrapper.getNetworkIdIfExistsAsync();
const gas = networkIdIfExists === constants.TESTRPC_NETWORK_ID ? ALLOWANCE_TO_ZERO_GAS_AMOUNT : undefined;
const txHash = await tokenContract.approve.sendTransactionAsync(spenderAddress, amountInBaseUnits, {
from: ownerAddress,
gas,
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
});
return txHash;
}
@@ -93,12 +94,13 @@ export class TokenWrapper extends ContractWrapper {
* @param ownerAddress The hex encoded user Ethereum address who would like to set an allowance
* for spenderAddress.
* @param spenderAddress The hex encoded user Ethereum address who will be able to spend the set allowance.
* @param txOpts Transaction parameters.
* @return Transaction hash.
*/
public async setUnlimitedAllowanceAsync(tokenAddress: string, ownerAddress: string,
spenderAddress: string): Promise<string> {
spenderAddress: string, txOpts: TransactionOpts = {}): Promise<string> {
const txHash = await this.setAllowanceAsync(
tokenAddress, ownerAddress, spenderAddress, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
tokenAddress, ownerAddress, spenderAddress, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, txOpts,
);
return txHash;
}
@@ -133,7 +135,7 @@ export class TokenWrapper extends ContractWrapper {
assert.isETHAddressHex('ownerAddress', ownerAddress);
assert.isETHAddressHex('tokenAddress', tokenAddress);
const proxyAddress = await this._getTokenTransferProxyAddressAsync();
const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress();
const allowanceInBaseUnits = await this.getAllowanceAsync(tokenAddress, ownerAddress, proxyAddress, methodOpts);
return allowanceInBaseUnits;
}
@@ -144,16 +146,19 @@ export class TokenWrapper extends ContractWrapper {
* @param ownerAddress The hex encoded user Ethereum address who is setting an allowance
* for the Proxy contract.
* @param amountInBaseUnits The allowance amount specified in baseUnits.
* @param txOpts Transaction parameters.
* @return Transaction hash.
*/
public async setProxyAllowanceAsync(tokenAddress: string, ownerAddress: string,
amountInBaseUnits: BigNumber): Promise<string> {
amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise<string> {
assert.isETHAddressHex('ownerAddress', ownerAddress);
assert.isETHAddressHex('tokenAddress', tokenAddress);
assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
const proxyAddress = await this._getTokenTransferProxyAddressAsync();
const txHash = await this.setAllowanceAsync(tokenAddress, ownerAddress, proxyAddress, amountInBaseUnits);
const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress();
const txHash = await this.setAllowanceAsync(
tokenAddress, ownerAddress, proxyAddress, amountInBaseUnits, txOpts,
);
return txHash;
}
/**
@@ -164,11 +169,14 @@ export class TokenWrapper extends ContractWrapper {
* @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
* @param ownerAddress The hex encoded user Ethereum address who is setting an allowance
* for the Proxy contract.
* @param txOpts Transaction parameters.
* @return Transaction hash.
*/
public async setUnlimitedProxyAllowanceAsync(tokenAddress: string, ownerAddress: string): Promise<string> {
public async setUnlimitedProxyAllowanceAsync(
tokenAddress: string, ownerAddress: string, txOpts: TransactionOpts = {},
): Promise<string> {
const txHash = await this.setProxyAllowanceAsync(
tokenAddress, ownerAddress, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
tokenAddress, ownerAddress, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, txOpts,
);
return txHash;
}
@@ -178,10 +186,11 @@ export class TokenWrapper extends ContractWrapper {
* @param fromAddress The hex encoded user Ethereum address that will send the funds.
* @param toAddress The hex encoded user Ethereum address that will receive the funds.
* @param amountInBaseUnits The amount (specified in baseUnits) of the token to transfer.
* @param txOpts Transaction parameters.
* @return Transaction hash.
*/
public async transferAsync(tokenAddress: string, fromAddress: string, toAddress: string,
amountInBaseUnits: BigNumber): Promise<string> {
amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise<string> {
assert.isETHAddressHex('tokenAddress', tokenAddress);
await assert.isSenderAddressAsync('fromAddress', fromAddress, this._web3Wrapper);
assert.isETHAddressHex('toAddress', toAddress);
@@ -196,6 +205,8 @@ export class TokenWrapper extends ContractWrapper {
const txHash = await tokenContract.transfer.sendTransactionAsync(toAddress, amountInBaseUnits, {
from: fromAddress,
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
});
return txHash;
}
@@ -210,10 +221,11 @@ export class TokenWrapper extends ContractWrapper {
* `fromAddress` must have set an allowance to the `senderAddress`
* before this call.
* @param amountInBaseUnits The amount (specified in baseUnits) of the token to transfer.
* @param txOpts Transaction parameters.
* @return Transaction hash.
*/
public async transferFromAsync(tokenAddress: string, fromAddress: string, toAddress: string,
senderAddress: string, amountInBaseUnits: BigNumber):
senderAddress: string, amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}):
Promise<string> {
assert.isETHAddressHex('tokenAddress', tokenAddress);
assert.isETHAddressHex('fromAddress', fromAddress);
@@ -237,6 +249,8 @@ export class TokenWrapper extends ContractWrapper {
fromAddress, toAddress, amountInBaseUnits,
{
from: senderAddress,
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
},
);
return txHash;
@@ -290,7 +304,7 @@ export class TokenWrapper extends ContractWrapper {
);
return logs;
}
private _invalidateContractInstancesAsync(): void {
private _invalidateContractInstances(): void {
this.unsubscribeAll();
this._tokenContractsByAddress = {};
}
@@ -299,15 +313,14 @@ export class TokenWrapper extends ContractWrapper {
if (!_.isUndefined(tokenContract)) {
return tokenContract;
}
const contractInstance = await this._instantiateContractIfExistsAsync<TokenContract>(
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
artifacts.TokenArtifact, tokenAddress,
);
tokenContract = contractInstance as TokenContract;
const contractInstance = new TokenContract(
web3ContractInstance, this._web3Wrapper.getContractDefaults(),
);
tokenContract = contractInstance;
this._tokenContractsByAddress[tokenAddress] = tokenContract;
return tokenContract;
}
private async _getTokenTransferProxyAddressAsync(): Promise<string> {
const tokenTransferProxyContractAddress = await this._tokenTransferProxyContractAddressFetcher();
return tokenTransferProxyContractAddress;
}
}

View File

@@ -39,12 +39,6 @@ declare module 'compare-versions' {
export = compareVersions;
}
// es6-promisify declarations
declare function promisify(original: any, settings?: any): ((...arg: any[]) => Promise<any>);
declare module 'es6-promisify' {
export = promisify;
}
declare module 'ethereumjs-abi' {
const soliditySHA3: (argTypes: string[], args: any[]) => Buffer;
}

View File

@@ -6,8 +6,6 @@ export {
ECSignature,
ZeroExError,
EventCallback,
EventCallbackAsync,
EventCallbackSync,
ExchangeContractErrs,
ContractEvent,
Token,
@@ -34,6 +32,7 @@ export {
LogWithDecodedArgs,
MethodOpts,
OrderTransactionOpts,
TransactionOpts,
FilterObject,
LogEvent,
DecodedLogEvent,

View File

@@ -1,6 +1,7 @@
import * as Web3 from 'web3';
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import * as _ from 'lodash';
import {Web3Wrapper} from '../web3_wrapper';
import * as Web3 from 'web3';
import {
BlockParamLiteral,
EventCallback,
@@ -8,11 +9,11 @@ import {
ZeroExError,
} from '../types';
import {AbiDecoder} from '../utils/abi_decoder';
import {intervalUtils} from '../utils/interval_utils';
import {assert} from '../utils/assert';
import {intervalUtils} from '../utils/interval_utils';
import {utils} from '../utils/utils';
const DEFAULT_EVENT_POLLING_INTERVAL = 200;
const DEFAULT_EVENT_POLLING_INTERVAL_MS = 200;
enum LogEventState {
Removed,
@@ -28,11 +29,11 @@ export class EventWatcher {
private _pollingIntervalMs: number;
private _intervalIdIfExists?: NodeJS.Timer;
private _lastEvents: Web3.LogEntry[] = [];
constructor(web3Wrapper: Web3Wrapper, pollingIntervalMs: undefined|number) {
constructor(web3Wrapper: Web3Wrapper, pollingIntervalIfExistsMs: undefined|number) {
this._web3Wrapper = web3Wrapper;
this._pollingIntervalMs = _.isUndefined(pollingIntervalMs) ?
DEFAULT_EVENT_POLLING_INTERVAL :
pollingIntervalMs;
this._pollingIntervalMs = _.isUndefined(pollingIntervalIfExistsMs) ?
DEFAULT_EVENT_POLLING_INTERVAL_MS :
pollingIntervalIfExistsMs;
}
public subscribe(callback: EventWatcherCallback): void {
assert.isFunction('callback', callback);
@@ -81,7 +82,7 @@ export class EventWatcher {
...log,
};
if (!_.isUndefined(this._intervalIdIfExists)) {
await callback(logEvent);
callback(logEvent);
}
}
}

View File

@@ -0,0 +1,77 @@
import {BigNumber} from 'bignumber.js';
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';
const DEFAULT_EXPIRATION_MARGIN_MS = 0;
const DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS = 50;
/**
* This class includes the functionality to detect expired orders.
* 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();
const comparator = (lhs: string, rhs: string) => scoreFunction(lhs) - scoreFunction(rhs);
this.orderHashByExpirationRBTree = new RBTree(comparator);
}
public subscribe(callback: (orderHash: string) => void): void {
if (!_.isUndefined(this.orderExpirationCheckingIntervalIdIfExists)) {
throw new Error(ZeroExError.SubscriptionAlreadyPresent);
}
this.orderExpirationCheckingIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
this.pruneExpiredOrders.bind(this, callback), this.orderExpirationCheckingIntervalMs,
);
}
public unsubscribe(): void {
if (_.isUndefined(this.orderExpirationCheckingIntervalIdIfExists)) {
throw new Error(ZeroExError.SubscriptionNotFound);
}
intervalUtils.clearAsyncExcludingInterval(this.orderExpirationCheckingIntervalIdIfExists);
delete this.orderExpirationCheckingIntervalIdIfExists;
}
public addOrder(orderHash: string, expirationUnixTimestampMs: BigNumber): void {
this.expiration[orderHash] = expirationUnixTimestampMs;
this.orderHashByExpirationRBTree.insert(orderHash);
}
public removeOrder(orderHash: string): void {
this.orderHashByExpirationRBTree.remove(orderHash);
delete this.expiration[orderHash];
}
private pruneExpiredOrders(callback: (orderHash: string) => void): void {
const currentUnixTimestampMs = utils.getCurrentUnixTimestampMs();
while (true) {
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 isSubscriptionActive = _.isUndefined(this.orderExpirationCheckingIntervalIdIfExists);
if (hasNoExpiredOrders || isSubscriptionActive) {
break;
}
const orderHash = this.orderHashByExpirationRBTree.min();
this.orderHashByExpirationRBTree.remove(orderHash);
delete this.expiration[orderHash];
callback(orderHash);
}
}
}

View File

@@ -1,41 +1,44 @@
import * as _ from 'lodash';
import {schemas} from '@0xproject/json-schemas';
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import * as _ from 'lodash';
import {ZeroEx} from '../0x';
import {EventWatcher} from './event_watcher';
import {assert} from '../utils/assert';
import {utils} from '../utils/utils';
import {artifacts} from '../artifacts';
import {AbiDecoder} from '../utils/abi_decoder';
import {OrderStateUtils} from '../utils/order_state_utils';
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 {
LogEvent,
OrderState,
SignedOrder,
Web3Provider,
BlockParamLiteral,
LogWithDecodedArgs,
ContractEventArgs,
OnOrderStateChangeCallback,
OrderStateWatcherConfig,
ApprovalContractEventArgs,
TransferContractEventArgs,
LogFillContractEventArgs,
LogCancelContractEventArgs,
BlockParamLiteral,
ContractEventArgs,
ExchangeContractErrs,
ExchangeEvents,
LogCancelContractEventArgs,
LogEvent,
LogFillContractEventArgs,
LogWithDecodedArgs,
OnOrderStateChangeCallback,
OrderState,
OrderStateWatcherConfig,
SignedOrder,
TokenEvents,
TransferContractEventArgs,
Web3Provider,
ZeroExError,
} from '../types';
import {Web3Wrapper} from '../web3_wrapper';
import {TokenWrapper} from '../contract_wrappers/token_wrapper';
import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper';
import {OrderFilledCancelledLazyStore} from '../stores/order_filled_cancelled_lazy_store';
import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store';
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';
const DEFAULT_NUM_CONFIRMATIONS = 0;
import {EventWatcher} from './event_watcher';
import {ExpirationWatcher} from './expiration_watcher';
interface DependentOrderHashes {
[makerAddress: string]: {
[makerToken: string]: Set<string>,
[makerToken: string]: Set<string>;
};
}
@@ -43,6 +46,12 @@ interface OrderByOrderHash {
[orderHash: string]: SignedOrder;
}
interface OrderStateByOrderHash {
[orderHash: string]: OrderState;
}
const DEFAULT_CLEANUP_JOB_INTERVAL_MS = 1000 * 60 * 60; // 1h
/**
* This class includes all the functionality related to watching a set of orders
* for potential changes in order validity/fillability. The orderWatcher notifies
@@ -50,28 +59,46 @@ interface OrderByOrderHash {
* the order should be deemed invalid.
*/
export class OrderStateWatcher {
private _orderStateByOrderHashCache: OrderStateByOrderHash = {};
private _orderByOrderHash: OrderByOrderHash = {};
private _dependentOrderHashes: DependentOrderHashes = {};
private _callbackIfExistsAsync?: OnOrderStateChangeCallback;
private _callbackIfExists?: OnOrderStateChangeCallback;
private _eventWatcher: EventWatcher;
private _web3Wrapper: Web3Wrapper;
private _abiDecoder: AbiDecoder;
private _expirationWatcher: ExpirationWatcher;
private _orderStateUtils: OrderStateUtils;
private _orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore;
private _balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore;
private _cleanupJobInterval: number;
private _cleanupJobIntervalIdIfExists?: NodeJS.Timer;
constructor(
web3Wrapper: Web3Wrapper, abiDecoder: AbiDecoder, token: TokenWrapper, exchange: ExchangeWrapper,
config?: OrderStateWatcherConfig,
) {
this._abiDecoder = abiDecoder;
this._web3Wrapper = web3Wrapper;
const eventPollingIntervalMs = _.isUndefined(config) ? undefined : config.eventPollingIntervalMs;
this._eventWatcher = new EventWatcher(web3Wrapper, eventPollingIntervalMs);
this._balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(token);
const pollingIntervalIfExistsMs = _.isUndefined(config) ? undefined : config.eventPollingIntervalMs;
this._eventWatcher = new EventWatcher(web3Wrapper, pollingIntervalIfExistsMs);
this._balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
token, BlockParamLiteral.Pending,
);
this._orderFilledCancelledLazyStore = new OrderFilledCancelledLazyStore(exchange);
this._orderStateUtils = new OrderStateUtils(
this._balanceAndProxyAllowanceLazyStore, this._orderFilledCancelledLazyStore,
);
const orderExpirationCheckingIntervalMsIfExists = _.isUndefined(config) ?
undefined :
config.orderExpirationCheckingIntervalMs;
const expirationMarginIfExistsMs = _.isUndefined(config) ?
undefined :
config.expirationMarginMs;
this._expirationWatcher = new ExpirationWatcher(
expirationMarginIfExistsMs, orderExpirationCheckingIntervalMsIfExists,
);
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
@@ -84,6 +111,8 @@ export class OrderStateWatcher {
assert.isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker);
this._orderByOrderHash[orderHash] = signedOrder;
this.addToDependentOrderHashes(signedOrder, orderHash);
const expirationUnixTimestampMs = signedOrder.expirationUnixTimestampSec.times(1000);
this._expirationWatcher.addOrder(orderHash, expirationUnixTimestampMs);
}
/**
* Removes an order from the orderStateWatcher
@@ -96,7 +125,12 @@ export class OrderStateWatcher {
return; // noop
}
delete this._orderByOrderHash[orderHash];
delete this._orderStateByOrderHashCache[orderHash];
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._expirationWatcher.removeOrder(orderHash);
}
/**
* Starts an orderStateWatcher subscription. The callback will be called every time a watched order's
@@ -106,23 +140,69 @@ export class OrderStateWatcher {
*/
public subscribe(callback: OnOrderStateChangeCallback): void {
assert.isFunction('callback', callback);
if (!_.isUndefined(this._callbackIfExistsAsync)) {
if (!_.isUndefined(this._callbackIfExists)) {
throw new Error(ZeroExError.SubscriptionAlreadyPresent);
}
this._callbackIfExistsAsync = callback;
this._callbackIfExists = callback;
this._eventWatcher.subscribe(this._onEventWatcherCallbackAsync.bind(this));
this._expirationWatcher.subscribe(this._onOrderExpired.bind(this));
this._cleanupJobIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
this._cleanupAsync.bind(this), this._cleanupJobInterval,
);
}
/**
* Ends an orderStateWatcher subscription.
*/
public unsubscribe(): void {
if (_.isUndefined(this._callbackIfExistsAsync)) {
if (_.isUndefined(this._callbackIfExists) || _.isUndefined(this._cleanupJobIntervalIdIfExists)) {
throw new Error(ZeroExError.SubscriptionNotFound);
}
this._balanceAndProxyAllowanceLazyStore.deleteAll();
this._orderFilledCancelledLazyStore.deleteAll();
delete this._callbackIfExistsAsync;
delete this._callbackIfExists;
this._eventWatcher.unsubscribe();
this._expirationWatcher.unsubscribe();
intervalUtils.clearAsyncExcludingInterval(this._cleanupJobIntervalIdIfExists);
}
private async _cleanupAsync(): Promise<void> {
for (const orderHash of _.keys(this._orderByOrderHash)) {
this._cleanupOrderRelatedState(orderHash);
await this._emitRevalidateOrdersAsync([orderHash]);
}
}
private _cleanupOrderRelatedState(orderHash: string): void {
const signedOrder = this._orderByOrderHash[orderHash];
this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(orderHash);
this._orderFilledCancelledLazyStore.deleteCancelledTakerAmount(orderHash);
this._balanceAndProxyAllowanceLazyStore.deleteBalance(signedOrder.makerTokenAddress, signedOrder.maker);
this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(signedOrder.makerTokenAddress, signedOrder.maker);
this._balanceAndProxyAllowanceLazyStore.deleteBalance(signedOrder.takerTokenAddress, signedOrder.taker);
this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(signedOrder.takerTokenAddress, signedOrder.taker);
const zrxTokenAddress = this._getZRXTokenAddress();
if (!signedOrder.makerFee.isZero()) {
this._balanceAndProxyAllowanceLazyStore.deleteBalance(zrxTokenAddress, signedOrder.maker);
this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(zrxTokenAddress, signedOrder.maker);
}
if (!signedOrder.takerFee.isZero()) {
this._balanceAndProxyAllowanceLazyStore.deleteBalance(zrxTokenAddress, signedOrder.taker);
this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(zrxTokenAddress, signedOrder.taker);
}
}
private _onOrderExpired(orderHash: string): void {
const orderState: OrderState = {
isValid: false,
orderHash,
error: ExchangeContractErrs.OrderFillExpired,
};
if (!_.isUndefined(this._orderByOrderHash[orderHash])) {
this.removeOrder(orderHash);
if (!_.isUndefined(this._callbackIfExists)) {
this._callbackIfExists(orderState);
}
}
}
private async _onEventWatcherCallbackAsync(log: LogEvent): Promise<void> {
const maybeDecodedLog = this._abiDecoder.tryToDecodeLogOrNoop(log);
@@ -200,17 +280,23 @@ export class OrderStateWatcher {
}
private async _emitRevalidateOrdersAsync(orderHashes: string[]): Promise<void> {
for (const orderHash of orderHashes) {
const signedOrder = this._orderByOrderHash[orderHash] as SignedOrder;
const signedOrder = this._orderByOrderHash[orderHash];
// Most of these calls will never reach the network because the data is fetched from stores
// and only updated when cache is invalidated
const orderState = await this._orderStateUtils.getOrderStateAsync(signedOrder);
if (_.isUndefined(this._callbackIfExistsAsync)) {
if (_.isUndefined(this._callbackIfExists)) {
break; // Unsubscribe was called
}
await this._callbackIfExistsAsync(orderState);
if (_.isEqual(orderState, this._orderStateByOrderHashCache[orderHash])) {
// Actual order state didn't change
continue;
} else {
this._orderStateByOrderHashCache[orderHash] = orderState;
}
this._callbackIfExists(orderState);
}
}
private addToDependentOrderHashes(signedOrder: SignedOrder, orderHash: string) {
private addToDependentOrderHashes(signedOrder: SignedOrder, orderHash: string): void {
if (_.isUndefined(this._dependentOrderHashes[signedOrder.maker])) {
this._dependentOrderHashes[signedOrder.maker] = {};
}
@@ -218,14 +304,24 @@ export class OrderStateWatcher {
this._dependentOrderHashes[signedOrder.maker][signedOrder.makerTokenAddress] = new Set();
}
this._dependentOrderHashes[signedOrder.maker][signedOrder.makerTokenAddress].add(orderHash);
const zrxTokenAddress = this._getZRXTokenAddress();
if (_.isUndefined(this._dependentOrderHashes[signedOrder.maker][zrxTokenAddress])) {
this._dependentOrderHashes[signedOrder.maker][zrxTokenAddress] = new Set();
}
this._dependentOrderHashes[signedOrder.maker][zrxTokenAddress].add(orderHash);
}
private removeFromDependentOrderHashes(makerAddress: string, makerTokenAddress: string, orderHash: string) {
this._dependentOrderHashes[makerAddress][makerTokenAddress].delete(orderHash);
if (this._dependentOrderHashes[makerAddress][makerTokenAddress].size === 0) {
delete this._dependentOrderHashes[makerAddress][makerTokenAddress];
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];
}
if (_.isEmpty(this._dependentOrderHashes[makerAddress])) {
delete this._dependentOrderHashes[makerAddress];
}
}
private _getZRXTokenAddress(): string {
const exchange = (this._orderFilledCancelledLazyStore as any).exchange as ExchangeWrapper;
const zrxTokenAddress = exchange.getZRXTokenAddress();
return zrxTokenAddress;
}
}

View File

@@ -0,0 +1,87 @@
import {BigNumber} from 'bignumber.js';
import {SignedOrder} from '../types';
export class RemainingFillableCalculator {
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);
}
public computeRemainingMakerFillable(): BigNumber {
if (this.hasSufficientFundsForFeeAndTransferAmount()) {
return this.remainingMakerTokenAmount;
}
if (this.signedOrder.makerFee.isZero()) {
return BigNumber.min(this.remainingMakerTokenAmount, this.transferrableMakerTokenAmount);
}
return this.calculatePartiallyFillableMakerTokenAmount();
}
public computeRemainingTakerFillable(): BigNumber {
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);
return hasSufficientFunds;
} else {
const hasSufficientFundsForTransferAmount = this.transferrableMakerTokenAmount.greaterThanOrEqualTo(
this.remainingMakerTokenAmount);
const hasSufficientFundsForFeeAmount = this.transferrableMakerFeeTokenAmount.greaterThanOrEqualTo(
this.remainingMakerFeeAmount);
const hasSufficientFunds = hasSufficientFundsForTransferAmount && hasSufficientFundsForFeeAmount;
return hasSufficientFunds;
}
}
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);
// 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);
// 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) {
// 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;
// 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)));
}
// 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);
const partiallyFillableFeeTokenAmount = fillableTimesInFeeTokenBaseUnits
.times(this.signedOrder.makerTokenAmount)
.dividedToIntegerBy(this.signedOrder.makerFee);
const partiallyFillableAmount = BigNumber.min(partiallyFillableMakerTokenAmount,
partiallyFillableFeeTokenAmount);
return partiallyFillableAmount;
}
}

View File

@@ -1,6 +1,10 @@
export const zeroExConfigSchema = {
id: '/ZeroExConfig',
properties: {
networkId: {
type: 'number',
minimum: 0,
},
gasPrice: {$ref: '/Number'},
exchangeContractAddress: {$ref: '/Address'},
tokenRegistryContractAddress: {$ref: '/Address'},
@@ -20,4 +24,5 @@ export const zeroExConfigSchema = {
},
},
type: 'object',
required: ['networkId'],
};

View File

@@ -1,6 +1,7 @@
import {BigNumber} from 'bignumber.js';
import * as _ from 'lodash';
import * as Web3 from 'web3';
import {BigNumber} from 'bignumber.js';
import {TokenWrapper} from '../contract_wrappers/token_wrapper';
import {BlockParamLiteral} from '../types';
@@ -9,25 +10,27 @@ import {BlockParamLiteral} from '../types';
*/
export class BalanceAndProxyAllowanceLazyStore {
private token: TokenWrapper;
private defaultBlock: BlockParamLiteral;
private balance: {
[tokenAddress: string]: {
[userAddress: string]: BigNumber,
},
[userAddress: string]: BigNumber;
};
};
private proxyAllowance: {
[tokenAddress: string]: {
[userAddress: string]: BigNumber,
},
[userAddress: string]: BigNumber;
};
};
constructor(token: TokenWrapper) {
constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) {
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])) {
const methodOpts = {
defaultBlock: BlockParamLiteral.Pending,
defaultBlock: this.defaultBlock,
};
const balance = await this.token.getBalanceAsync(tokenAddress, userAddress, methodOpts);
this.setBalance(tokenAddress, userAddress, balance);
@@ -53,7 +56,7 @@ export class BalanceAndProxyAllowanceLazyStore {
if (_.isUndefined(this.proxyAllowance[tokenAddress]) ||
_.isUndefined(this.proxyAllowance[tokenAddress][userAddress])) {
const methodOpts = {
defaultBlock: BlockParamLiteral.Pending,
defaultBlock: this.defaultBlock,
};
const proxyAllowance = await this.token.getProxyAllowanceAsync(tokenAddress, userAddress, methodOpts);
this.setProxyAllowance(tokenAddress, userAddress, proxyAllowance);

View File

@@ -1,6 +1,7 @@
import {BigNumber} from 'bignumber.js';
import * as _ from 'lodash';
import * as Web3 from 'web3';
import {BigNumber} from 'bignumber.js';
import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper';
import {BlockParamLiteral} from '../types';
@@ -10,10 +11,10 @@ import {BlockParamLiteral} from '../types';
export class OrderFilledCancelledLazyStore {
private exchange: ExchangeWrapper;
private filledTakerAmount: {
[orderHash: string]: BigNumber,
[orderHash: string]: BigNumber;
};
private cancelledTakerAmount: {
[orderHash: string]: BigNumber,
[orderHash: string]: BigNumber;
};
constructor(exchange: ExchangeWrapper) {
this.exchange = exchange;

View File

@@ -1,9 +1,13 @@
import * as Web3 from 'web3';
import BigNumber from 'bignumber.js';
import * as Web3 from 'web3';
export enum ZeroExError {
ContractDoesNotExist = 'CONTRACT_DOES_NOT_EXIST',
ExchangeContractDoesNotExist = 'EXCHANGE_CONTRACT_DOES_NOT_EXIST',
ZRXContractDoesNotExist = 'ZRX_CONTRACT_DOES_NOT_EXIST',
EtherTokenContractDoesNotExist = 'ETHER_TOKEN_CONTRACT_DOES_NOT_EXIST',
TokenTransferProxyContractDoesNotExist = 'TOKEN_TRANSFER_PROXY_CONTRACT_DOES_NOT_EXIST',
TokenRegistryContractDoesNotExist = 'TOKEN_REGISTRY_CONTRACT_DOES_NOT_EXIST',
TokenContractDoesNotExist = 'TOKEN_CONTRACT_DOES_NOT_EXIST',
UnhandledError = 'UNHANDLED_ERROR',
UserHasNoAssociatedAddress = 'USER_HAS_NO_ASSOCIATED_ADDRESSES',
InvalidSignature = 'INVALID_SIGNATURE',
@@ -40,165 +44,13 @@ export type OrderValues = [BigNumber, BigNumber, BigNumber,
BigNumber, BigNumber, BigNumber];
export type LogEvent = Web3.LogEntryEvent;
export type DecodedLogEvent<ArgsType> = Web3.DecodedLogEntryEvent<ArgsType>;
export type EventCallbackAsync<ArgsType> = (err: null|Error, log?: DecodedLogEvent<ArgsType>) => Promise<void>;
export type EventCallbackSync<ArgsType> = (err: null|Error, log?: DecodedLogEvent<ArgsType>) => void;
export type EventCallback<ArgsType> = EventCallbackSync<ArgsType>|EventCallbackAsync<ArgsType>;
export type EventWatcherCallbackSync = (log: LogEvent) => void;
export type EventWatcherCallbackAsync = (log: LogEvent) => Promise<void>;
export type EventWatcherCallback = EventWatcherCallbackSync|EventWatcherCallbackAsync;
export interface ExchangeContract extends Web3.ContractInstance {
isValidSignature: {
callAsync: (signerAddressHex: string, dataHex: string, v: number, r: string, s: string,
txOpts?: TxOpts) => Promise<boolean>;
};
ZRX_TOKEN_CONTRACT: {
callAsync: () => Promise<string>;
};
TOKEN_TRANSFER_PROXY_CONTRACT: {
callAsync: () => Promise<string>;
};
getUnavailableTakerTokenAmount: {
callAsync: (orderHash: string, defaultBlock?: Web3.BlockParam) => Promise<BigNumber>;
};
isRoundingError: {
callAsync: (takerTokenFillAmount: BigNumber, takerTokenAmount: BigNumber,
makerTokenAmount: BigNumber, txOpts?: TxOpts) => Promise<boolean>;
};
fillOrder: {
sendTransactionAsync: (orderAddresses: OrderAddresses, orderValues: OrderValues,
fillTakerTokenAmount: BigNumber,
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
v: number, r: string, s: string, txOpts?: TxOpts) => Promise<string>;
estimateGasAsync: (orderAddresses: OrderAddresses, orderValues: OrderValues,
fillTakerTokenAmount: BigNumber,
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
v: number, r: string, s: string, txOpts?: TxOpts) => Promise<number>;
};
batchFillOrders: {
sendTransactionAsync: (orderAddresses: OrderAddresses[], orderValues: OrderValues[],
fillTakerTokenAmounts: BigNumber[],
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
v: number[], r: string[], s: string[], txOpts?: TxOpts) => Promise<string>;
estimateGasAsync: (orderAddresses: OrderAddresses[], orderValues: OrderValues[],
fillTakerTokenAmounts: BigNumber[],
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
v: number[], r: string[], s: string[], txOpts?: TxOpts) => Promise<number>;
};
fillOrdersUpTo: {
sendTransactionAsync: (orderAddresses: OrderAddresses[], orderValues: OrderValues[],
fillTakerTokenAmount: BigNumber,
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
v: number[], r: string[], s: string[], txOpts?: TxOpts) => Promise<string>;
estimateGasAsync: (orderAddresses: OrderAddresses[], orderValues: OrderValues[],
fillTakerTokenAmount: BigNumber,
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
v: number[], r: string[], s: string[], txOpts?: TxOpts) => Promise<number>;
};
cancelOrder: {
sendTransactionAsync: (orderAddresses: OrderAddresses, orderValues: OrderValues,
cancelTakerTokenAmount: BigNumber, txOpts?: TxOpts) => Promise<string>;
estimateGasAsync: (orderAddresses: OrderAddresses, orderValues: OrderValues,
cancelTakerTokenAmount: BigNumber,
txOpts?: TxOpts) => Promise<number>;
};
batchCancelOrders: {
sendTransactionAsync: (orderAddresses: OrderAddresses[], orderValues: OrderValues[],
cancelTakerTokenAmounts: BigNumber[], txOpts?: TxOpts) => Promise<string>;
estimateGasAsync: (orderAddresses: OrderAddresses[], orderValues: OrderValues[],
cancelTakerTokenAmounts: BigNumber[],
txOpts?: TxOpts) => Promise<number>;
};
fillOrKillOrder: {
sendTransactionAsync: (orderAddresses: OrderAddresses, orderValues: OrderValues,
fillTakerTokenAmount: BigNumber,
v: number, r: string, s: string, txOpts?: TxOpts) => Promise<string>;
estimateGasAsync: (orderAddresses: OrderAddresses, orderValues: OrderValues,
fillTakerTokenAmount: BigNumber,
v: number, r: string, s: string, txOpts?: TxOpts) => Promise<number>;
};
batchFillOrKillOrders: {
sendTransactionAsync: (orderAddresses: OrderAddresses[], orderValues: OrderValues[],
fillTakerTokenAmounts: BigNumber[],
v: number[], r: string[], s: string[], txOpts: TxOpts) => Promise<string>;
estimateGasAsync: (orderAddresses: OrderAddresses[], orderValues: OrderValues[],
fillTakerTokenAmounts: BigNumber[],
v: number[], r: string[], s: string[], txOpts?: TxOpts) => Promise<number>;
};
filled: {
callAsync: (orderHash: string, defaultBlock?: Web3.BlockParam) => Promise<BigNumber>;
};
cancelled: {
callAsync: (orderHash: string, defaultBlock?: Web3.BlockParam) => Promise<BigNumber>;
};
getOrderHash: {
callAsync: (orderAddresses: OrderAddresses, orderValues: OrderValues) => Promise<string>;
};
export interface DecodedLogEvent<ArgsType> {
isRemoved: boolean;
log: LogWithDecodedArgs<ArgsType>;
}
export interface TokenContract extends Web3.ContractInstance {
balanceOf: {
callAsync: (address: string, defaultBlock?: Web3.BlockParam) => Promise<BigNumber>;
};
allowance: {
callAsync: (ownerAddress: string, allowedAddress: string,
defaultBlock?: Web3.BlockParam) => Promise<BigNumber>;
};
transfer: {
sendTransactionAsync: (toAddress: string, amountInBaseUnits: BigNumber,
txOpts?: TxOpts) => Promise<string>;
};
transferFrom: {
sendTransactionAsync: (fromAddress: string, toAddress: string, amountInBaseUnits: BigNumber,
txOpts?: TxOpts) => Promise<string>;
};
approve: {
sendTransactionAsync: (proxyAddress: string, amountInBaseUnits: BigNumber,
txOpts?: TxOpts) => Promise<string>;
};
}
export interface TokenRegistryContract extends Web3.ContractInstance {
getTokenMetaData: {
callAsync: (address: string) => Promise<TokenMetadata>;
};
getTokenAddresses: {
callAsync: () => Promise<string[]>;
};
getTokenAddressBySymbol: {
callAsync: (symbol: string) => Promise<string>;
};
getTokenAddressByName: {
callAsync: (name: string) => Promise<string>;
};
getTokenBySymbol: {
callAsync: (symbol: string) => Promise<TokenMetadata>;
};
getTokenByName: {
callAsync: (name: string) => Promise<TokenMetadata>;
};
}
export interface EtherTokenContract extends Web3.ContractInstance {
deposit: {
sendTransactionAsync: (txOpts: TxOpts) => Promise<string>;
};
withdraw: {
sendTransactionAsync: (amount: BigNumber, txOpts: TxOpts) => Promise<string>;
};
}
export interface TokenTransferProxyContract extends Web3.ContractInstance {
getAuthorizedAddresses: {
callAsync: () => Promise<string[]>;
};
authorized: {
callAsync: (address: string) => Promise<boolean>;
};
}
export type EventCallback<ArgsType> = (err: null|Error, log?: DecodedLogEvent<ArgsType>) => void;
export type EventWatcherCallback = (log: LogEvent) => void;
export enum SolidityTypes {
Address = 'address',
@@ -330,6 +182,7 @@ export interface TxOpts {
from: string;
gas?: number;
value?: BigNumber;
gasPrice?: BigNumber;
}
export interface TokenAddressBySymbol {
@@ -353,9 +206,11 @@ export interface IndexedFilterValues {
[index: string]: ContractEventArg;
}
// Earliest is omitted by design. It is simply an alias for the `0` constant and
// is thus not very helpful. Moreover, this type is used in places that only accept
// `latest` or `pending`.
export enum BlockParamLiteral {
Latest = 'latest',
Earliest = 'earliest',
Pending = 'pending',
}
@@ -383,38 +238,46 @@ export type AsyncMethod = (...args: any[]) => Promise<any>;
/**
* We re-export the `Web3.Provider` type specified in the Web3 Typescript typings
* since it is the type of the `provider` argument to the `ZeroEx` constructor.
* It is however a `Web3` library type, not a native `0x.js` type.
* It is however a `Web3` library type, not a native `0x.js` type. To learn more
* about providers, visit https://0xproject.com/wiki#Web3-Provider-Explained
*/
export type Web3Provider = Web3.Provider;
export interface ExchangeContractByAddress {
[address: string]: ExchangeContract;
}
export interface JSONRPCPayload {
params: any[];
method: string;
}
/*
* eventPollingIntervalMs: How often to poll the Ethereum node for new events
* orderExpirationCheckingIntervalMs: How often to check for expired orders. Default: 50
* eventPollingIntervalMs: How often to poll the Ethereum node for new events. Defaults: 200
* expirationMarginMs: Amount of time before order expiry that you'd like to be notified
* of an orders expiration. Defaults: 0
* cleanupJobIntervalMs: How often to run a cleanup job which revalidates all the orders. Defaults: 1h
*/
export interface OrderStateWatcherConfig {
orderExpirationCheckingIntervalMs?: number;
eventPollingIntervalMs?: number;
expirationMarginMs?: number;
cleanupJobIntervalMs?: number;
}
/*
* 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
* 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
*/
export interface ZeroExConfig {
gasPrice?: BigNumber; // Gas price to use with every transaction
networkId: number;
gasPrice?: BigNumber;
exchangeContractAddress?: string;
tokenRegistryContractAddress?: string;
etherTokenContractAddress?: string;
tokenTransferProxyContractAddress?: string;
orderWatcherConfig?: OrderStateWatcherConfig;
}
@@ -435,11 +298,16 @@ export interface TransactionReceiptWithDecodedLogs extends TransactionReceipt {
logs: Array<LogWithDecodedArgs<DecodedLogArgs>|Web3.LogEntry>;
}
export type ArtifactContractName = 'ZRX'|'TokenTransferProxy'|'TokenRegistry'|'Token'|'Exchange'|'EtherToken';
export interface Artifact {
abi: any;
networks: {[networkId: number]: {
address: string;
}};
contract_name: ArtifactContractName;
abi: Web3.ContractAbi;
networks: {
[networkId: number]: {
address: string;
};
};
}
/*
@@ -463,11 +331,20 @@ export interface MethodOpts {
}
/*
* shouldValidate: Flag indicating whether the library should make attempts to validate a transaction before
* broadcasting it. For example, order has a valid signature, maker has sufficient funds, etc.
* gasPrice: Gas price in Wei to use for a transaction
* gasLimit: The amount of gas to send with a transaction
*/
export interface OrderTransactionOpts {
shouldValidate: boolean;
export interface TransactionOpts {
gasPrice?: BigNumber;
gasLimit?: number;
}
/*
* shouldValidate: Flag indicating whether the library should make attempts to validate a transaction before
* broadcasting it. For example, order has a valid signature, maker has sufficient funds, etc. Default: true
*/
export interface OrderTransactionOpts extends TransactionOpts {
shouldValidate?: boolean;
}
export type FilterObject = Web3.FilterObject;
@@ -490,6 +367,7 @@ export interface OrderRelevantState {
filledTakerTokenAmount: BigNumber;
cancelledTakerTokenAmount: BigNumber;
remainingFillableMakerTokenAmount: BigNumber;
remainingFillableTakerTokenAmount: BigNumber;
}
export interface OrderStateValid {
@@ -506,9 +384,18 @@ export interface OrderStateInvalid {
export type OrderState = OrderStateValid|OrderStateInvalid;
export type OnOrderStateChangeCallbackSync = (orderState: OrderState) => void;
export type OnOrderStateChangeCallbackAsync = (orderState: OrderState) => Promise<void>;
export type OnOrderStateChangeCallback = OnOrderStateChangeCallbackAsync|OnOrderStateChangeCallbackSync;
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;
@@ -522,4 +409,4 @@ export interface TransactionReceipt {
gasUsed: number;
contractAddress: string|null;
logs: Web3.LogEntry[];
}
} // tslint:disable:max-file-line-count

View File

@@ -1,12 +1,22 @@
import * as Web3 from 'web3';
import * as _ from 'lodash';
import BigNumber from 'bignumber.js';
import {AbiType, DecodedLogArgs, LogWithDecodedArgs, RawLog, SolidityTypes, ContractEventArgs} from '../types';
import * as _ from 'lodash';
import * as Web3 from 'web3';
import * as SolidityCoder from 'web3/lib/solidity/coder';
import {AbiType, ContractEventArgs, DecodedLogArgs, LogWithDecodedArgs, RawLog, SolidityTypes} from '../types';
export class AbiDecoder {
private savedABIs: Web3.AbiDefinition[] = [];
private methodIds: {[signatureHash: string]: Web3.EventAbi} = {};
private static padZeros(address: string) {
let formatted = address;
if (_.startsWith(formatted, '0x')) {
formatted = formatted.slice(2);
}
formatted = _.padStart(formatted, 40, '0');
return `0x${formatted}`;
}
constructor(abiArrays: Web3.AbiDefinition[][]) {
_.map(abiArrays, this.addABI.bind(this));
}
@@ -31,7 +41,7 @@ export class AbiDecoder {
// Indexed parameters are stored in topics. Non-indexed ones in decodedData
let value = param.indexed ? log.topics[topicsIndex++] : decodedData[dataIndex++];
if (param.type === SolidityTypes.Address) {
value = this.padZeros(new BigNumber(value).toString(16));
value = AbiDecoder.padZeros(new BigNumber(value).toString(16));
} else if (param.type === SolidityTypes.Uint256 ||
param.type === SolidityTypes.Uint8 ||
param.type === SolidityTypes.Uint) {
@@ -56,13 +66,4 @@ export class AbiDecoder {
});
this.savedABIs = this.savedABIs.concat(abiArray);
}
private padZeros(address: string) {
let formatted = address;
if (_.startsWith(formatted, '0x')) {
formatted = formatted.slice(2);
}
formatted = _.padStart(formatted, 40, '0');
return `0x${formatted}`;
}
}

View File

@@ -1,15 +1,17 @@
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 * as _ from 'lodash';
import * as Web3 from 'web3';
import BigNumber from 'bignumber.js';
import {SchemaValidator, Schema} from '@0xproject/json-schemas';
import {assert as sharedAssert} from '@0xproject/assert';
import {Web3Wrapper} from '../web3_wrapper';
import {signatureUtils} from '../utils/signature_utils';
import {ECSignature} from '../types';
import {signatureUtils} from '../utils/signature_utils';
const HEX_REGEX = /^0x[0-9A-F]*$/i;
export const assert = _.extend({}, sharedAssert, {
export const assert = {
...sharedAssert,
isValidSignature(orderHash: string, ecSignature: ECSignature, signerAddress: string) {
const isValidSignature = signatureUtils.isValidSignature(orderHash, ecSignature, signerAddress);
this.assert(isValidSignature, `Expected order with hash '${orderHash}' to have a valid signature`);
@@ -26,4 +28,4 @@ export const assert = _.extend({}, sharedAssert, {
const availableAddresses = await web3Wrapper.getAvailableAddressesAsync();
this.assert(!_.isEmpty(availableAddresses), 'No addresses were available on the provided web3 provider');
},
});
};

View File

@@ -0,0 +1,18 @@
import * as _ from 'lodash';
export const classUtils = {
// This is useful for classes that have nested methods. Nested methods don't get bound out of the box.
bindAll(self: any, exclude: string[] = ['contructor'], thisArg?: any): void {
for (const key of Object.getOwnPropertyNames(self)) {
const val = self[key];
if (!_.includes(exclude, key)) {
if (_.isFunction(val)) {
self[key] = val.bind(thisArg || self);
} else if (_.isObject(val)) {
classUtils.bindAll(val, exclude, self);
}
}
}
return self;
},
};

View File

@@ -1,7 +1,9 @@
import * as _ from 'lodash';
import {constants} from './constants';
import {AsyncMethod, ZeroExError} from '../types';
import {constants} from './constants';
export const decorators = {
/**
* Source: https://stackoverflow.com/a/29837695/3546986

View File

@@ -1,8 +1,9 @@
import * as _ from 'lodash';
import BigNumber from 'bignumber.js';
import {ExchangeContractErrs, TradeSide, TransferType, BlockParamLiteral} from '../types';
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';
enum FailureReason {
Balance = 'balance',
@@ -35,8 +36,13 @@ const ERR_MSG_MAPPING = {
export class ExchangeTransferSimulator {
private store: BalanceAndProxyAllowanceLazyStore;
private UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber;
constructor(token: TokenWrapper) {
this.store = new BalanceAndProxyAllowanceLazyStore(token);
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;
}
/**
@@ -54,10 +60,10 @@ export class ExchangeTransferSimulator {
const balance = await this.store.getBalanceAsync(tokenAddress, from);
const proxyAllowance = await this.store.getProxyAllowanceAsync(tokenAddress, from);
if (proxyAllowance.lessThan(amountInBaseUnits)) {
this.throwValidationError(FailureReason.ProxyAllowance, tradeSide, transferType);
ExchangeTransferSimulator.throwValidationError(FailureReason.ProxyAllowance, tradeSide, transferType);
}
if (balance.lessThan(amountInBaseUnits)) {
this.throwValidationError(FailureReason.Balance, tradeSide, transferType);
ExchangeTransferSimulator.throwValidationError(FailureReason.Balance, tradeSide, transferType);
}
await this.decreaseProxyAllowanceAsync(tokenAddress, from, amountInBaseUnits);
await this.decreaseBalanceAsync(tokenAddress, from, amountInBaseUnits);
@@ -80,9 +86,4 @@ export class ExchangeTransferSimulator {
const balance = await this.store.getBalanceAsync(tokenAddress, userAddress);
this.store.setBalance(tokenAddress, userAddress, balance.minus(amountInBaseUnits));
}
private throwValidationError(failureReason: FailureReason, tradeSide: TradeSide,
transferType: TransferType): Promise<never> {
const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType];
throw new Error(errMsg);
}
}

View File

@@ -1,8 +1,9 @@
import * as _ from 'lodash';
import * as Web3 from 'web3';
import * as uuid from 'uuid/v4';
import * as ethUtil from 'ethereumjs-util';
import * as jsSHA3 from 'js-sha3';
import * as _ from 'lodash';
import * as uuid from 'uuid/v4';
import * as Web3 from 'web3';
import {ContractEvents, IndexedFilterValues, SubscriptionOpts} from '../types';
const TOPIC_LENGTH = 32;

View File

@@ -1,26 +1,61 @@
import BigNumber from 'bignumber.js';
import * as _ from 'lodash';
import * as Web3 from 'web3';
import BigNumber from 'bignumber.js';
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 {
ExchangeContractErrs,
SignedOrder,
OrderRelevantState,
MethodOpts,
OrderRelevantState,
OrderState,
OrderStateValid,
OrderStateInvalid,
OrderStateValid,
SignedOrder,
} from '../types';
import {ZeroEx} from '../0x';
import {TokenWrapper} from '../contract_wrappers/token_wrapper';
import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper';
import {utils} from '../utils/utils';
import {constants} from '../utils/constants';
import {OrderFilledCancelledLazyStore} from '../stores/order_filled_cancelled_lazy_store';
import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store';
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 {
const unavailableTakerTokenAmount = orderRelevantState.cancelledTakerTokenAmount.add(
orderRelevantState.filledTakerTokenAmount,
);
const availableTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
if (availableTakerTokenAmount.eq(0)) {
throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero);
}
if (orderRelevantState.makerBalance.eq(0)) {
throw new Error(ExchangeContractErrs.InsufficientMakerBalance);
}
if (orderRelevantState.makerProxyAllowance.eq(0)) {
throw new Error(ExchangeContractErrs.InsufficientMakerAllowance);
}
if (!signedOrder.makerFee.eq(0)) {
if (orderRelevantState.makerFeeBalance.eq(0)) {
throw new Error(ExchangeContractErrs.InsufficientMakerFeeBalance);
}
if (orderRelevantState.makerFeeProxyAllowance.eq(0)) {
throw new Error(ExchangeContractErrs.InsufficientMakerFeeAllowance);
}
}
const minFillableTakerTokenAmountWithinNoRoundingErrorRange = signedOrder.takerTokenAmount
.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;
@@ -30,7 +65,7 @@ export class OrderStateUtils {
const orderRelevantState = await this.getOrderRelevantStateAsync(signedOrder);
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
try {
this.validateIfOrderIsValid(signedOrder, orderRelevantState);
OrderStateUtils.validateIfOrderIsValid(signedOrder, orderRelevantState);
const orderState: OrderStateValid = {
isValid: true,
orderHash,
@@ -52,7 +87,7 @@ export class OrderStateUtils {
// 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 zrxTokenAddress = await exchange.getZRXTokenAddressAsync();
const zrxTokenAddress = exchange.getZRXTokenAddress();
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
const makerBalance = await this.balanceAndProxyAllowanceLazyStore.getBalanceAsync(
signedOrder.makerTokenAddress, signedOrder.maker,
@@ -76,9 +111,17 @@ export class OrderStateUtils {
const remainingTakerTokenAmount = totalTakerTokenAmount.minus(unavailableTakerTokenAmount);
const remainingMakerTokenAmount = remainingTakerTokenAmount.times(totalMakerTokenAmount)
.dividedToIntegerBy(totalTakerTokenAmount);
const fillableMakerTokenAmount = BigNumber.min([makerProxyAllowance, makerBalance]);
const remainingFillableMakerTokenAmount = BigNumber.min(fillableMakerTokenAmount, remainingMakerTokenAmount);
// TODO: Handle edge case where maker token is ZRX with fee
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 remainingFillableMakerTokenAmount = remainingFillableCalculator.computeRemainingMakerFillable();
const remainingFillableTakerTokenAmount = remainingFillableCalculator.computeRemainingTakerFillable();
const orderRelevantState = {
makerBalance,
makerProxyAllowance,
@@ -87,33 +130,8 @@ export class OrderStateUtils {
filledTakerTokenAmount,
cancelledTakerTokenAmount,
remainingFillableMakerTokenAmount,
remainingFillableTakerTokenAmount,
};
return orderRelevantState;
}
private validateIfOrderIsValid(signedOrder: SignedOrder, orderRelevantState: OrderRelevantState): void {
const unavailableTakerTokenAmount = orderRelevantState.cancelledTakerTokenAmount.add(
orderRelevantState.filledTakerTokenAmount,
);
const availableTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
if (availableTakerTokenAmount.eq(0)) {
throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero);
}
if (orderRelevantState.makerBalance.eq(0)) {
throw new Error(ExchangeContractErrs.InsufficientMakerBalance);
}
if (orderRelevantState.makerProxyAllowance.eq(0)) {
throw new Error(ExchangeContractErrs.InsufficientMakerAllowance);
}
if (!signedOrder.makerFee.eq(0)) {
if (orderRelevantState.makerFeeBalance.eq(0)) {
throw new Error(ExchangeContractErrs.InsufficientMakerFeeBalance);
}
if (orderRelevantState.makerFeeProxyAllowance.eq(0)) {
throw new Error(ExchangeContractErrs.InsufficientMakerFeeAllowance);
}
}
// TODO Add linear function solver when maker token is ZRX #badass
// Return the max amount that's fillable
}
}

View File

@@ -1,16 +1,89 @@
import * as _ from 'lodash';
import BigNumber from 'bignumber.js';
import {ExchangeContractErrs, SignedOrder, Order, ZeroExError, TradeSide, TransferType} from '../types';
import * as _ from 'lodash';
import {ZeroEx} from '../0x';
import {TokenWrapper} from '../contract_wrappers/token_wrapper';
import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper';
import {utils} from '../utils/utils';
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 {ExchangeTransferSimulator} from './exchange_transfer_simulator';
export class OrderValidationUtils {
private tokenWrapper: TokenWrapper;
private exchangeWrapper: ExchangeWrapper;
public static validateCancelOrderThrowIfInvalid(
order: Order, cancelTakerTokenAmount: BigNumber, unavailableTakerTokenAmount: BigNumber,
): void {
if (cancelTakerTokenAmount.eq(0)) {
throw new Error(ExchangeContractErrs.OrderCancelAmountZero);
}
if (order.takerTokenAmount.eq(unavailableTakerTokenAmount)) {
throw new Error(ExchangeContractErrs.OrderAlreadyCancelledOrFilled);
}
const currentUnixTimestampSec = utils.getCurrentUnixTimestampSec();
if (order.expirationUnixTimestampSec.lessThan(currentUnixTimestampSec)) {
throw new Error(ExchangeContractErrs.OrderCancelExpired);
}
}
public static async validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder,
fillTakerTokenAmount: BigNumber, senderAddress: string, zrxTokenAddress: string,
): Promise<void> {
const fillMakerTokenAmount = OrderValidationUtils.getPartialAmount(
fillTakerTokenAmount,
signedOrder.takerTokenAmount,
signedOrder.makerTokenAmount,
);
await exchangeTradeEmulator.transferFromAsync(
signedOrder.makerTokenAddress, signedOrder.maker, senderAddress, fillMakerTokenAmount,
TradeSide.Maker, TransferType.Trade,
);
await exchangeTradeEmulator.transferFromAsync(
signedOrder.takerTokenAddress, senderAddress, signedOrder.maker, fillTakerTokenAmount,
TradeSide.Taker, TransferType.Trade,
);
const makerFeeAmount = OrderValidationUtils.getPartialAmount(
fillTakerTokenAmount,
signedOrder.takerTokenAmount,
signedOrder.makerFee,
);
await exchangeTradeEmulator.transferFromAsync(
zrxTokenAddress, signedOrder.maker, signedOrder.feeRecipient, makerFeeAmount, TradeSide.Maker,
TransferType.Fee,
);
const takerFeeAmount = OrderValidationUtils.getPartialAmount(
fillTakerTokenAmount,
signedOrder.takerTokenAmount,
signedOrder.takerFee,
);
await exchangeTradeEmulator.transferFromAsync(
zrxTokenAddress, senderAddress, signedOrder.feeRecipient, takerFeeAmount, TradeSide.Taker,
TransferType.Fee,
);
}
private static validateRemainingFillAmountNotZeroOrThrow(
takerTokenAmount: BigNumber, unavailableTakerTokenAmount: BigNumber,
) {
if (takerTokenAmount.eq(unavailableTakerTokenAmount)) {
throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero);
}
}
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 {
const fillMakerTokenAmount = numerator
.mul(target)
.div(denominator)
.round(0);
return fillMakerTokenAmount;
}
constructor(tokenWrapper: TokenWrapper, exchangeWrapper: ExchangeWrapper) {
this.tokenWrapper = tokenWrapper;
this.exchangeWrapper = exchangeWrapper;
@@ -20,15 +93,15 @@ export class OrderValidationUtils {
expectedFillTakerTokenAmount?: BigNumber): Promise<void> {
const orderHash = utils.getOrderHashHex(signedOrder);
const unavailableTakerTokenAmount = await this.exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
this.validateRemainingFillAmountNotZeroOrThrow(
OrderValidationUtils.validateRemainingFillAmountNotZeroOrThrow(
signedOrder.takerTokenAmount, unavailableTakerTokenAmount,
);
this.validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
OrderValidationUtils.validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
let fillTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
if (!_.isUndefined(expectedFillTakerTokenAmount)) {
fillTakerTokenAmount = expectedFillTakerTokenAmount;
}
const fillMakerTokenAmount = this.getPartialAmount(
const fillMakerTokenAmount = OrderValidationUtils.getPartialAmount(
fillTakerTokenAmount,
signedOrder.takerTokenAmount,
signedOrder.makerTokenAmount,
@@ -37,7 +110,7 @@ export class OrderValidationUtils {
signedOrder.makerTokenAddress, signedOrder.maker, signedOrder.taker, fillMakerTokenAmount,
TradeSide.Maker, TransferType.Trade,
);
const makerFeeAmount = this.getPartialAmount(
const makerFeeAmount = OrderValidationUtils.getPartialAmount(
fillTakerTokenAmount,
signedOrder.takerTokenAmount,
signedOrder.makerFee,
@@ -59,18 +132,18 @@ export class OrderValidationUtils {
throw new Error(ZeroExError.InvalidSignature);
}
const unavailableTakerTokenAmount = await this.exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
this.validateRemainingFillAmountNotZeroOrThrow(
OrderValidationUtils.validateRemainingFillAmountNotZeroOrThrow(
signedOrder.takerTokenAmount, unavailableTakerTokenAmount,
);
if (signedOrder.taker !== constants.NULL_ADDRESS && signedOrder.taker !== takerAddress) {
throw new Error(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker);
}
this.validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
OrderValidationUtils.validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
const remainingTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
const filledTakerTokenAmount = remainingTakerTokenAmount.lessThan(fillTakerTokenAmount) ?
remainingTakerTokenAmount :
fillTakerTokenAmount;
await this.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
exchangeTradeEmulator, signedOrder, filledTakerTokenAmount, takerAddress, zrxTokenAddress,
);
@@ -92,75 +165,4 @@ export class OrderValidationUtils {
throw new Error(ExchangeContractErrs.InsufficientRemainingFillAmount);
}
}
public async validateCancelOrderThrowIfInvalidAsync(order: Order,
cancelTakerTokenAmount: BigNumber,
unavailableTakerTokenAmount: BigNumber,
): Promise<void> {
if (cancelTakerTokenAmount.eq(0)) {
throw new Error(ExchangeContractErrs.OrderCancelAmountZero);
}
if (order.takerTokenAmount.eq(unavailableTakerTokenAmount)) {
throw new Error(ExchangeContractErrs.OrderAlreadyCancelledOrFilled);
}
const currentUnixTimestampSec = utils.getCurrentUnixTimestamp();
if (order.expirationUnixTimestampSec.lessThan(currentUnixTimestampSec)) {
throw new Error(ExchangeContractErrs.OrderCancelExpired);
}
}
public async validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder,
fillTakerTokenAmount: BigNumber, senderAddress: string, zrxTokenAddress: string): Promise<void> {
const fillMakerTokenAmount = this.getPartialAmount(
fillTakerTokenAmount,
signedOrder.takerTokenAmount,
signedOrder.makerTokenAmount,
);
await exchangeTradeEmulator.transferFromAsync(
signedOrder.makerTokenAddress, signedOrder.maker, senderAddress, fillMakerTokenAmount,
TradeSide.Maker, TransferType.Trade,
);
await exchangeTradeEmulator.transferFromAsync(
signedOrder.takerTokenAddress, senderAddress, signedOrder.maker, fillTakerTokenAmount,
TradeSide.Taker, TransferType.Trade,
);
const makerFeeAmount = this.getPartialAmount(
fillTakerTokenAmount,
signedOrder.takerTokenAmount,
signedOrder.makerFee,
);
await exchangeTradeEmulator.transferFromAsync(
zrxTokenAddress, signedOrder.maker, signedOrder.feeRecipient, makerFeeAmount, TradeSide.Maker,
TransferType.Fee,
);
const takerFeeAmount = this.getPartialAmount(
fillTakerTokenAmount,
signedOrder.takerTokenAmount,
signedOrder.takerFee,
);
await exchangeTradeEmulator.transferFromAsync(
zrxTokenAddress, senderAddress, signedOrder.feeRecipient, takerFeeAmount, TradeSide.Taker,
TransferType.Fee,
);
}
private validateRemainingFillAmountNotZeroOrThrow(
takerTokenAmount: BigNumber, unavailableTakerTokenAmount: BigNumber,
) {
if (takerTokenAmount.eq(unavailableTakerTokenAmount)) {
throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero);
}
}
private validateOrderNotExpiredOrThrow(expirationUnixTimestampSec: BigNumber) {
const currentUnixTimestampSec = utils.getCurrentUnixTimestamp();
if (expirationUnixTimestampSec.lessThan(currentUnixTimestampSec)) {
throw new Error(ExchangeContractErrs.OrderFillExpired);
}
}
private getPartialAmount(numerator: BigNumber, denominator: BigNumber,
target: BigNumber): BigNumber {
const fillMakerTokenAmount = numerator
.mul(target)
.div(denominator)
.round(0);
return fillMakerTokenAmount;
}
}

View File

@@ -1,4 +1,5 @@
import * as ethUtil from 'ethereumjs-util';
import {ECSignature} from '../types';
export const signatureUtils = {

View File

@@ -1,9 +1,10 @@
import * as _ from 'lodash';
import * as ethABI from 'ethereumjs-abi';
import * as ethUtil from 'ethereumjs-util';
import {Order, SignedOrder, SolidityTypes} from '../types';
import BigNumber from 'bignumber.js';
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';
export const utils = {
/**
@@ -49,7 +50,10 @@ export const utils = {
const hashHex = ethUtil.bufferToHex(hashBuff);
return hashHex;
},
getCurrentUnixTimestamp(): BigNumber {
return new BigNumber(Date.now() / 1000);
getCurrentUnixTimestampSec(): BigNumber {
return new BigNumber(Date.now() / 1000).round();
},
getCurrentUnixTimestampMs(): BigNumber {
return new BigNumber(Date.now());
},
};

View File

@@ -1,14 +1,16 @@
import * as _ from 'lodash';
import * as chai from 'chai';
import {chaiSetup} from './utils/chai_setup';
import 'mocha';
import BigNumber from 'bignumber.js';
import * as chai from 'chai';
import * as _ from 'lodash';
import 'mocha';
import * as Sinon from 'sinon';
import {ZeroEx, Order, ZeroExError, LogWithDecodedArgs, ApprovalContractEventArgs, TokenEvents} from '../src';
import {ApprovalContractEventArgs, LogWithDecodedArgs, Order, TokenEvents, ZeroEx, ZeroExError} 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 {BlockchainLifecycle} from './utils/blockchain_lifecycle';
const blockchainLifecycle = new BlockchainLifecycle();
chaiSetup.configure();
@@ -16,7 +18,10 @@ const expect = chai.expect;
describe('ZeroEx library', () => {
const web3 = web3Factory.create();
const zeroEx = new ZeroEx(web3.currentProvider);
const config = {
networkId: constants.TESTRPC_NETWORK_ID,
};
const zeroEx = new ZeroEx(web3.currentProvider, config);
describe('#setProvider', () => {
it('overrides provider in nested web3s and invalidates contractInstances', async () => {
// Instantiate the contract instances with the current provider
@@ -28,7 +33,7 @@ describe('ZeroEx library', () => {
const newProvider = web3Factory.getRpcProvider();
// Add property to newProvider so that we can differentiate it from old provider
(newProvider as any).zeroExTestId = 1;
await zeroEx.setProviderAsync(newProvider);
zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID);
// Check that contractInstances with old provider are removed after provider update
expect((zeroEx.exchange as any)._exchangeContractIfExists).to.be.undefined();
@@ -36,11 +41,11 @@ describe('ZeroEx library', () => {
// Check that all nested web3 wrapper instances return the updated provider
const nestedWeb3WrapperProvider = (zeroEx as any)._web3Wrapper.getCurrentProvider();
expect((nestedWeb3WrapperProvider as any).zeroExTestId).to.be.a('number');
expect((nestedWeb3WrapperProvider).zeroExTestId).to.be.a('number');
const exchangeWeb3WrapperProvider = (zeroEx.exchange as any)._web3Wrapper.getCurrentProvider();
expect((exchangeWeb3WrapperProvider as any).zeroExTestId).to.be.a('number');
expect((exchangeWeb3WrapperProvider).zeroExTestId).to.be.a('number');
const tokenRegistryWeb3WrapperProvider = (zeroEx.tokenRegistry as any)._web3Wrapper.getCurrentProvider();
expect((tokenRegistryWeb3WrapperProvider as any).zeroExTestId).to.be.a('number');
expect((tokenRegistryWeb3WrapperProvider).zeroExTestId).to.be.a('number');
});
});
describe('#isValidSignature', () => {
@@ -220,7 +225,7 @@ describe('ZeroEx library', () => {
const tokens = await zeroEx.tokenRegistry.getTokensAsync();
const tokenUtils = new TokenUtils(tokens);
const zrxTokenAddress = tokenUtils.getProtocolTokenOrThrow().address;
const proxyAddress = await zeroEx.proxy.getContractAddressAsync();
const proxyAddress = zeroEx.proxy.getContractAddress();
const txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(zrxTokenAddress, coinbase);
const txReceiptWithDecodedLogs = await zeroEx.awaitTransactionMinedAsync(txHash);
const log = txReceiptWithDecodedLogs.logs[0] as LogWithDecodedArgs<ApprovalContractEventArgs>;
@@ -232,28 +237,29 @@ describe('ZeroEx library', () => {
});
describe('#config', () => {
it('allows to specify exchange contract address', async () => {
const config = {
const zeroExConfig = {
exchangeContractAddress: ZeroEx.NULL_ADDRESS,
networkId: constants.TESTRPC_NETWORK_ID,
};
const zeroExWithWrongExchangeAddress = new ZeroEx(web3.currentProvider, config);
return expect(zeroExWithWrongExchangeAddress.exchange.getContractAddressAsync())
.to.be.rejectedWith(ZeroExError.ContractDoesNotExist);
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 config = {
const zeroExConfig = {
etherTokenContractAddress: ZeroEx.NULL_ADDRESS,
networkId: constants.TESTRPC_NETWORK_ID,
};
const zeroExWithWrongEtherTokenAddress = new ZeroEx(web3.currentProvider, config);
return expect(zeroExWithWrongEtherTokenAddress.etherToken.getContractAddressAsync())
.to.be.rejectedWith(ZeroExError.ContractDoesNotExist);
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 config = {
const zeroExConfig = {
tokenRegistryContractAddress: ZeroEx.NULL_ADDRESS,
networkId: constants.TESTRPC_NETWORK_ID,
};
const zeroExWithWrongTokenRegistryAddress = new ZeroEx(web3.currentProvider, config);
return expect(zeroExWithWrongTokenRegistryAddress.tokenRegistry.getContractAddressAsync())
.to.be.rejectedWith(ZeroExError.ContractDoesNotExist);
const zeroExWithWrongTokenRegistryAddress = new ZeroEx(web3.currentProvider, zeroExConfig);
expect(zeroExWithWrongTokenRegistryAddress.tokenRegistry.getContractAddress())
.to.be.equal(ZeroEx.NULL_ADDRESS);
});
});
});

View File

@@ -1,8 +1,10 @@
import * as fs from 'fs';
import * as chai from 'chai';
import {chaiSetup} from './utils/chai_setup';
import * as fs from 'fs';
import HDWalletProvider = require('truffle-hdwallet-provider');
import {ZeroEx} from '../src';
import {chaiSetup} from './utils/chai_setup';
import {constants} from './utils/constants';
chaiSetup.configure();
@@ -18,15 +20,18 @@ describe('Artifacts', () => {
const packageJSON = JSON.parse(packageJSONContent);
const mnemonic = packageJSON.config.mnemonic;
const web3Provider = new HDWalletProvider(mnemonic, kovanRpcUrl);
const zeroEx = new ZeroEx(web3Provider);
const config = {
networkId: constants.KOVAN_NETWORK_ID,
};
const zeroEx = new ZeroEx(web3Provider, config);
it('token registry contract is deployed', async () => {
await (zeroEx.tokenRegistry as any)._getTokenRegistryContractAsync();
}).timeout(TIMEOUT);
it('proxy contract is deployed', async () => {
await (zeroEx.token as any)._getTokenTransferProxyAddressAsync();
await (zeroEx.proxy as any)._getTokenTransferProxyContractAsync();
}).timeout(TIMEOUT);
it('exchange contract is deployed', async () => {
await zeroEx.exchange.getContractAddressAsync();
await (zeroEx.exchange as any)._getExchangeContractAsync();
}).timeout(TIMEOUT);
});
describe('contracts are deployed on ropsten', () => {
@@ -35,15 +40,18 @@ describe('Artifacts', () => {
const packageJSON = JSON.parse(packageJSONContent);
const mnemonic = packageJSON.config.mnemonic;
const web3Provider = new HDWalletProvider(mnemonic, ropstenRpcUrl);
const zeroEx = new ZeroEx(web3Provider);
const config = {
networkId: constants.ROPSTEN_NETWORK_ID,
};
const zeroEx = new ZeroEx(web3Provider, config);
it('token registry contract is deployed', async () => {
await (zeroEx.tokenRegistry as any)._getTokenRegistryContractAsync();
}).timeout(TIMEOUT);
it('proxy contract is deployed', async () => {
await (zeroEx.token as any)._getTokenTransferProxyAddressAsync();
await (zeroEx.proxy as any)._getTokenTransferProxyContractAsync();
}).timeout(TIMEOUT);
it('exchange contract is deployed', async () => {
await zeroEx.exchange.getContractAddressAsync();
await (zeroEx.exchange as any)._getExchangeContractAsync();
}).timeout(TIMEOUT);
});
});

View File

@@ -1,14 +1,20 @@
import * as chai from 'chai';
import 'mocha';
import {ZeroEx} from '../src';
import {assert} from '../src/utils/assert';
import {constants} from './utils/constants';
import {web3Factory} from './utils/web3_factory';
const expect = chai.expect;
describe('Assertion library', () => {
const web3 = web3Factory.create();
const zeroEx = new ZeroEx(web3.currentProvider);
const config = {
networkId: constants.TESTRPC_NETWORK_ID,
};
const zeroEx = new ZeroEx(web3.currentProvider, config);
describe('#isSenderAddressHexAsync', () => {
it('throws when address is invalid', async () => {
const address = '0xdeadbeef';

View File

@@ -1,11 +1,14 @@
import 'mocha';
import * as chai from 'chai';
import {chaiSetup} from './utils/chai_setup';
import * as Web3 from 'web3';
import BigNumber from 'bignumber.js';
import {web3Factory} from './utils/web3_factory';
import * as chai from 'chai';
import 'mocha';
import * as Web3 from 'web3';
import {ZeroEx, ZeroExError} 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';
chaiSetup.configure();
const expect = chai.expect;
@@ -15,7 +18,7 @@ const blockchainLifecycle = new BlockchainLifecycle();
// a small amount of ETH will be used to pay this gas cost. We therefore check that the difference between
// the expected balance and actual balance (given the amount of ETH deposited), only deviates by the amount
// required to pay gas costs.
const MAX_REASONABLE_GAS_COST_IN_WEI = 62237;
const MAX_REASONABLE_GAS_COST_IN_WEI = 62517;
describe('EtherTokenWrapper', () => {
let web3: Web3;
@@ -28,13 +31,14 @@ describe('EtherTokenWrapper', () => {
const gasPrice = new BigNumber(1);
const zeroExConfig = {
gasPrice,
networkId: constants.TESTRPC_NETWORK_ID,
};
before(async () => {
web3 = web3Factory.create();
zeroEx = new ZeroEx(web3.currentProvider, zeroExConfig);
userAddresses = await zeroEx.getAvailableAddressesAsync();
addressWithETH = userAddresses[0];
wethContractAddress = await zeroEx.etherToken.getContractAddressAsync();
wethContractAddress = zeroEx.etherToken.getContractAddress();
depositWeiAmount = (zeroEx as any)._web3Wrapper.toWei(new BigNumber(5));
decimalPlaces = 7;
});

View File

@@ -1,20 +1,23 @@
import 'mocha';
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import BigNumber from 'bignumber.js';
import * as chai from 'chai';
import * as _ from 'lodash';
import 'mocha';
import * as Sinon from 'sinon';
import * as Web3 from 'web3';
import BigNumber from 'bignumber.js';
import {chaiSetup} from './utils/chai_setup';
import {web3Factory} from './utils/web3_factory';
import {Web3Wrapper} from '../src/web3_wrapper';
import {EventWatcher} from '../src/order_watcher/event_watcher';
import {
ZeroEx,
LogEvent,
DecodedLogEvent,
LogEvent,
ZeroEx,
} 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';
chaiSetup.configure();
const expect = chai.expect;

View File

@@ -1,19 +1,25 @@
import * as chai from 'chai';
import BigNumber from 'bignumber.js';
import {chaiSetup} from './utils/chai_setup';
import {web3Factory} from './utils/web3_factory';
import {ZeroEx, ExchangeContractErrs, Token} from '../src';
import {TradeSide, TransferType} from '../src/types';
import {BlockchainLifecycle} from './utils/blockchain_lifecycle';
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 {BlockchainLifecycle} from './utils/blockchain_lifecycle';
import {chaiSetup} from './utils/chai_setup';
import {constants} from './utils/constants';
import {web3Factory} from './utils/web3_factory';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle();
describe('ExchangeTransferSimulator', () => {
const web3 = web3Factory.create();
const zeroEx = new ZeroEx(web3.currentProvider);
const config = {
networkId: constants.TESTRPC_NETWORK_ID,
};
const zeroEx = new ZeroEx(web3.currentProvider, config);
const transferAmount = new BigNumber(5);
let userAddresses: string[];
let tokens: Token[];
@@ -37,7 +43,7 @@ describe('ExchangeTransferSimulator', () => {
});
describe('#transferFromAsync', () => {
beforeEach(() => {
exchangeTransferSimulator = new ExchangeTransferSimulator(zeroEx.token);
exchangeTransferSimulator = new ExchangeTransferSimulator(zeroEx.token, BlockParamLiteral.Latest);
});
it('throws if the user doesn\'t have enough allowance', async () => {
return expect(exchangeTransferSimulator.transferFromAsync(

View File

@@ -1,27 +1,30 @@
import 'mocha';
import * as chai from 'chai';
import * as Web3 from 'web3';
import BigNumber from 'bignumber.js';
import {chaiSetup} from './utils/chai_setup';
import {web3Factory} from './utils/web3_factory';
import {BlockchainLifecycle} from './utils/blockchain_lifecycle';
import * as chai from 'chai';
import 'mocha';
import * as Web3 from 'web3';
import {
ZeroEx,
Token,
SignedOrder,
SubscriptionOpts,
ExchangeEvents,
DecodedLogEvent,
ExchangeContractErrs,
OrderCancellationRequest,
OrderFillRequest,
LogFillContractEventArgs,
ExchangeEvents,
LogCancelContractEventArgs,
LogEvent,
DecodedLogEvent,
LogFillContractEventArgs,
OrderCancellationRequest,
OrderFillRequest,
SignedOrder,
SubscriptionOpts,
Token,
ZeroEx,
} from '../src';
import {DoneCallback, BlockParamLiteral} from '../src/types';
import {BlockParamLiteral, DoneCallback} from '../src/types';
import {BlockchainLifecycle} from './utils/blockchain_lifecycle';
import {chaiSetup} from './utils/chai_setup';
import {constants} from './utils/constants';
import {FillScenarios} from './utils/fill_scenarios';
import {TokenUtils} from './utils/token_utils';
import {web3Factory} from './utils/web3_factory';
chaiSetup.configure();
const expect = chai.expect;
@@ -38,10 +41,13 @@ describe('ExchangeWrapper', () => {
let zrxTokenAddress: string;
let fillScenarios: FillScenarios;
let exchangeContractAddress: string;
const config = {
networkId: constants.TESTRPC_NETWORK_ID,
};
before(async () => {
web3 = web3Factory.create();
zeroEx = new ZeroEx(web3.currentProvider);
exchangeContractAddress = await zeroEx.exchange.getContractAddressAsync();
zeroEx = new ZeroEx(web3.currentProvider, config);
exchangeContractAddress = zeroEx.exchange.getContractAddress();
userAddresses = await zeroEx.getAvailableAddressesAsync();
tokens = await zeroEx.tokenRegistry.getTokensAsync();
tokenUtils = new TokenUtils(tokens);
@@ -613,7 +619,7 @@ describe('ExchangeWrapper', () => {
});
});
});
describe('#subscribeAsync', () => {
describe('#subscribe', () => {
const indexFilterValues = {};
const shouldThrowOnInsufficientBalanceOrAllowance = true;
let makerTokenAddress: string;
@@ -649,10 +655,10 @@ describe('ExchangeWrapper', () => {
(async () => {
const callback = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
expect(logEvent.event).to.be.equal(ExchangeEvents.LogFill);
expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogFill);
done();
};
await zeroEx.exchange.subscribeAsync(
zeroEx.exchange.subscribe(
ExchangeEvents.LogFill, indexFilterValues, callback,
);
await zeroEx.exchange.fillOrderAsync(
@@ -665,33 +671,33 @@ describe('ExchangeWrapper', () => {
(async () => {
const callback = (err: Error, logEvent: DecodedLogEvent<LogCancelContractEventArgs>) => {
expect(logEvent.event).to.be.equal(ExchangeEvents.LogCancel);
expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogCancel);
done();
};
await zeroEx.exchange.subscribeAsync(
zeroEx.exchange.subscribe(
ExchangeEvents.LogCancel, indexFilterValues, callback,
);
await zeroEx.exchange.cancelOrderAsync(signedOrder, cancelTakerAmountInBaseUnits);
})().catch(done);
});
it('Outstanding subscriptions are cancelled when zeroEx.setProviderAsync called', (done: DoneCallback) => {
it('Outstanding subscriptions are cancelled when zeroEx.setProvider called', (done: DoneCallback) => {
(async () => {
const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
done(new Error('Expected this subscription to have been cancelled'));
};
await zeroEx.exchange.subscribeAsync(
zeroEx.exchange.subscribe(
ExchangeEvents.LogFill, indexFilterValues, callbackNeverToBeCalled,
);
const newProvider = web3Factory.getRpcProvider();
await zeroEx.setProviderAsync(newProvider);
zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID);
const callback = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
expect(logEvent.event).to.be.equal(ExchangeEvents.LogFill);
expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogFill);
done();
};
await zeroEx.exchange.subscribeAsync(
zeroEx.exchange.subscribe(
ExchangeEvents.LogFill, indexFilterValues, callback,
);
await zeroEx.exchange.fillOrderAsync(
@@ -705,7 +711,7 @@ describe('ExchangeWrapper', () => {
const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
done(new Error('Expected this subscription to have been cancelled'));
};
const subscriptionToken = await zeroEx.exchange.subscribeAsync(
const subscriptionToken = zeroEx.exchange.subscribe(
ExchangeEvents.LogFill, indexFilterValues, callbackNeverToBeCalled,
);
zeroEx.exchange.unsubscribe(subscriptionToken);
@@ -740,8 +746,8 @@ describe('ExchangeWrapper', () => {
});
});
describe('#getZRXTokenAddressAsync', () => {
it('gets the same token as is in token registry', async () => {
const zrxAddress = await zeroEx.exchange.getZRXTokenAddressAsync();
it('gets the same token as is in token registry', () => {
const zrxAddress = zeroEx.exchange.getZRXTokenAddress();
const zrxToken = tokenUtils.getProtocolTokenOrThrow();
expect(zrxAddress).to.equal(zrxToken.address);
});
@@ -754,7 +760,7 @@ describe('ExchangeWrapper', () => {
const fillableAmount = new BigNumber(5);
const shouldThrowOnInsufficientBalanceOrAllowance = true;
const subscriptionOpts: SubscriptionOpts = {
fromBlock: BlockParamLiteral.Earliest,
fromBlock: 0,
toBlock: BlockParamLiteral.Latest,
};
let txHash: string;
@@ -821,4 +827,4 @@ describe('ExchangeWrapper', () => {
expect(args.maker).to.be.equal(differentMakerAddress);
});
});
});
}); // tslint:disable:max-file-line-count

View File

@@ -0,0 +1,144 @@
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import BigNumber from 'bignumber.js';
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 {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';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle();
describe('ExpirationWatcher', () => {
let web3: Web3;
let zeroEx: ZeroEx;
let tokenUtils: TokenUtils;
let tokens: Token[];
let userAddresses: string[];
let zrxTokenAddress: string;
let fillScenarios: FillScenarios;
let exchangeContractAddress: string;
let makerTokenAddress: string;
let takerTokenAddress: string;
let coinbase: string;
let makerAddress: string;
let takerAddress: string;
let feeRecipient: string;
const fillableAmount = new BigNumber(5);
let currentUnixTimestampSec: BigNumber;
let timer: Sinon.SinonFakeTimers;
let expirationWatcher: ExpirationWatcher;
before(async () => {
web3 = web3Factory.create();
const config = {
networkId: constants.TESTRPC_NETWORK_ID,
};
zeroEx = new ZeroEx(web3.currentProvider, config);
exchangeContractAddress = zeroEx.exchange.getContractAddress();
userAddresses = await zeroEx.getAvailableAddressesAsync();
tokens = await zeroEx.tokenRegistry.getTokensAsync();
tokenUtils = new TokenUtils(tokens);
zrxTokenAddress = tokenUtils.getProtocolTokenOrThrow().address;
fillScenarios = new FillScenarios(zeroEx, userAddresses, tokens, zrxTokenAddress, exchangeContractAddress);
[coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses;
tokens = await zeroEx.tokenRegistry.getTokensAsync();
const [makerToken, takerToken] = tokenUtils.getNonProtocolTokens();
makerTokenAddress = makerToken.address;
takerTokenAddress = takerToken.address;
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
const sinonTimerConfig = {shouldAdvanceTime: true} as any;
// This constructor has incorrect types
timer = Sinon.useFakeTimers(sinonTimerConfig);
currentUnixTimestampSec = utils.getCurrentUnixTimestampSec();
expirationWatcher = new ExpirationWatcher();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
timer.restore();
expirationWatcher.unsubscribe();
});
it('correctly emits events when order expires', (done: DoneCallback) => {
(async () => {
const orderLifetimeSec = 60;
const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec);
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
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) => {
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) => {
(async () => {
const orderLifetimeSec = 60;
const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec);
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
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) => {
done(new Error('Emitted expiration went before the order actually expired'));
});
expirationWatcher.subscribe(callbackAsync);
const notEnoughTime = orderLifetimeSec - 1;
timer.tick(notEnoughTime * 1000);
done();
})().catch(done);
});
it('emits events in correct order', (done: DoneCallback) => {
(async () => {
const order1Lifetime = 60;
const order2Lifetime = 120;
const order1ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order1Lifetime);
const order2ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order2Lifetime);
const signedOrder1 = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
order1ExpirationUnixTimestampSec,
);
const signedOrder2 = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
order2ExpirationUnixTimestampSec,
);
const orderHash1 = ZeroEx.getOrderHashHex(signedOrder1);
const orderHash2 = ZeroEx.getOrderHashHex(signedOrder2);
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 orderHash = expirationOrder.shift();
expect(hash).to.be.equal(orderHash);
if (_.isEmpty(expirationOrder)) {
done();
}
});
expirationWatcher.subscribe(callbackAsync);
timer.tick(order2Lifetime * 1000);
})().catch(done);
});
});

View File

@@ -1,30 +1,33 @@
import 'mocha';
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import BigNumber from 'bignumber.js';
import * as chai from 'chai';
import * as _ from 'lodash';
import 'mocha';
import * as Web3 from 'web3';
import BigNumber from 'bignumber.js';
import { chaiSetup } from './utils/chai_setup';
import { web3Factory } from './utils/web3_factory';
import { Web3Wrapper } from '../src/web3_wrapper';
import { OrderStateWatcher } from '../src/order_watcher/order_state_watcher';
import {
DecodedLogEvent,
ExchangeContractErrs,
LogEvent,
OrderState,
OrderStateInvalid,
OrderStateValid,
SignedOrder,
Token,
ZeroEx,
LogEvent,
DecodedLogEvent,
ZeroExConfig,
OrderState,
SignedOrder,
ZeroExError,
OrderStateValid,
OrderStateInvalid,
ExchangeContractErrs,
} from '../src';
import { TokenUtils } from './utils/token_utils';
import { FillScenarios } from './utils/fill_scenarios';
import { DoneCallback } from '../src/types';
import {OrderStateWatcher} from '../src/order_watcher/order_state_watcher';
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';
const TIMEOUT_MS = 150;
@@ -47,11 +50,15 @@ describe('OrderStateWatcher', () => {
let taker: string;
let web3Wrapper: Web3Wrapper;
let signedOrder: SignedOrder;
const fillableAmount = new BigNumber(5);
const config = {
networkId: constants.TESTRPC_NETWORK_ID,
};
const decimals = constants.ZRX_DECIMALS;
const fillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals);
before(async () => {
web3 = web3Factory.create();
zeroEx = new ZeroEx(web3.currentProvider);
exchangeContractAddress = await zeroEx.exchange.getContractAddressAsync();
zeroEx = new ZeroEx(web3.currentProvider, config);
exchangeContractAddress = zeroEx.exchange.getContractAddress();
userAddresses = await zeroEx.getAvailableAddressesAsync();
[, maker, taker] = userAddresses;
tokens = await zeroEx.tokenRegistry.getTokensAsync();
@@ -178,16 +185,12 @@ describe('OrderStateWatcher', () => {
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
zeroEx.orderStateWatcher.addOrder(signedOrder);
let eventCount = 0;
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
eventCount++;
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);
if (eventCount === 2) {
done();
}
done();
});
zeroEx.orderStateWatcher.subscribe(callback);
@@ -210,9 +213,7 @@ describe('OrderStateWatcher', () => {
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
zeroEx.orderStateWatcher.addOrder(signedOrder);
let eventCount = 0;
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
eventCount++;
expect(orderState.isValid).to.be.true();
const validOrderState = orderState as OrderStateValid;
expect(validOrderState.orderHash).to.be.equal(orderHash);
@@ -221,10 +222,10 @@ describe('OrderStateWatcher', () => {
const remainingFillable = fillableAmount.minus(fillAmountInBaseUnits);
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
remainingFillable);
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
remainingFillable);
expect(orderRelevantState.makerBalance).to.be.bignumber.equal(remainingMakerBalance);
if (eventCount === 2) {
done();
}
done();
});
zeroEx.orderStateWatcher.subscribe(callback);
const shouldThrowOnInsufficientBalanceOrAllowance = true;
@@ -233,84 +234,187 @@ describe('OrderStateWatcher', () => {
);
})().catch(done);
});
describe('remainingFillableMakerTokenAmount', () => {
it('should calculate correct remaining fillable', (done: DoneCallback) => {
(async () => {
const takerFillableAmount = new BigNumber(10);
const makerFillableAmount = new BigNumber(20);
signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
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 = new BigNumber(2);
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
zeroEx.orderStateWatcher.addOrder(signedOrder);
let eventCount = 0;
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
eventCount++;
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(
new BigNumber(16));
if (eventCount === 2) {
done();
}
});
zeroEx.orderStateWatcher.subscribe(callback);
const shouldThrowOnInsufficientBalanceOrAllowance = true;
await zeroEx.exchange.fillOrderAsync(
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,
);
it('should trigger the callback when orders backing ZRX allowance changes', (done: DoneCallback) => {
(async () => {
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);
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);
});
describe('remainingFillable(M|T)akerTokenAmount', () => {
it('should calculate correct remaining fillable', (done: DoneCallback) => {
(async () => {
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,
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) => {
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));
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
ZeroEx.toBaseUnitAmount(new BigNumber(8), decimals));
done();
});
zeroEx.orderStateWatcher.subscribe(callback);
const shouldThrowOnInsufficientBalanceOrAllowance = true;
await zeroEx.exchange.fillOrderAsync(
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,
);
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
const changedMakerApprovalAmount = new BigNumber(3);
zeroEx.orderStateWatcher.addOrder(signedOrder);
const changedMakerApprovalAmount = ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals);
zeroEx.orderStateWatcher.addOrder(signedOrder);
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
const validOrderState = orderState as OrderStateValid;
const orderRelevantState = validOrderState.orderRelevantState;
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
changedMakerApprovalAmount);
done();
});
zeroEx.orderStateWatcher.subscribe(callback);
await zeroEx.token.setProxyAllowanceAsync(makerToken.address, maker, changedMakerApprovalAmount);
})().catch(done);
});
it('should equal balance amount when balance amount is lowest', (done: DoneCallback) => {
(async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerToken.address, takerToken.address, maker, taker, fillableAmount,
);
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
const validOrderState = orderState as OrderStateValid;
const orderRelevantState = validOrderState.orderRelevantState;
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
changedMakerApprovalAmount);
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
changedMakerApprovalAmount);
done();
});
zeroEx.orderStateWatcher.subscribe(callback);
await zeroEx.token.setProxyAllowanceAsync(makerToken.address, maker, changedMakerApprovalAmount);
})().catch(done);
});
it('should equal balance amount when balance amount is lowest', (done: DoneCallback) => {
(async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerToken.address, takerToken.address, maker, taker, fillableAmount,
);
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
const remainingAmount = new BigNumber(1);
const transferAmount = makerBalance.sub(remainingAmount);
zeroEx.orderStateWatcher.addOrder(signedOrder);
const remainingAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals);
const transferAmount = makerBalance.sub(remainingAmount);
zeroEx.orderStateWatcher.addOrder(signedOrder);
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
const validOrderState = orderState as OrderStateValid;
const orderRelevantState = validOrderState.orderRelevantState;
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
remainingAmount);
done();
});
zeroEx.orderStateWatcher.subscribe(callback);
await zeroEx.token.transferAsync(
makerToken.address, maker, ZeroEx.NULL_ADDRESS, transferAmount);
})().catch(done);
});
const callback = reportCallbackErrors(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);
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
remainingAmount);
done();
});
zeroEx.orderStateWatcher.subscribe(callback);
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) => {
(async () => {
const takerFee = ZeroEx.toBaseUnitAmount(new BigNumber(0), decimals);
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);
const remainingTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(4), decimals);
const transferTokenAmount = makerFee.sub(remainingTokenAmount);
zeroEx.orderStateWatcher.addOrder(signedOrder);
const callback = reportCallbackErrors(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();
});
zeroEx.orderStateWatcher.subscribe(callback);
await zeroEx.exchange.cancelOrderAsync(signedOrder, transferTokenAmount);
})().catch(done);
});
it('should equal ratio amount when fee balance is lowered', (done: DoneCallback) => {
(async () => {
const takerFee = ZeroEx.toBaseUnitAmount(new BigNumber(0), decimals);
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);
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 validOrderState = orderState as OrderStateValid;
const orderRelevantState = validOrderState.orderRelevantState;
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
remainingFeeAmount);
done();
});
zeroEx.orderStateWatcher.subscribe(callback);
await zeroEx.token.setProxyAllowanceAsync(zrxTokenAddress, maker, remainingFeeAmount);
await zeroEx.token.transferAsync(
makerToken.address, maker, ZeroEx.NULL_ADDRESS, transferTokenAmount);
})().catch(done);
});
it('should calculate full amount when all available and non-divisible', (done: DoneCallback) => {
(async () => {
const takerFee = ZeroEx.toBaseUnitAmount(new BigNumber(0), decimals);
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);
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
zeroEx.orderStateWatcher.addOrder(signedOrder);
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
const validOrderState = orderState as OrderStateValid;
const orderRelevantState = validOrderState.orderRelevantState;
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
fillableAmount);
done();
});
zeroEx.orderStateWatcher.subscribe(callback);
await zeroEx.token.setProxyAllowanceAsync(
makerToken.address, maker, ZeroEx.toBaseUnitAmount(new BigNumber(100), decimals));
})().catch(done);
});
});
it('should emit orderStateInvalid when watched order cancelled', (done: DoneCallback) => {
(async () => {
@@ -333,6 +437,28 @@ describe('OrderStateWatcher', () => {
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
})().catch(done);
});
it('should emit orderStateInvalid when within rounding error range', (done: DoneCallback) => {
(async () => {
const remainingFillableAmountInBaseUnits = new BigNumber(100);
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerToken.address, takerToken.address, maker, taker, fillableAmount,
);
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
zeroEx.orderStateWatcher.addOrder(signedOrder);
const callback = reportCallbackErrors(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),
);
})().catch(done);
});
it('should emit orderStateValid when watched order partially cancelled', (done: DoneCallback) => {
(async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
@@ -359,4 +485,4 @@ describe('OrderStateWatcher', () => {
})().catch(done);
});
});
});
}); // tslint:disable:max-file-line-count

View File

@@ -1,16 +1,19 @@
import * as chai from 'chai';
import * as Web3 from 'web3';
import BigNumber from 'bignumber.js';
import * as chai from 'chai';
import * as Sinon from 'sinon';
import {chaiSetup} from './utils/chai_setup';
import {web3Factory} from './utils/web3_factory';
import {ZeroEx, SignedOrder, Token, ExchangeContractErrs, ZeroExError} from '../src';
import {TradeSide, TransferType} from '../src/types';
import {TokenUtils} from './utils/token_utils';
import {BlockchainLifecycle} from './utils/blockchain_lifecycle';
import {FillScenarios} from './utils/fill_scenarios';
import {OrderValidationUtils} from '../src/utils/order_validation_utils';
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 {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';
chaiSetup.configure();
const expect = chai.expect;
@@ -34,10 +37,13 @@ describe('OrderValidation', () => {
let orderValidationUtils: OrderValidationUtils;
const fillableAmount = new BigNumber(5);
const fillTakerAmount = new BigNumber(5);
const config = {
networkId: constants.TESTRPC_NETWORK_ID,
};
before(async () => {
web3 = web3Factory.create();
zeroEx = new ZeroEx(web3.currentProvider);
exchangeContractAddress = await zeroEx.exchange.getContractAddressAsync();
zeroEx = new ZeroEx(web3.currentProvider, config);
exchangeContractAddress = zeroEx.exchange.getContractAddress();
userAddresses = await zeroEx.getAvailableAddressesAsync();
[coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses;
tokens = await zeroEx.tokenRegistry.getTokensAsync();
@@ -110,7 +116,7 @@ describe('OrderValidation', () => {
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
// 27 <--> 28
signedOrder.ecSignature.v = 27 + (28 - signedOrder.ecSignature.v);
signedOrder.ecSignature.v = (28 - signedOrder.ecSignature.v) + 27;
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
signedOrder, fillableAmount, takerAddress,
)).to.be.rejectedWith(ZeroExError.InvalidSignature);
@@ -215,7 +221,7 @@ describe('OrderValidation', () => {
return Sinon.match((value: BigNumber) => value.eq(expected));
};
beforeEach('create exchangeTransferSimulator', async () => {
exchangeTransferSimulator = new ExchangeTransferSimulator(zeroEx.token);
exchangeTransferSimulator = new ExchangeTransferSimulator(zeroEx.token, BlockParamLiteral.Latest);
transferFromAsync = Sinon.spy();
exchangeTransferSimulator.transferFromAsync = transferFromAsync as any;
});
@@ -226,7 +232,7 @@ describe('OrderValidation', () => {
makerTokenAddress, takerTokenAddress, makerFee, takerFee,
makerAddress, takerAddress, fillableAmount, feeRecipient,
);
await orderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
exchangeTransferSimulator, signedOrder, fillableAmount, takerAddress, zrxTokenAddress,
);
expect(transferFromAsync.callCount).to.be.equal(4);
@@ -262,7 +268,7 @@ describe('OrderValidation', () => {
makerTokenAddress, takerTokenAddress, makerFee, takerFee,
makerAddress, ZeroEx.NULL_ADDRESS, fillableAmount, feeRecipient,
);
await orderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
exchangeTransferSimulator, signedOrder, fillableAmount, takerAddress, zrxTokenAddress,
);
expect(transferFromAsync.callCount).to.be.equal(4);
@@ -297,7 +303,7 @@ describe('OrderValidation', () => {
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, makerTokenAmount, takerTokenAmount,
);
await orderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
exchangeTransferSimulator, signedOrder, takerTokenAmount, takerAddress, zrxTokenAddress,
);
expect(transferFromAsync.callCount).to.be.equal(4);
@@ -312,7 +318,7 @@ describe('OrderValidation', () => {
fillableAmount, ZeroEx.NULL_ADDRESS,
);
const fillTakerTokenAmount = fillableAmount.div(2).round(0);
await orderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
exchangeTransferSimulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress,
);
const makerPartialFee = makerFee.div(2);

View File

@@ -0,0 +1,178 @@
import BigNumber from 'bignumber.js';
import * as chai from 'chai';
import 'mocha';
import { ZeroEx } from '../src/0x';
import { RemainingFillableCalculator } from '../src/order_watcher/remaining_fillable_calculator';
import { ECSignature, SignedOrder } from '../src/types';
import { chaiSetup } from './utils/chai_setup';
import { TokenUtils } from './utils/token_utils';
chaiSetup.configure();
const expect = chai.expect;
describe('RemainingFillableCalculator', () => {
let calculator: RemainingFillableCalculator;
let signedOrder: SignedOrder;
let transferrableMakerTokenAmount: BigNumber;
let transferrableMakerFeeTokenAmount: BigNumber;
let remainingMakerTokenAmount: BigNumber;
let makerAmount: BigNumber;
let takerAmount: BigNumber;
let makerFeeAmount: BigNumber;
let isMakerTokenZRX: boolean;
const makerToken: string = '0x1';
const takerToken: string = '0x2';
const decimals: number = 4;
const zero: BigNumber = new BigNumber(0);
const zeroAddress = '0x0';
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)];
[transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount] = [
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 };
}
describe('Maker token is NOT ZRX', () => {
before(async () => {
isMakerTokenZRX = false;
});
it('calculates the correct amount when unfilled and funds available', () => {
signedOrder = buildSignedOrder();
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
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);
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);
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(zero);
});
it('calculates the correct amount when balance is less than remaining fillable', () => {
signedOrder = buildSignedOrder();
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);
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)];
});
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);
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)];
});
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);
const calculatedFillableAmount = calculator.computeRemainingMakerFillable();
expect(calculatedFillableAmount.lessThanOrEqualTo(transferrableMakerTokenAmount)).to.be.true();
expect(calculatedFillableAmount).to.be.bignumber.greaterThan(new BigNumber(0));
const orderToFeeRatio = signedOrder.makerTokenAmount.dividedBy(signedOrder.makerFee);
const calculatedFeeAmount = calculatedFillableAmount.dividedBy(orderToFeeRatio);
expect(calculatedFeeAmount).to.be.bignumber.lessThan(transferrableMakerFeeTokenAmount);
});
});
});
describe('Maker Token is ZRX', () => {
before(async () => {
isMakerTokenZRX = true;
});
it('calculates the correct amount when unfilled and funds available', () => {
signedOrder = buildSignedOrder();
transferrableMakerTokenAmount = makerAmount.plus(makerFeeAmount);
transferrableMakerFeeTokenAmount = transferrableMakerTokenAmount;
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
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);
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
});
it('calculates the amount to be 0 when all fee funds are transferred', () => {
signedOrder = buildSignedOrder();
transferrableMakerTokenAmount = zero;
transferrableMakerFeeTokenAmount = zero;
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
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', () => {
signedOrder = buildSignedOrder();
const partiallyFilledAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
remainingMakerTokenAmount = signedOrder.makerTokenAmount.minus(partiallyFilledAmount);
transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(partiallyFilledAmount);
transferrableMakerFeeTokenAmount = transferrableMakerTokenAmount;
const orderToFeeRatio = signedOrder.makerTokenAmount.dividedToIntegerBy(signedOrder.makerFee);
const expectedFillableAmount = new BigNumber(450980);
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
const calculatedFillableAmount = calculator.computeRemainingMakerFillable();
const numberOfFillsInRatio = calculatedFillableAmount.dividedToIntegerBy(orderToFeeRatio);
const calculatedFillableAmountPlusFees = calculatedFillableAmount.plus(numberOfFillsInRatio);
expect(calculatedFillableAmountPlusFees).to.be.bignumber.lessThan(transferrableMakerTokenAmount);
expect(calculatedFillableAmountPlusFees).to.be.bignumber.lessThan(remainingMakerTokenAmount);
expect(calculatedFillableAmount).to.be.bignumber.equal(expectedFillableAmount);
expect(numberOfFillsInRatio.decimalPlaces()).to.be.equal(0);
});
});
});

View File

@@ -1,23 +1,26 @@
import 'mocha';
import * as _ from 'lodash';
import * as chai from 'chai';
import * as Sinon from 'sinon';
import {chaiSetup} from './utils/chai_setup';
import * as Web3 from 'web3';
import BigNumber from 'bignumber.js';
import promisify = require('es6-promisify');
import {web3Factory} from './utils/web3_factory';
import * as chai from 'chai';
import * as _ from 'lodash';
import 'mocha';
import * as Sinon from 'sinon';
import * as Web3 from 'web3';
import {
ApprovalContractEventArgs,
DecodedLogEvent,
Token,
TokenEvents,
ZeroEx,
ZeroExError,
Token,
ApprovalContractEventArgs,
TokenEvents,
DecodedLogEvent,
} from '../src';
import {BlockParamLiteral, 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 {DoneCallback, BlockParamLiteral} from '../src/types';
import {web3Factory} from './utils/web3_factory';
chaiSetup.configure();
const expect = chai.expect;
@@ -31,9 +34,12 @@ describe('SubscriptionTest', () => {
let tokenUtils: TokenUtils;
let coinbase: string;
let addressWithoutFunds: string;
const config = {
networkId: constants.TESTRPC_NETWORK_ID,
};
before(async () => {
web3 = web3Factory.create();
zeroEx = new ZeroEx(web3.currentProvider);
zeroEx = new ZeroEx(web3.currentProvider, config);
userAddresses = await zeroEx.getAvailableAddressesAsync();
tokens = await zeroEx.tokenRegistry.getTokensAsync();
tokenUtils = new TokenUtils(tokens);
@@ -62,22 +68,44 @@ describe('SubscriptionTest', () => {
_.each(stubs, s => s.restore());
stubs = [];
});
it('Should receive the Error when an error occurs', (done: DoneCallback) => {
it('Should receive the Error when an error occurs while fetching the block', (done: DoneCallback) => {
(async () => {
const callback = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
expect(err).to.not.be.null();
expect(logEvent).to.be.undefined();
done();
};
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('JSON RPC error'),
.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);
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;
@@ -85,11 +113,11 @@ describe('SubscriptionTest', () => {
tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
stubs = [
Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync')
.throws('JSON RPC error'),
.throws(new Error('JSON RPC error')),
];
zeroEx.token.unsubscribeAll();
done();
})().catch(done);
});
});
});
});

View File

@@ -1,11 +1,14 @@
import {schemas, SchemaValidator} from '@0xproject/json-schemas';
import * as chai from 'chai';
import * as _ from 'lodash';
import 'mocha';
import * as chai from 'chai';
import {SchemaValidator, schemas} from '@0xproject/json-schemas';
import {chaiSetup} from './utils/chai_setup';
import {web3Factory} from './utils/web3_factory';
import {ZeroEx, Token} 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';
chaiSetup.configure();
const expect = chai.expect;
@@ -24,9 +27,12 @@ describe('TokenRegistryWrapper', () => {
const registeredName = '0x Protocol Token';
const unregisteredSymbol = 'MAL';
const unregisteredName = 'Malicious Token';
const config = {
networkId: constants.TESTRPC_NETWORK_ID,
};
before(async () => {
const web3 = web3Factory.create();
zeroEx = new ZeroEx(web3.currentProvider);
zeroEx = new ZeroEx(web3.currentProvider, config);
tokens = await zeroEx.tokenRegistry.getTokensAsync();
_.map(tokens, token => {
tokenAddressBySymbol[token.symbol] = token.address;

View File

@@ -1,17 +1,23 @@
import * as chai from 'chai';
import {chaiSetup} from './utils/chai_setup';
import {web3Factory} from './utils/web3_factory';
import {ZeroEx} from '../src';
import {TokenTransferProxyWrapper} from '../src/contract_wrappers/token_transfer_proxy_wrapper';
import {chaiSetup} from './utils/chai_setup';
import {constants} from './utils/constants';
import {web3Factory} from './utils/web3_factory';
chaiSetup.configure();
const expect = chai.expect;
describe('TokenTransferProxyWrapper', () => {
let zeroEx: ZeroEx;
const config = {
networkId: constants.TESTRPC_NETWORK_ID,
};
before(async () => {
const web3 = web3Factory.create();
zeroEx = new ZeroEx(web3.currentProvider);
zeroEx = new ZeroEx(web3.currentProvider, config);
});
describe('#isAuthorizedAsync', () => {
it('should return false if the address is not authorized', async () => {

View File

@@ -1,27 +1,31 @@
import 'mocha';
import * as chai from 'chai';
import {chaiSetup} from './utils/chai_setup';
import * as Web3 from 'web3';
import {promisify} from '@0xproject/utils';
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import BigNumber from 'bignumber.js';
import promisify = require('es6-promisify');
import {web3Factory} from './utils/web3_factory';
import * as chai from 'chai';
import 'mocha';
import * as Web3 from 'web3';
import {
ApprovalContractEventArgs,
ContractEvent,
DecodedLogEvent,
LogEvent,
LogWithDecodedArgs,
SubscriptionOpts,
Token,
TokenContractEventArgs,
TokenEvents,
TransferContractEventArgs,
ZeroEx,
ZeroExError,
Token,
SubscriptionOpts,
TokenEvents,
ContractEvent,
TransferContractEventArgs,
ApprovalContractEventArgs,
TokenContractEventArgs,
LogWithDecodedArgs,
LogEvent,
DecodedLogEvent,
} from '../src';
import {BlockParamLiteral, 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 {DoneCallback, BlockParamLiteral} from '../src/types';
import {web3Factory} from './utils/web3_factory';
chaiSetup.configure();
const expect = chai.expect;
@@ -35,9 +39,14 @@ describe('TokenWrapper', () => {
let tokenUtils: TokenUtils;
let coinbase: string;
let addressWithoutFunds: string;
let web3Wrapper: Web3Wrapper;
const config = {
networkId: constants.TESTRPC_NETWORK_ID,
};
before(async () => {
web3 = web3Factory.create();
zeroEx = new ZeroEx(web3.currentProvider);
zeroEx = new ZeroEx(web3.currentProvider, config);
web3Wrapper = new Web3Wrapper(web3.currentProvider);
userAddresses = await zeroEx.getAvailableAddressesAsync();
tokens = await zeroEx.tokenRegistry.getTokensAsync();
tokenUtils = new TokenUtils(tokens);
@@ -80,7 +89,7 @@ describe('TokenWrapper', () => {
const toAddress = coinbase;
return expect(zeroEx.token.transferAsync(
nonExistentTokenAddress, fromAddress, toAddress, transferAmount,
)).to.be.rejectedWith(ZeroExError.ContractDoesNotExist);
)).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
});
});
describe('#transferFromAsync', () => {
@@ -153,7 +162,7 @@ describe('TokenWrapper', () => {
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
return expect(zeroEx.token.transferFromAsync(
nonExistentTokenAddress, fromAddress, toAddress, senderAddress, new BigNumber(42),
)).to.be.rejectedWith(ZeroExError.ContractDoesNotExist);
)).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
});
});
describe('#getBalanceAsync', () => {
@@ -169,7 +178,7 @@ describe('TokenWrapper', () => {
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
const ownerAddress = coinbase;
return expect(zeroEx.token.getBalanceAsync(nonExistentTokenAddress, ownerAddress))
.to.be.rejectedWith(ZeroExError.ContractDoesNotExist);
.to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
});
it('should return a balance of 0 for a non-existent owner address', async () => {
const token = tokens[0];
@@ -184,7 +193,7 @@ describe('TokenWrapper', () => {
before(async () => {
const hasAddresses = false;
const web3WithoutAccounts = web3Factory.create(hasAddresses);
zeroExWithoutAccounts = new ZeroEx(web3WithoutAccounts.currentProvider);
zeroExWithoutAccounts = new ZeroEx(web3WithoutAccounts.currentProvider, config);
});
it('should return balance even when called with Web3 provider instance without addresses', async () => {
const token = tokens[0];
@@ -231,8 +240,10 @@ describe('TokenWrapper', () => {
await zeroEx.token.setAllowanceAsync(zrx.address, coinbase, userWithNormalAllowance, transferAmount);
await zeroEx.token.setUnlimitedAllowanceAsync(zrx.address, coinbase, userWithUnlimitedAllowance);
const initBalanceWithNormalAllowance = await promisify(web3.eth.getBalance)(userWithNormalAllowance);
const initBalanceWithUnlimitedAllowance = await promisify(web3.eth.getBalance)(userWithUnlimitedAllowance);
const initBalanceWithNormalAllowance = await web3Wrapper.getBalanceInWeiAsync(userWithNormalAllowance);
const initBalanceWithUnlimitedAllowance = await web3Wrapper.getBalanceInWeiAsync(
userWithUnlimitedAllowance,
);
await zeroEx.token.transferFromAsync(
zrx.address, coinbase, userWithNormalAllowance, userWithNormalAllowance, transferAmount,
@@ -241,8 +252,10 @@ describe('TokenWrapper', () => {
zrx.address, coinbase, userWithUnlimitedAllowance, userWithUnlimitedAllowance, transferAmount,
);
const finalBalanceWithNormalAllowance = await promisify(web3.eth.getBalance)(userWithNormalAllowance);
const finalBalanceWithUnlimitedAllowance = await promisify(web3.eth.getBalance)(userWithUnlimitedAllowance);
const finalBalanceWithNormalAllowance = await web3Wrapper.getBalanceInWeiAsync(userWithNormalAllowance);
const finalBalanceWithUnlimitedAllowance = await web3Wrapper.getBalanceInWeiAsync(
userWithUnlimitedAllowance,
);
const normalGasCost = initBalanceWithNormalAllowance.minus(finalBalanceWithNormalAllowance);
const unlimitedGasCost = initBalanceWithUnlimitedAllowance.minus(finalBalanceWithUnlimitedAllowance);
@@ -281,7 +294,7 @@ describe('TokenWrapper', () => {
before(async () => {
const hasAddresses = false;
const web3WithoutAccounts = web3Factory.create(hasAddresses);
zeroExWithoutAccounts = new ZeroEx(web3WithoutAccounts.currentProvider);
zeroExWithoutAccounts = new ZeroEx(web3WithoutAccounts.currentProvider, config);
});
it('should get the proxy allowance', async () => {
const token = tokens[0];
@@ -361,7 +374,11 @@ describe('TokenWrapper', () => {
(async () => {
const callback = (err: Error, logEvent: DecodedLogEvent<TransferContractEventArgs>) => {
expect(logEvent).to.not.be.undefined();
const args = logEvent.args;
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);
@@ -376,7 +393,8 @@ describe('TokenWrapper', () => {
(async () => {
const callback = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
expect(logEvent).to.not.be.undefined();
const args = logEvent.args;
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);
@@ -387,7 +405,7 @@ describe('TokenWrapper', () => {
await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount);
})().catch(done);
});
it('Outstanding subscriptions are cancelled when zeroEx.setProviderAsync called', (done: DoneCallback) => {
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'));
@@ -399,7 +417,7 @@ describe('TokenWrapper', () => {
done();
};
const newProvider = web3Factory.getRpcProvider();
await zeroEx.setProviderAsync(newProvider);
zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID);
zeroEx.token.subscribe(
tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackToBeCalled,
);
@@ -423,14 +441,14 @@ describe('TokenWrapper', () => {
let tokenAddress: string;
let tokenTransferProxyAddress: string;
const subscriptionOpts: SubscriptionOpts = {
fromBlock: BlockParamLiteral.Earliest,
fromBlock: 0,
toBlock: BlockParamLiteral.Latest,
};
let txHash: string;
before(async () => {
before(() => {
const token = tokens[0];
tokenAddress = token.address;
tokenTransferProxyAddress = await zeroEx.proxy.getContractAddressAsync();
tokenTransferProxyAddress = zeroEx.proxy.getContractAddress();
});
it('should get logs with decoded args emitted by Approval', async () => {
txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase);

View File

@@ -1,7 +1,7 @@
import * as chai from 'chai';
import * as dirtyChai from 'dirty-chai';
import ChaiBigNumber = require('chai-bignumber');
import chaiAsPromised = require('chai-as-promised');
import ChaiBigNumber = require('chai-bignumber');
import * as dirtyChai from 'dirty-chai';
export const chaiSetup = {
configure() {

View File

@@ -2,7 +2,11 @@ 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',
ZRX_DECIMALS: 18,
GAS_ESTIMATE: 500000,
};

View File

@@ -1,6 +1,8 @@
import BigNumber from 'bignumber.js';
import {ZeroEx, Token, SignedOrder} from '../../src';
import {SignedOrder, Token, ZeroEx} from '../../src';
import {orderFactory} from '../utils/order_factory';
import {constants} from './constants';
export class FillScenarios {

View File

@@ -1,6 +1,7 @@
import * as _ from 'lodash';
import BigNumber from 'bignumber.js';
import {ZeroEx, SignedOrder} from '../../src';
import * as _ from 'lodash';
import {SignedOrder, ZeroEx} from '../../src';
export const orderFactory = {
async createSignedOrderAsync(
@@ -15,11 +16,11 @@ export const orderFactory = {
takerTokenAddress: string,
exchangeContractAddress: string,
feeRecipient: string,
expirationUnixTimestampSec?: BigNumber): Promise<SignedOrder> {
expirationUnixTimestampSecIfExists?: BigNumber): Promise<SignedOrder> {
const defaultExpirationUnixTimestampSec = new BigNumber(2524604400); // Close to infinite
expirationUnixTimestampSec = _.isUndefined(expirationUnixTimestampSec) ?
const expirationUnixTimestampSec = _.isUndefined(expirationUnixTimestampSecIfExists) ?
defaultExpirationUnixTimestampSec :
expirationUnixTimestampSec;
expirationUnixTimestampSecIfExists;
const order = {
maker,
taker,

View File

@@ -2,7 +2,7 @@ import { DoneCallback } from '../../src/types';
export const reportCallbackErrors = (done: DoneCallback) => {
return (f: (...args: any[]) => void) => {
const wrapped = (...args: any[]) => {
const wrapped = async (...args: any[]) => {
try {
f(...args);
} catch (err) {

View File

@@ -1,5 +1,6 @@
import * as ethUtil from 'ethereumjs-util';
import * as request from 'request-promise-native';
import {constants} from './constants';
export class RPC {

View File

@@ -1,11 +1,13 @@
import {JSONRPCPayload} from '../types';
import {JSONRPCPayload} from '../../../src/types';
/*
* This class implements the web3-provider-engine subprovider interface and returns
* that the provider has no addresses when queried.
* Source: https://github.com/MetaMask/provider-engine/blob/master/subproviders/subprovider.js
*/
export class EmptyWalletSubProvider {
export class EmptyWalletSubprovider {
// This method needs to be here to satisfy the interface but linter wants it to be static.
// tslint:disable-next-line:prefer-function-over-method
public handleRequest(payload: JSONRPCPayload, next: () => void, end: (err: Error|null, result: any) => void) {
switch (payload.method) {
case 'eth_accounts':
@@ -18,6 +20,7 @@ export class EmptyWalletSubProvider {
}
}
// Required to implement this method despite not needing it for this subprovider
// tslint:disable-next-line:prefer-function-over-method
public setEngine(engine: any) {
// noop
}

View File

@@ -0,0 +1,34 @@
import {JSONRPCPayload} from '../../../src/types';
/*
* This class implements the web3-provider-engine subprovider interface and returns
* the constant gas estimate when queried.
* HACK: We need this so that our tests don't use testrpc gas estimation which sometimes kills the node.
* Source: https://github.com/trufflesuite/ganache-cli/issues/417
* Source: https://github.com/trufflesuite/ganache-cli/issues/437
* Source: https://github.com/MetaMask/provider-engine/blob/master/subproviders/subprovider.js
*/
export class FakeGasEstimateSubprovider {
private constantGasAmount: number;
constructor(constantGasAmount: number) {
this.constantGasAmount = constantGasAmount;
}
// This method needs to be here to satisfy the interface but linter wants it to be static.
// tslint:disable-next-line:prefer-function-over-method
public handleRequest(payload: JSONRPCPayload, next: () => void, end: (err: Error|null, result: any) => void) {
switch (payload.method) {
case 'eth_estimateGas':
end(null, this.constantGasAmount);
return;
default:
next();
return;
}
}
// Required to implement this method despite not needing it for this subprovider
// tslint:disable-next-line:prefer-function-over-method
public setEngine(engine: any) {
// noop
}
}

View File

@@ -1,5 +1,6 @@
import * as _ from 'lodash';
import {Token, InternalZeroExError} from '../../src/types';
import {InternalZeroExError, Token} from '../../src/types';
const PROTOCOL_TOKEN_SYMBOL = 'ZRX';

View File

@@ -3,11 +3,14 @@
// we are not running in a browser env.
// Filed issue: https://github.com/ethereum/web3.js/issues/844
(global as any).XMLHttpRequest = undefined;
import * as Web3 from 'web3';
import ProviderEngine = require('web3-provider-engine');
import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
import * as Web3 from 'web3';
import {EmptyWalletSubprovider} from './subproviders/empty_wallet_subprovider';
import {FakeGasEstimateSubprovider} from './subproviders/fake_gas_estimate_subprovider';
import {constants} from './constants';
import {EmptyWalletSubProvider} from '../../src/subproviders/empty_wallet_subprovider';
export const web3Factory = {
create(hasAddresses: boolean = true): Web3 {
@@ -20,8 +23,9 @@ export const web3Factory = {
const provider = new ProviderEngine();
const rpcUrl = `http://${constants.RPC_HOST}:${constants.RPC_PORT}`;
if (!hasAddresses) {
provider.addProvider(new EmptyWalletSubProvider());
provider.addProvider(new EmptyWalletSubprovider());
}
provider.addProvider(new FakeGasEstimateSubprovider(constants.GAS_ESTIMATE));
provider.addProvider(new RpcSubprovider({
rpcUrl,
}));

View File

@@ -1,29 +0,0 @@
import * as chai from 'chai';
import {web3Factory} from './utils/web3_factory';
import {ZeroEx} from '../src/';
import {Web3Wrapper} from '../src/web3_wrapper';
import {constants} from './utils/constants';
chai.config.includeStack = true;
const expect = chai.expect;
describe('Web3Wrapper', () => {
const web3Provider = web3Factory.create().currentProvider;
describe('#getNetworkIdIfExistsAsync', () => {
it('caches network id requests', async () => {
const web3Wrapper = (new ZeroEx(web3Provider) as any)._web3Wrapper as Web3Wrapper;
expect((web3Wrapper as any).networkIdIfExists).to.be.undefined();
const networkIdIfExists = await web3Wrapper.getNetworkIdIfExistsAsync();
expect((web3Wrapper as any).networkIdIfExists).to.be.equal(constants.TESTRPC_NETWORK_ID);
});
it('invalidates network id cache on setProvider call', async () => {
const web3Wrapper = (new ZeroEx(web3Provider) as any)._web3Wrapper as Web3Wrapper;
expect((web3Wrapper as any).networkIdIfExists).to.be.undefined();
const networkIdIfExists = await web3Wrapper.getNetworkIdIfExistsAsync();
expect((web3Wrapper as any).networkIdIfExists).to.be.equal(constants.TESTRPC_NETWORK_ID);
const newProvider = web3Factory.create().currentProvider;
web3Wrapper.setProvider(newProvider);
expect((web3Wrapper as any).networkIdIfExists).to.be.undefined();
});
});
});

View File

@@ -0,0 +1,27 @@
/**
* 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 {{contractName}}Contract extends BaseContract {
{{#each methods}}
{{#this.constant}}
{{> call contractName=../contractName}}
{{/this.constant}}
{{^this.constant}}
{{> tx contractName=../contractName}}
{{/this.constant}}
{{/each}}
constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) {
super(web3ContractInstance, defaults);
classUtils.bindAll(this, ['web3ContractInstance', 'defaults']);
}
} // tslint:disable:max-file-line-count

View File

@@ -0,0 +1,15 @@
{
"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,15 @@
public {{this.name}} = {
async callAsync(
{{> typed_params inputs=inputs}}
defaultBlock?: Web3.BlockParam,
): Promise<{{> return_type outputs=outputs}}> {
const self = this as {{contractName}}Contract;
const result = await promisify<{{> return_type outputs=outputs}}>(
self.web3ContractInstance.{{this.name}}.call,
self.web3ContractInstance,
)(
{{> params inputs=inputs}}
);
return result;
},
};

View File

@@ -0,0 +1,3 @@
{{#each inputs}}
{{name}},
{{/each}}

View File

@@ -0,0 +1,6 @@
{{#singleReturnValue}}
{{#returnType outputs.0.type}}{{/returnType}}
{{/singleReturnValue}}
{{^singleReturnValue}}
[{{#each outputs}}{{#returnType type}}{{/returnType}}{{#unless @last}}, {{/unless}}{{/each}}]
{{/singleReturnValue}}

View File

@@ -0,0 +1,51 @@
public {{this.name}} = {
async sendTransactionAsync(
{{> typed_params inputs=inputs}}
{{#this.payable}}
txData: TxDataPayable = {},
{{/this.payable}}
{{^this.payable}}
txData: TxData = {},
{{/this.payable}}
): Promise<string> {
const self = this as {{contractName}}Contract;
const txDataWithDefaults = await self.applyDefaultsToTxDataAsync(
txData,
self.{{this.name}}.estimateGasAsync.bind(
self,
{{> params inputs=inputs}}
),
);
const txHash = await promisify<string>(
self.web3ContractInstance.{{this.name}}, self.web3ContractInstance,
)(
{{> params inputs=inputs}}
txDataWithDefaults,
);
return txHash;
},
async estimateGasAsync(
{{> typed_params inputs=inputs}}
txData: TxData = {},
): Promise<number> {
const self = this as {{contractName}}Contract;
const txDataWithDefaults = await self.applyDefaultsToTxDataAsync(
txData,
);
const gas = await promisify<number>(
self.web3ContractInstance.{{this.name}}.estimateGas, self.web3ContractInstance,
)(
{{> params inputs=inputs}}
txDataWithDefaults,
);
return gas;
},
getABIEncodedTransactionData(
{{> typed_params inputs=inputs}}
txData: TxData = {},
): string {
const self = this as {{contractName}}Contract;
const abiEncodedTransactionData = self.web3ContractInstance.{{this.name}}.getData();
return abiEncodedTransactionData;
},
};

View File

@@ -0,0 +1,3 @@
{{#each inputs}}
{{name}}: {{#parameterType type}}{{/parameterType}},
{{/each}}

View File

@@ -0,0 +1,39 @@
# ABI Gen
This package allows you to generate TypeScript contract wrappers from ABI files.
It's heavily inspired by [Geth abigen](https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts) but takes a different approach.
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.
## Instalation
`yarn add -g @0xproject/abi-gen`
## Usage
```
abi-gen
Options:
--help Show help [boolean]
--version Show version number [boolean]
--abiGlob Glob pattern to search for ABI JSON files [string] [required]
--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.
TL;DR - here is the example from 0x.js.
`--abiGlob 'src/artifacts/@(Exchange|Token|TokenTransferProxy|EtherToken|TokenRegistry).json`
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.
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

@@ -0,0 +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"
}
}

4
packages/abi-gen/src/globals.d.ts vendored Normal file
View File

@@ -0,0 +1,4 @@
declare function toSnakeCase(str: string): string;
declare module 'to-snake-case' {
export = toSnakeCase;
}

View File

@@ -0,0 +1,98 @@
#!/usr/bin/env node
import chalk from 'chalk';
import * as fs from 'fs';
import {sync as globSync} from 'glob';
import * as Handlebars from 'handlebars';
import * as _ from 'lodash';
import * as mkdirp from 'mkdirp';
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';
const ABI_TYPE_METHOD = 'function';
const MAIN_TEMPLATE_NAME = 'contract.mustache';
const args = yargs
.option('abiGlob', {
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,
})
.option('output', {
describe: 'Folder where to put the output files',
type: 'string',
demand: true,
})
.argv;
function writeOutputFile(name: string, renderedTsCode: string): void {
const fileName = toSnakeCase(name);
const filePath = `${args.output}/${fileName}.ts`;
fs.writeFileSync(filePath, renderedTsCode);
utils.log(`Created: ${chalk.bold(filePath)}`);
}
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}`);
const template = Handlebars.compile<ContextData>(mainTemplate.content);
const abiFileNames = globSync(args.abiGlob);
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
${chalk.bold('*.json')} extensions`);
process.exit(1);
} else {
utils.log(`Found ${chalk.green(`${abiFileNames.length}`)} ${chalk.bold('ABI')} files`);
mkdirp.sync(args.output);
}
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
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);
}
const methodAbis = ABI.filter((abi: Web3.AbiDefinition) => abi.type === ABI_TYPE_METHOD) as Web3.MethodAbi[];
const methodsData = _.map(methodAbis, methodAbi => {
_.map(methodAbi.inputs, input => {
if (_.isEmpty(input.name)) {
// Auto-generated getters don't have parameter names
input.name = 'index';
}
});
// This will make templates simpler
const methodData = {
...methodAbi,
singleReturnValue: methodAbi.outputs.length === 1,
};
return methodData;
});
const contextData = {
contractName: namedContent.name,
methods: methodsData,
};
const renderedTsCode = template(contextData);
writeOutputFile(namedContent.name, renderedTsCode);
}

View File

@@ -0,0 +1,15 @@
import * as Web3 from 'web3';
export enum ParamKind {
Input = 'input',
Output = 'output',
}
export interface Method extends Web3.MethodAbi {
singleReturnValue: boolean;
}
export interface ContextData {
contractName: string;
methods: Method[];
}

View File

@@ -0,0 +1,56 @@
import * as fs from 'fs';
import * as _ from 'lodash';
import * as path from 'path';
import {ParamKind} from './types';
export const utils = {
solTypeToTsType(paramKind: ParamKind, solType: string): string {
const trailingArrayRegex = /\[\d*\]$/;
if (solType.match(trailingArrayRegex)) {
const arrayItemSolType = solType.replace(trailingArrayRegex, '');
const arrayItemTsType = utils.solTypeToTsType(paramKind, arrayItemSolType);
const arrayTsType = `${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'},
];
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'});
}
for (const regexAndTxType of solTypeRegexToTsType) {
const {regex, tsType} = regexAndTxType;
if (solType.match(regex)) {
return tsType;
}
}
throw new Error(`Unknown Solidity type found: ${solType}`);
}
},
log(...args: any[]): void {
console.log(...args); // tslint:disable-line:no-console
},
getPartialNameFromFileName(filename: string): string {
const name = path.parse(filename).name;
return name;
},
getNamedContent(filename: string): {name: string; content: string} {
const name = utils.getPartialNameFromFileName(filename);
try {
const content = fs.readFileSync(filename).toString();
return {
name,
content,
};
} catch (err) {
throw new Error(`Failed to read ${filename}: ${err}`);
}
},
};

View File

@@ -0,0 +1,17 @@
{
"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"
]
}

View File

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

View File

@@ -0,0 +1,6 @@
# CHANGELOG
v0.0.4 - _Nov. 14, 2017_
------------------------
* Re-publish Assert previously published under NPM package @0xproject/0x-assert
* Added assertion isValidBaseUnitAmount which checks both that the value is a valid bigNumber and that it does not contain decimals.

View File

@@ -1 +1,10 @@
assert
------
Standard type and schema assertions to be used across all 0x projects and packages
## Install
```bash
npm install @0xproject/assert --save
```

View File

@@ -1,13 +1,13 @@
{
"name": "@0xproject/assert",
"version": "0.0.4",
"version": "0.0.7",
"description": "Provides a standard way of performing type and schema validation across 0x projects",
"main": "lib/src/index.js",
"types": "lib/src/index.d.ts",
"scripts": {
"build": "tsc",
"clean": "shx rm -rf _bundles lib test_temp",
"lint": "tslint src/**/*.ts test/**/*.ts",
"lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'",
"run_mocha": "mocha lib/test/**/*_test.js",
"prepublishOnly": "run-p build",
"test": "run-s clean build run_mocha",
@@ -23,21 +23,21 @@
},
"homepage": "https://github.com/0xProject/0x.js/packages/assert/README.md",
"devDependencies": {
"@0xproject/tslint-config": "^0.1.0",
"@types/lodash": "^4.14.78",
"@0xproject/tslint-config": "^0.2.1",
"@types/lodash": "^4.14.86",
"@types/mocha": "^2.2.42",
"@types/valid-url": "^1.0.2",
"chai": "^4.0.1",
"chai-typescript-typings": "^0.0.1",
"dirty-chai": "^2.0.1",
"mocha": "^4.0.1",
"npm-run-all": "^4.1.1",
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"tslint": "5.8.0",
"typescript": "^2.4.2"
"typescript": "~2.6.1"
},
"dependencies": {
"@0xproject/json-schemas": "^0.6.7",
"@0xproject/json-schemas": "^0.6.10",
"bignumber.js": "~4.1.0",
"ethereum-address": "^0.0.4",
"lodash": "^4.17.4",

View File

@@ -0,0 +1,14 @@
const postpublish_utils = require('../../../scripts/postpublish_utils');
const packageJSON = require('../package.json');
const subPackageName = packageJSON.name;
postpublish_utils.getLatestTagAndVersionAsync(subPackageName)
.then(function(result) {
const releaseName = postpublish_utils.getReleaseName(subPackageName, result.version);
const assets = [];
return postpublish_utils.publishReleaseNotes(result.tag, releaseName, assets);
})
.catch (function(err) {
throw err;
});

View File

@@ -1,11 +1,11 @@
import {
Schema,
SchemaValidator,
} from '@0xproject/json-schemas';
import BigNumber from 'bignumber.js';
import * as ethereum_address from 'ethereum-address';
import * as _ from 'lodash';
import * as validUrl from 'valid-url';
import {
SchemaValidator,
Schema,
} from '@0xproject/json-schemas';
const HEX_REGEX = /^0x[0-9A-F]*$/i;
@@ -62,7 +62,7 @@ export const assert = {
this.assert(_.isBoolean(value), this.typeAssertionMessage(variableName, 'boolean', value));
},
isWeb3Provider(variableName: string, value: any): void {
const isWeb3Provider = _.isFunction((value as any).send) || _.isFunction((value as any).sendAsync);
const isWeb3Provider = _.isFunction((value).send) || _.isFunction((value).sendAsync);
this.assert(isWeb3Provider, this.typeAssertionMessage(variableName, 'Web3.Provider', value));
},
doesConformToSchema(variableName: string, value: any, schema: Schema): void {

View File

@@ -1,8 +1,9 @@
import 'mocha';
import * as dirtyChai from 'dirty-chai';
import * as chai from 'chai';
import {BigNumber} from 'bignumber.js';
import {schemas} from '@0xproject/json-schemas';
import {BigNumber} from 'bignumber.js';
import * as chai from 'chai';
import * as dirtyChai from 'dirty-chai';
import 'mocha';
import {assert} from '../src/index';
chai.config.includeStack = true;
@@ -183,7 +184,7 @@ describe('Assertions', () => {
it('should not throw for valid input', () => {
const validInputs = [
42,
0.00,
0,
21e+42,
];
validInputs.forEach(input => expect(assert.isNumber.bind(assert, variableName, input)).to.not.throw());

View File

@@ -0,0 +1,16 @@
# CHANGELOG
v0.3.0 - _December 8, 2017_
------------------------
* Expose WebSocketOrderbookChannel and associated types to public interface (#251)
* Remove tokenA and tokenB fields from OrdersRequest (#256)
v0.2.0 - _November 29, 2017_
------------------------
* Add SignedOrder and TokenTradeInfo to the public interface
* Add ECSignature and Order to the public interface
* Remove dependency on 0x.js
v0.1.0 - _November 22, 2017_
------------------------
* Provide a HttpClient class for interacting with standard relayer api compliant HTTP urls

View File

@@ -0,0 +1 @@
This repository contains a Javascript library that makes it easy to interact with Relayers that conform to the [Standard Relayer API](https://github.com/0xProject/standard-relayer-api)

View File

@@ -0,0 +1,69 @@
{
"name": "@0xproject/connect",
"version": "0.3.0",
"description": "A javascript library for interacting with the standard relayer api",
"keywords": [
"connect",
"0xproject",
"ethereum",
"tokens",
"exchange"
],
"main": "lib/src/index.js",
"types": "lib/src/index.d.ts",
"scripts": {
"build": "tsc",
"clean": "shx rm -rf _bundles lib test_temp",
"docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_DIR",
"upload_docs_json": "aws s3 cp generated_docs/index.json $S3_URL --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type application/json",
"copy_test_fixtures": "copyfiles -u 2 './test/fixtures/**/*.json' ./lib/test/fixtures",
"lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'",
"run_mocha": "mocha lib/test/**/*_test.js",
"test": "run-s clean build copy_test_fixtures run_mocha",
"test:circleci": "yarn test"
},
"repository": {
"type": "git",
"url": "https://github.com/0xProject/0x.js.git"
},
"author": "Brandon Millman",
"license": "Apache-2.0",
"engines": {
"node": ">=6.0.0"
},
"bugs": {
"url": "https://github.com/0xProject/0x.js/issues"
},
"homepage": "https://github.com/0xProject/0x.js/packages/connect/README.md",
"dependencies": {
"@0xproject/assert": "^0.0.7",
"@0xproject/json-schemas": "^0.6.10",
"bignumber.js": "~4.1.0",
"isomorphic-fetch": "^2.2.1",
"lodash": "^4.17.4",
"query-string": "^5.0.1",
"websocket": "^1.0.25"
},
"devDependencies": {
"@0xproject/tslint-config": "^0.2.1",
"@types/fetch-mock": "^5.12.1",
"@types/lodash": "^4.14.86",
"@types/mocha": "^2.2.42",
"@types/query-string": "^5.0.1",
"@types/websocket": "^0.0.34",
"chai": "^4.0.1",
"chai-as-promised": "^7.1.0",
"chai-as-promised-typescript-typings": "^0.0.3",
"chai-typescript-typings": "^0.0.1",
"copyfiles": "^1.2.0",
"dirty-chai": "^2.0.1",
"fetch-mock": "^5.13.1",
"mocha": "^4.0.1",
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"tslint": "5.8.0",
"typedoc": "~0.8.0",
"typescript": "~2.6.1",
"web3-typescript-typings": "^0.7.2"
}
}

View File

@@ -0,0 +1,40 @@
const execAsync = require('async-child-process').execAsync;
const postpublish_utils = require('../../../scripts/postpublish_utils');
const packageJSON = require('../package.json');
const cwd = __dirname + '/..';
const subPackageName = packageJSON.name;
const S3BucketPath = 's3://connect-docs-jsons/';
let tag;
let version;
postpublish_utils.getLatestTagAndVersionAsync(subPackageName)
.then(function(result) {
tag = result.tag;
version = result.version;
const releaseName = postpublish_utils.getReleaseName(subPackageName, version);
return postpublish_utils.publishReleaseNotes(tag, releaseName);
})
.then(function(release) {
console.log('POSTPUBLISH: Release successful, generating docs...');
const jsonFilePath = __dirname + '/../' + postpublish_utils.generatedDocsDirectoryName + '/index.json';
return execAsync(
'JSON_FILE_PATH=' + jsonFilePath + ' PROJECT_DIR=' + __dirname + '/.. yarn docs:json',
{
cwd,
}
);
})
.then(function(result) {
if (result.stderr !== '') {
throw new Error(result.stderr);
}
const fileName = 'v' + version + '.json';
console.log('POSTPUBLISH: Doc generation successful, uploading docs... as ', fileName);
const s3Url = S3BucketPath + fileName;
return execAsync('S3_URL=' + s3Url + ' yarn upload_docs_json', {
cwd,
});
}).catch (function(err) {
throw err;
});

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