Compare commits

..

1764 Commits

Author SHA1 Message Date
Fabio Berger
f684cc3711 Publish
- 0x.js@0.29.0
 - @0xproject/abi-gen@0.0.4
 - @0xproject/assert@0.0.9
 - @0xproject/connect@0.3.2
 - contracts@2.1.1
 - @0xproject/dev-utils@0.0.3
 - @0xproject/json-schemas@0.7.1
 - @0xproject/kovan_faucets@1.0.2
 - @0xproject/monorepo-scripts@0.1.2
 - @0xproject/subproviders@0.2.0
 - @0xproject/tslint-config@0.4.0
 - @0xproject/types@0.1.2
 - @0xproject/utils@0.1.2
 - @0xproject/web3-wrapper@0.1.2
 - @0xproject/website@0.0.4
2017-12-28 10:57:04 +01:00
Fabio Berger
ab0c8c3496 Add dates to CHANGELOG entries 2017-12-28 10:36:06 +01:00
Fabio Berger
47534b200d Update subproviders CHANGELOG 2017-12-28 10:29:52 +01:00
Fabio Berger
f2976af734 Support both personal_sign and eth_sign 2017-12-28 10:28:27 +01:00
Fabio Berger
ee463058f1 Fix Ledger tests given change from personal_sign to eth_sign 2017-12-28 09:46:50 +01:00
Fabio Berger
c36a7471a8 Merge pull request #300 from cavanmflynn/fix/ledger-subprovider-signing
Update subprovider to catch correct RPC method
2017-12-28 09:45:41 +01:00
Cavan Flynn
6ea8cee551 Update subprovider to catch correct RPC method
ZeroEx uses web3.eth.sign, rather than web3.eth.personal.sign. In addition, the message to sign is the second parameter; not the first. The first parameter is the address.
2017-12-27 19:48:58 -05:00
Fabio Berger
69806c8839 Rename guide 2017-12-25 17:54:24 +01:00
Fabio Berger
690036aa30 Update contribution guide 2017-12-25 17:53:18 +01:00
Brandon Millman
eda6b8d01b Fix broken links in the abi-gen README 2017-12-24 19:46:45 -05:00
Brandon Millman
cbf06b2165 Merge pull request #289 from 0xProject/fix/missingBigNumberConfigs
Add missing calls to bigNumberConfigs in packages where we are instan…
2017-12-21 21:04:50 -05:00
Fabio Berger
e884eb9882 Merge pull request #288 from 0xProject/fix/docLinks
Fix doc anchor link collisions
2017-12-21 22:45:22 +01:00
Brandon Millman
f8cbfea4a1 Remove unused import 2017-12-21 15:40:09 -05:00
Fabio Berger
e01c0f054d Merge branch 'development' into fix/docLinks
* development:
  Update and standardize contracts README
  Add to CHANGELOG
  Refactor toBaseUnitAmount so that it throws if user supplies unitAmount with too many decimals
  Make assertion stricter so that one cannot submit invalid baseUnit amounts to `toUnitAmount`
  Add some missed underscores, update changelog and comments
  Add new underscore-privates rule to @0xproject/tslint-config and fix lint errors

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

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

# Conflicts:
#	packages/website/ts/components/eth_weth_conversion_button.tsx
2017-12-19 11:04:25 +01:00
Fabio Berger
2930537a51 Add WETH 2017-12-19 10:41:52 +01:00
Fabio Berger
16c91bca0a remove extra space 2017-12-19 10:41:45 +01:00
Fabio Berger
1f85d31663 Remove binding on prop passed callbacks 2017-12-19 10:39:25 +01:00
Fabio Berger
684542d073 Add airtable tasks to TODO's 2017-12-19 10:36:54 +01:00
Fabio Berger
bab01abe27 Merge branch 'development' into createWethPage
* development:
  Add additional public changes introduced to changelog
  Update CHANGELOG
  Add a comment
  Introduce a variable for true
  Remove redundant template string
  Implement the address derivations
  Add hdnode dependency
  Move web3 import after subprovider imports in test web3_factory
  Fixed https://github.com/0xProject/wiki/issues/19 by disabling re-rendering of markdownCodeBlock renderer if props haven't updated
  Add convenience `rebuild` command
  Update website calls to deposit/withdraw
  Add entry to CHANGELOG
2017-12-19 10:28:11 +01:00
Fabio Berger
c63f76dde7 Merge pull request #268 from 0xProject/fix/codeSelectingInDocs
Fix code selection bug in docs
2017-12-19 10:23:35 +01:00
Fabio Berger
79bd416c61 Merge pull request #267 from 0xProject/refactor/passInEtherTokenAddress
Refactor EtherToken wrapper to accept address in method args
2017-12-19 10:23:07 +01:00
Fabio Berger
7710989dee Add additional public changes introduced to changelog 2017-12-18 22:04:12 +01:00
Fabio Berger
fb0b7efc45 Refactor configs and constants, standardize on uppercase/snakecase, alphebetize, rename for logical grouping 2017-12-18 19:30:25 +01:00
Brandon Millman
1af427e4a7 Merge pull request #269 from 0xProject/fix/brokenCi
Move web3 import after subprovider imports in test web3_factory
2017-12-18 10:41:15 -05:00
Leonid
bb6d594ec7 Merge pull request #271 from 0xProject/fix/ledger-derivation
Implement ledger optimization for address derivation
2017-12-18 16:09:22 +01:00
Leonid Logvinov
a57dda2c2a Update CHANGELOG 2017-12-18 15:57:40 +01:00
Leonid Logvinov
a3a2df098b Add a comment 2017-12-18 15:56:31 +01:00
Leonid Logvinov
90d1c3e2c9 Introduce a variable for true 2017-12-18 14:49:13 +01:00
Leonid Logvinov
950406f1f9 Remove redundant template string 2017-12-18 14:47:39 +01:00
Leonid Logvinov
064405126d Implement the address derivations 2017-12-18 12:30:34 +01:00
Leonid Logvinov
6d447fd8a5 Add hdnode dependency 2017-12-18 12:30:14 +01:00
Fabio Berger
400228e139 Sort colors into color spectrum 2017-12-18 10:44:55 +01:00
Fabio Berger
edfae32484 remove unused style 2017-12-18 10:44:41 +01:00
Fabio Berger
1aed970ce3 standarize on grey over gray spelling and other color related fixes 2017-12-18 10:28:34 +01:00
Fabio Berger
445ff1e28e Standardize colors to always be in uppercase hex and consolidate material-ui greys 2017-12-18 10:06:16 +01:00
Fabio Berger
df9d3e3e16 Consolidate all custom colors and material-ui colors into a colors module 2017-12-18 09:15:12 +01:00
Brandon Millman
4dc6694651 Move web3 import after subprovider imports in test web3_factory 2017-12-17 23:30:14 -05:00
Fabio Berger
98c01c2f80 Remove unused location prop 2017-12-17 20:57:39 -05:00
Fabio Berger
f698dd4077 Use bigNumberConfigs from @0xproject/utils in website repo 2017-12-17 20:55:50 -05:00
Fabio Berger
0578116f1d Fix unhoverable help tooltip by renaming Trade Permissions to Allowance 2017-12-17 20:51:54 -05:00
Fabio Berger
abbad68eb8 Replace remaining strEnums with property TS string enums 2017-12-17 20:48:23 -05:00
Fabio Berger
90d274ffc4 Update ActionType enum and move from using _.assign in reducer 2017-12-17 20:06:49 -05:00
Fabio Berger
449fd9f024 Remove unused enums 2017-12-17 19:38:59 -05:00
Fabio Berger
22c4ee6ef7 Update first two string enums to native type 2017-12-17 19:35:24 -05:00
Fabio Berger
951fbc9b76 Temporarily pretend as if new WETH contracts are already whitelisted by tokenRegistry and put hacks behind the shouldDeprecateOldWethToken flag 2017-12-17 19:18:33 -05:00
Fabio Berger
89f368a8b8 Add notice dialog to balances page about updating the WETH contract. We also draw attention to the new dedicated section for unwrapping from outdated WETH tokens 2017-12-17 18:58:12 -05:00
Fabio Berger
672c8acaca Fix linter errors 2017-12-17 17:21:33 -05:00
Fabio Berger
681617480a Move weth.io url to constants 2017-12-17 17:10:51 -05:00
Fabio Berger
95dfac6f9b Make it such that Wrapped Ether page works on networks without any outdated WETH tokens 2017-12-17 17:09:16 -05:00
Fabio Berger
b2256679be Add Max convenience button in unwrap WETH dialog 2017-12-17 15:41:24 -05:00
Fabio Berger
9e914be975 Link all EtherTokens to Etherscan and add address tooltip 2017-12-17 14:14:23 -06:00
Fabio Berger
edbe6915e0 Fixed https://github.com/0xProject/wiki/issues/19 by disabling re-rendering of markdownCodeBlock renderer if props haven't updated 2017-12-17 13:22:54 -06:00
Fabio Berger
fd3e8cd813 Add convenience rebuild command 2017-12-17 13:20:27 -06:00
Fabio Berger
b640e2cc49 Update website calls to deposit/withdraw 2017-12-17 12:40:04 -06:00
Fabio Berger
51af6de624 Update to passing etherTokenAddress into withdraw and deposit calls 2017-12-17 12:36:50 -06:00
Fabio Berger
054c00e323 Add entry to CHANGELOG 2017-12-17 01:07:28 -06:00
Fabio Berger
5664333490 Since sending the error report could take some time, we first trigger onError so that the user gets notified immediately 2017-12-17 00:44:34 -06:00
Fabio Berger
ac78c64f9e Fix tests in contracts 2017-12-17 00:40:19 -06:00
Fabio Berger
1f748afed9 Modify the etherToken wrapper methods to accept an etherTokenAddress as the first arg. Since it is becoming apparent we will be updating the canonical WETH contract, we want users of 0x.js to be able to interact with n number of etherTokens without re-instantiating for each one. 2017-12-17 00:32:53 -06:00
Fabio Berger
4a73c05435 Fix documentation issue where unsubscribeAll shown as method on every contractWrapper instance even though it's only used by Exchange and Token wrappers. 2017-12-17 00:19:15 -06:00
Fabio Berger
fe8f2d87c7 Temporary hack to alleviate issues with updating tokenRegistry with new WETH address 2017-12-15 14:07:14 -06:00
Fabio Berger
a71a1edf2c Two mysteriously missing imports 2017-12-15 13:01:45 -06:00
Fabio Berger
87209b8f57 Merge pull request #264 from 0xProject/createWethPage
Create WETH Page
2017-12-15 12:58:22 -06:00
Fabio Berger
13279f1f20 Fix linter errors 2017-12-15 12:47:16 -06:00
Fabio Berger
b46dd2e0a2 Merge branch 'development' into createWethPage
* development: (54 commits)
  Fix redundant spaces
  Fix tests
  Fix website unused vars
  Fix connect unused vars
  Fix 0x.js unused vars
  Dissallow unused vars/imports
  Implement first custom linter rule async-suffix
  Reuse intervalutils in website
  Add a newline
  Name a variable
  Add a comment
  Fix a conditional
  Make migrations deterministic
  Fix linter error
  Fix linter errors
  Add a function to init token balances
  Rename tokenUtils.getNonProtocolTokens to tokenUtils.getDummyTokens
  Add DummyToken to gitignore
  Add DummyToken to artifacts list
  Increase mocha timeout
  ...
2017-12-15 12:37:03 -06:00
Leonid
3eb08735d4 Merge pull request #266 from 0xProject/fix/no-unused-vars
Remove all unused vars and imports
2017-12-15 19:03:01 +01:00
Leonid Logvinov
c8e52882ca Fix redundant spaces 2017-12-15 18:44:13 +01:00
Fabio Berger
484dd4c33a Update name to be a call to action 2017-12-15 11:06:18 -06:00
Fabio Berger
94f40a54b4 Add default value for onConversionSuccessful 2017-12-15 11:05:53 -06:00
Leonid Logvinov
818a50a3fb Fix tests 2017-12-15 15:32:10 +01:00
Leonid Logvinov
2041e9945e Fix website unused vars 2017-12-15 15:19:19 +01:00
Leonid Logvinov
126048bac9 Fix connect unused vars 2017-12-15 13:58:30 +01:00
Leonid Logvinov
274aa50d74 Fix 0x.js unused vars 2017-12-15 13:30:19 +01:00
Leonid Logvinov
c36d85a46c Dissallow unused vars/imports 2017-12-15 13:14:44 +01:00
Fabio Berger
ac1fbeb962 Improve WETH page styling 2017-12-14 19:28:49 -06:00
Leonid
de8c445f96 Merge pull request #265 from 0xProject/feature/custom-linter-rule
Implement first custom linter rule async-suffix
2017-12-14 22:34:54 +01:00
Leonid Logvinov
c23d42fea5 Implement first custom linter rule async-suffix 2017-12-14 21:49:19 +01:00
Leonid
a0aa21103b Merge pull request #258 from 0xProject/feature/contracts-refactor
A bunch of refactorings
2017-12-14 17:48:45 +01:00
Leonid Logvinov
ce242b10e2 Reuse intervalutils in website 2017-12-14 17:43:42 +01:00
Fabio Berger
6d386220d9 Use new wrap/unwrap buttons, fetch outdated WETH balances and re-fetch after a successful unwrap. 2017-12-14 10:43:20 -06:00
Fabio Berger
7ce1021798 Refactor the WETH conversion dialog/button to be either wrap or unwrap specific and not both 2017-12-14 10:41:33 -06:00
Leonid Logvinov
9ad9e1204c Add a newline 2017-12-14 17:15:49 +01:00
Leonid Logvinov
a63061f5b2 Name a variable 2017-12-14 17:15:07 +01:00
Leonid Logvinov
4997331410 Add a comment 2017-12-14 17:13:34 +01:00
Leonid Logvinov
f7f4b6da8d Fix a conditional 2017-12-14 17:12:18 +01:00
Leonid Logvinov
c975676f6c Make migrations deterministic 2017-12-14 16:40:37 +01:00
Leonid Logvinov
d702c65a5b Fix linter error 2017-12-14 15:59:00 +01:00
Leonid Logvinov
4391f9913e Fix linter errors 2017-12-14 15:47:03 +01:00
Leonid Logvinov
28c409fc6d Add a function to init token balances 2017-12-14 15:47:03 +01:00
Leonid Logvinov
449a04d39c Rename tokenUtils.getNonProtocolTokens to tokenUtils.getDummyTokens 2017-12-14 15:47:03 +01:00
Leonid Logvinov
4bcd7ba31e Add DummyToken to gitignore 2017-12-14 15:47:03 +01:00
Leonid Logvinov
5bda301fec Add DummyToken to artifacts list 2017-12-14 15:47:03 +01:00
Leonid Logvinov
84c7c6eb12 Increase mocha timeout 2017-12-14 15:47:03 +01:00
Leonid Logvinov
a5b7980b06 Add DummyToken to artifacts list 2017-12-14 15:47:03 +01:00
Leonid Logvinov
f746f5bfa3 Update addresses and add DummyToken artifact 2017-12-14 15:47:03 +01:00
Leonid Logvinov
3ed2eedfda Change circle commit hash to the newest one from the monorepo 2017-12-14 15:47:03 +01:00
Leonid Logvinov
4ce8eaa158 Fix CI build 2017-12-14 15:47:02 +01:00
Leonid Logvinov
7abb026819 Delete abi-gen-templates 2017-12-14 15:47:02 +01:00
Leonid Logvinov
abd55411d4 Move shared types to types package 2017-12-14 15:47:02 +01:00
Leonid Logvinov
cb596c1413 Move more shared utils into utils package and reuse them 2017-12-14 15:47:02 +01:00
Leonid Logvinov
6120a43fff Create dev-utils with blockchainLifecycle in it 2017-12-14 15:47:02 +01:00
Leonid Logvinov
02e7354b53 Move 0x.js temnplates to 0x.js instead of having them as a separate package 2017-12-14 15:47:02 +01:00
Leonid Logvinov
0a0d3503c0 Remove generated contracts and ignore them. Add a prebuild command to regenerate them 2017-12-14 15:47:02 +01:00
Fabio Berger
105bcc6664 Clear trackedTokens so that a user starts tracking the new WETH and no longer the old one 2017-12-13 19:58:33 -06:00
Fabio Berger
ceae51fe32 Make label optional and make sure the input field still renders properly without it 2017-12-13 19:46:48 -06:00
Fabio Berger
b054080fa1 Remove ETH-WETH convert button from balances page 2017-12-13 19:45:44 -06:00
Fabio Berger
565010408e Remove temporary hack 2017-12-13 19:44:27 -06:00
Fabio Berger
5619780cc1 Use boxed ETH 2017-12-13 19:43:43 -06:00
Brandon Millman
d69143487e Reorganize packages section of readme 2017-12-13 15:37:47 -08:00
Brandon Millman
2ef763a195 Merge pull request #229 from 0xProject/feature/addKovanFaucets
Add kovan faucet project into the mono repo
2017-12-13 15:09:39 -08:00
Brandon Millman
6ba4ed99c4 Fix hanging requests by importing web3 last 2017-12-13 15:05:57 -08:00
Brandon Millman
aec3c83191 Add kovan faucet to main README 2017-12-13 12:39:52 -08:00
Brandon Millman
19d8449981 Merge branch 'development' into feature/addKovanFaucets
* development:
  Add new packages to main README
  Remove redundant totalSupply from token interface
2017-12-13 12:37:01 -08:00
Brandon Millman
91f276d925 Cleanup kovan-faucet package 2017-12-13 12:36:29 -08:00
Leonid Logvinov
6bda6a22e3 Add new packages to main README 2017-12-13 16:05:48 +01:00
Amir Bandeali
1fbe638950 Remove redundant totalSupply from token interface 2017-12-12 16:07:04 -08:00
Brandon Millman
1e9f23ebba Fix build errors 2017-12-12 15:56:30 -08:00
Brandon Millman
bbb768c5cf Add kovan faucet project into the mono repo 2017-12-12 15:45:22 -08:00
Amir Bandeali
5678196706 Merge pull request #255 from 0xProject/feature/updateWeth
Update WETH
2017-12-12 15:39:29 -08:00
Amir Bandeali
987637abed Increase timeout on deployer tests 2017-12-12 15:11:57 -08:00
Amir Bandeali
ff422ecfb2 Add version string to EtherToken_v2 2017-12-12 15:05:31 -08:00
Amir Bandeali
1fb643cb69 Formatting fixes 2017-12-12 15:05:30 -08:00
Amir Bandeali
88db8c3724 Add missing package in utils, fix linting error 2017-12-12 15:05:30 -08:00
Amir Bandeali
cf50a82ecc fix tests after merging with development 2017-12-12 15:05:30 -08:00
Amir Bandeali
145fea5253 Add test:circleci command, add newlines to end of contracts 2017-12-12 15:05:30 -08:00
Amir Bandeali
b97f140b78 Add gas limits to failing tests 2017-12-12 15:05:30 -08:00
Amir Bandeali
1dda4d5f78 Rename contracts lib to utils 2017-12-12 15:05:29 -08:00
Amir Bandeali
6f2cb66163 Refactor unlimited allowance logic out of ERC20Token 2017-12-12 15:05:29 -08:00
Amir Bandeali
8b29f6f18d Fix typo, change variable name to be consistent 2017-12-12 15:05:28 -08:00
Amir Bandeali
2cc410e61f Update 0x.js version, fix build errors 2017-12-12 15:05:27 -08:00
Amir Bandeali
548fda8dba Add updated contracts, reorganize contract file structure 2017-12-12 15:02:05 -08:00
Amir Bandeali
b58bf8259d Add tests for ERC20Token and EtherToken_v2 2017-12-12 15:02:05 -08:00
Amir Bandeali
e6862e9739 Fix errors with new testrpc version 2017-12-12 15:02:04 -08:00
Amir Bandeali
7008e882c0 Add version to new EtherToken, fix typos 2017-12-12 15:02:04 -08:00
Amir Bandeali
7d59faa650 Add updated ERC20 implementation, update WETH 2017-12-12 15:02:04 -08:00
Fabio Berger
eaa6484f24 Merge branch 'development' into createWethPage
* development:
  update yarn.lock
  Fix typedoc_utils to take into account subPackageName when rendering call path
  Add WebSocketOrderbookChannel to connect docs
2017-12-12 15:40:23 -06:00
Fabio Berger
6630b1d8a5 update yarn.lock 2017-12-12 15:27:07 -06:00
Fabio Berger
d0916e196c progress weth page 2017-12-12 14:53:39 -06:00
Brandon Millman
8e74a22c6f Merge pull request #263 from 0xProject/fix/docsCallPath
Fix typedoc_utils to take into account subPackageName when rendering …
2017-12-12 12:52:35 -08:00
Brandon Millman
2ffcc853fd Fix typedoc_utils to take into account subPackageName when rendering call path 2017-12-12 10:23:51 -08:00
Brandon Millman
caeb5cb6ab Merge pull request #261 from 0xProject/feature/addWebSocketDocs
Add WebSocketOrderbookChannel to connect docs
2017-12-12 10:23:17 -08:00
Fabio Berger
4f72c527de Merge branch 'development' of github.com:0xProject/0x.js into development
* 'development' of github.com:0xProject/0x.js:
  Re-hard code the dependency
  Add missing dependency
  Add missing dependency
  Fix a dependency
  Fix an invocation
  Move dependency
  Merge dependencies
  Don't unsubscribe on error. It's done automatically
  Rename blockAndLogStreamer to blockAndLogStreamerIfExists
  Move isAddress to shared utils and remove all dependencies on ethereum-address
  Remove ethereum-address dependency and add this logic to the repo
2017-12-12 11:38:13 -06:00
Fabio Berger
71cb2e05d1 Resize token icons 2017-12-12 11:36:57 -06:00
Brandon Millman
d1fb61e0de Add WebSocketOrderbookChannel to connect docs 2017-12-12 15:37:55 +01:00
Leonid
cb7188d473 Merge pull request #257 from 0xProject/fix/ethereum-address
Remove ethereum-address dependency and add this logic to the repo
2017-12-12 15:30:04 +01:00
Leonid
02f22d9155 Merge pull request #262 from 0xProject/fix/portal-bug
Fix portal subscriptions bug
2017-12-12 15:27:35 +01:00
Leonid Logvinov
707b98849c Re-hard code the dependency 2017-12-12 15:25:06 +01:00
Leonid Logvinov
d778378b37 Add missing dependency 2017-12-12 15:14:54 +01:00
Leonid Logvinov
f3f596b231 Add missing dependency 2017-12-12 15:06:38 +01:00
Leonid Logvinov
276ee9903a Fix a dependency 2017-12-12 14:01:58 +01:00
Leonid Logvinov
16a970b65d Fix an invocation 2017-12-12 13:56:19 +01:00
Leonid Logvinov
1647e45247 Move dependency 2017-12-12 13:55:34 +01:00
Leonid Logvinov
3477a84bbd Merge dependencies 2017-12-12 13:54:17 +01:00
Leonid Logvinov
c61fe3ce64 Don't unsubscribe on error. It's done automatically 2017-12-12 13:33:12 +01:00
Leonid Logvinov
f94dc1fe44 Rename blockAndLogStreamer to blockAndLogStreamerIfExists 2017-12-12 13:32:54 +01:00
Brandon Millman
1339aadf4e Merge pull request #259 from 0xProject/fix/addChangelogAndPostpublishScripts
Fix broken postpublish_utils, add CHANGELOG and postpublish.js script…
2017-12-11 13:10:43 -08:00
Leonid Logvinov
a14424ae5f Move isAddress to shared utils and remove all dependencies on ethereum-address 2017-12-11 12:43:19 +01:00
Leonid Logvinov
f1e7ea118b Remove ethereum-address dependency and add this logic to the repo 2017-12-11 12:21:44 +01:00
Brandon Millman
9c6453e129 Fix broken postpublish_utils, add CHANGELOG and postpublish.js scripts to all packages 2017-12-08 15:01:52 -08:00
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
Fabio Berger
79df9ef8e6 Publish
- @0xproject/0x.js@0.24.0
 - @0xproject/assert@0.0.4
 - @0xproject/json-schemas@0.6.7
 - @0xproject/tslint-config@0.1.0
2017-11-14 15:43:59 -05:00
Fabio Berger
3b52686125 Remove private flag because we need it published to npm 2017-11-14 15:43:32 -05:00
Fabio Berger
af7c03212d Revert version 2017-11-14 15:38:24 -05:00
Fabio Berger
bdeedb6c91 Update package name and version in package.json 2017-11-14 15:00:40 -05:00
Brandon Millman
4d61d56639 Merge pull request #221 from 0xProject/feature/addJsonSchemas
Add json-schemas package to mono repo
2017-11-14 13:02:17 -05:00
Fabio Berger
430154d543 Update CHANGELOG 2017-11-14 12:57:34 -05:00
Brandon Millman
bb6631c7c6 Update tslint rules for assert and json-schemas 2017-11-14 12:56:22 -05:00
Brandon Millman
9bb5e6f5ce Merge branch 'development' into feature/addJsonSchemas
* development:
  Improve description
  Alphabetize
  Add exit 0 to 0x.js build command
  Add snapshot save and revert to order_state_watcher_test.ts
  Fix changelog
  Use tslint v5.8.0 everywhere and use the tslint-config sub-package instead of the old repo as a dep. in the rest of the sub-packages.
  Add tslint-config sub-package
  Fix tslint issue
  Public interface has changed, moved to minor version
  Update changelog
  Renamed canceled to cancelled
2017-11-14 12:29:46 -05:00
Fabio Berger
05de07496f Merge pull request #220 from 0xProject/feature/addTsLintPackage
Add TSLint Config package
2017-11-14 12:25:44 -05:00
Fabio Berger
ab9dc66b8f Improve description 2017-11-14 12:25:29 -05:00
Fabio Berger
f98042a7f8 Alphabetize 2017-11-14 12:25:20 -05:00
Brandon Millman
247b4686fa Add exit 0 to 0x.js build command 2017-11-14 12:14:08 -05:00
Brandon Millman
c78cb27175 Add snapshot save and revert to order_state_watcher_test.ts 2017-11-14 11:58:35 -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
Brandon Millman
56b5619d24 Add json-schemas package to mono repo 2017-11-14 09:42:50 -05:00
Fabio Berger
bc61b92070 Fix changelog 2017-11-13 21:31:40 -05:00
Fabio Berger
682fbd3b76 Merge pull request #217 from dekz/fixCancelledNaming2
Standardise on Cancelled over canceled
2017-11-13 21:12:31 -05:00
Fabio Berger
574ea453b0 Use tslint v5.8.0 everywhere and use the tslint-config sub-package instead of the old repo as a dep. in the rest of the sub-packages. 2017-11-13 21:08:23 -05:00
Fabio Berger
2b806455a5 Add tslint-config sub-package 2017-11-13 20:57:26 -05:00
Fabio Berger
49898525af Fix tslint issue 2017-11-13 20:56:01 -05:00
Leonid Logvinov
24493a4556 Fix tests 2017-11-13 20:32:39 -05:00
Jacob Evans
8de64c9495 Public interface has changed, moved to minor version 2017-11-13 19:25:50 -05:00
Leonid Logvinov
02bbcf6b0e Add a test for rounding error 2017-11-13 18:57:38 -05:00
Fabio Berger
08963f269b Merge pull request #218 from 0xProject/bmillman_add_assert
Add assert sub-package
2017-11-13 18:50:49 -05:00
Fabio Berger
2d0fd14d3c remove new line 2017-11-13 18:50:09 -05:00
Fabio Berger
a15f78652f Update urls 2017-11-13 18:50:00 -05:00
Fabio Berger
3d62312657 Missing @ 2017-11-13 18:45:30 -05:00
Fabio Berger
9b083eebd7 Remove unused circle.yml 2017-11-13 18:42:14 -05:00
Fabio Berger
c7e57a4124 Move conditional running of umd test to 0x.js's package.json 2017-11-13 18:42:02 -05:00
Fabio Berger
ee1a44ebeb Add preliminary instructions to top-level README 2017-11-13 18:20:20 -05:00
Fabio Berger
5b70383ce6 remove image from sub-readme 2017-11-13 18:20:04 -05:00
Fabio Berger
abb2ad45ce fix orderings 2017-11-13 18:12:01 -05:00
Fabio Berger
087ea1f068 Standardize around a test:circleci command that any sub-package can implement in order to have their tests run on CircleCi 2017-11-13 18:11:31 -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
Fabio Berger
4354d3f121 Rename back 2017-11-13 17:57:02 -05:00
Fabio Berger
3e8e3478a3 Rename assert sub-package and removed duplicate methods from 0x.js's assert module 2017-11-13 17:42:42 -05:00
Fabio Berger
cf29530dd0 fix merge 2017-11-13 17:14:07 -05:00
Brandon Millman
b0f13c17e2 Add assert package to the monorepo 2017-11-13 17:11:39 -05:00
Brandon Millman
1147cb56ba Add assert package to the monorepo 2017-11-13 17:07:33 -05:00
Jacob Evans
e29c3e4c70 Update changelog 2017-11-13 16:39:33 -05:00
Jacob Evans
b1b473d3cb Renamed canceled to cancelled 2017-11-13 16:35:37 -05:00
Fabio Berger
c088d9ddd9 Re-add changelog for 0x.js 2017-11-13 16:28:36 -05:00
Fabio Berger
2b26981e3d Merge pull request #215 from 0xProject/monoRepo
Mono repo Final Steps
2017-11-13 13:05:06 -05:00
Fabio Berger
f3e4576625 Upgrade to Typescript 2.6.1 and fix major & minor versions 2017-11-13 13:03:53 -05:00
Fabio Berger
5dae2b8d2b Don't remove files before UMD test run 2017-11-13 13:03:31 -05:00
Fabio Berger
62da364e5d Only run umd tests on development 2017-11-13 13:02:44 -05:00
Fabio Berger
58a318b754 Merge pull request #214 from 0xProject/monoRepo
Switch over to Lerna + Yarn Workspaces setup for a mono-repo approach
2017-11-13 12:52:08 -05:00
Fabio Berger
ff07f49002 Remove unused var 2017-11-13 12:47:54 -05:00
Fabio Berger
8d69d8553c Add interface type 2017-11-13 12:43:22 -05:00
Fabio Berger
a072954176 Replace _.get for type safety 2017-11-13 12:39:36 -05:00
Fabio Berger
23de8185c6 Declare as string 2017-11-13 12:39:20 -05:00
Fabio Berger
d9c80e9b6a Merge branch 'monoRepo' of github.com:0xProject/0x.js into monoRepo
* 'monoRepo' of github.com:0xProject/0x.js:
  Fail the tests on tsc error
2017-11-13 12:31:34 -05:00
Fabio Berger
dcc4272c4e move tslint.json to 0x.js sub-package 2017-11-13 12:31:29 -05:00
Fabio Berger
2060940ecc Fix lint and ts issues 2017-11-13 12:30:01 -05:00
Leonid Logvinov
14274ef67b Fail the tests on tsc error 2017-11-13 12:27:20 -05:00
Fabio Berger
70661c179f point to top-level node_modules 2017-11-13 12:21:25 -05:00
Fabio Berger
8a0ae68f27 remove unnecessary -- 2017-11-13 12:20:58 -05:00
Fabio Berger
06ada87370 Add missing key 2017-11-13 12:14:01 -05:00
Fabio Berger
a5d9b71eb6 Simply lerna command and run bootstrap to install dependencies 2017-11-13 12:13:11 -05:00
Fabio Berger
aa3385d516 Fix lerna command 2017-11-13 12:02:37 -05:00
Fabio Berger
af60b41c89 Fix package.json 2017-11-13 11:59:31 -05:00
Fabio Berger
506bf45272 Add checkout 2017-11-13 11:57:22 -05:00
Fabio Berger
2655daa2f4 Merge branch 'monoRepo' of github.com:0xProject/0x.js into monoRepo
* 'monoRepo' of github.com:0xProject/0x.js:
  Fix package.json
2017-11-13 11:54:29 -05:00
Fabio Berger
0b095ce5ce Upgrade circleci to version 2.0 2017-11-13 11:54:19 -05:00
Leonid Logvinov
ae461b77f8 Fix package.json 2017-11-13 11:26:39 -05:00
Fabio Berger
4f3b9dc61a leave out yarn version peg 2017-11-13 11:22:31 -05:00
Fabio Berger
a246702511 Use lerna 2017-11-13 11:20:07 -05:00
Fabio Berger
2ae47d64b7 use yarn instead of lerna 2017-11-13 11:09:56 -05:00
Fabio Berger
6a76349730 Install older version of yarn 2017-11-13 11:09:46 -05:00
Fabio Berger
e6482554f5 Add circle.yml and move testrpc command to top-level repo 2017-11-13 10:56:22 -05:00
Fabio Berger
c4ee2d7386 Switch over to Lerna + Yarn Workspaces setup for a mono-repo approach 2017-11-12 22:17:18 -05:00
Fabio Berger
a74ec0effa Merge pull request #200 from 0xProject/feature/receipt-status
Normalize the way we return the transaction status
2017-11-12 21:24:00 -05:00
Fabio Berger
e33027c624 Merge branch 'development' into feature/receipt-status
* development: (164 commits)
  Remove old tests
  Remove unused code
  Fix tests
  Remove redundant spaces
  Don't store empty objects
  Fix a typo
  Remove duplicate operations
  Remove redundant instance variables
  Fix tests
  Remove blockStore and default to numConfirmations === 0
  Add a comment
  Store number of confirmations in a blockStore
  Remove tautology check
  Pass blockStore to eventWatcher
  Fix last merge conflicts
  Clear cache on unsubscribe
  Clear store cache on events
  Add more configs for order watcher
  Make subscribe function async and make blockStore operational
  Adjust tests to new interface
  ...

# Conflicts:
#	package.json
#	src/types.ts
#	yarn.lock
2017-11-12 21:12:37 -05:00
Fabio Berger
b0be323e89 Merge pull request #205 from 0xProject/orderWatcher
Order watcher
2017-11-12 20:50:42 -05:00
Fabio Berger
a22661670f Merge branch 'orderWatcher' of github.com:0xProject/0x.js into orderWatcher
* 'orderWatcher' of github.com:0xProject/0x.js: (33 commits)
  Remove old tests
  Remove unused code
  Fix tests
  Remove redundant spaces
  Don't store empty objects
  Fix a typo
  Remove duplicate operations
  Remove redundant instance variables
  Fix tests
  Remove blockStore and default to numConfirmations === 0
  Add a comment
  Store number of confirmations in a blockStore
  Remove tautology check
  Pass blockStore to eventWatcher
  Fix last merge conflicts
  Clear cache on unsubscribe
  Clear store cache on events
  Add more configs for order watcher
  Make subscribe function async and make blockStore operational
  Adjust tests to new interface
  ...
2017-11-12 20:49:56 -05:00
Fabio Berger
442f35a1fd Merge branch 'development' into orderWatcher
* development:
  0.23.0
  Update CHANGELOG
  Fix amounts in tests one last time. Now that we updated the testRPC snapshot, this should no longer be mismatched between CI and locally
  Update testRPC snapshot used by CircleCi
  Push unsubscribe to the base class rather than super
  Check for null rather than undefined
  Removed nits
  Test case was error then unsubscribe
  Clean up subscription state.
  Fix unhandled promise rejection error on subscriptions

# Conflicts:
#	src/types.ts
#	test/exchange_wrapper_test.ts
#	test/token_wrapper_test.ts
2017-11-12 20:49:48 -05:00
Fabio Berger
5aef16c2aa Merge pull request #211 from 0xProject/feature/orderWatcherLocalStateStore
Order watcher local state store
2017-11-12 20:26:21 -05:00
Leonid Logvinov
e512e38efb Remove old tests 2017-11-12 20:21:24 -05:00
Leonid Logvinov
7ea0b138bc Remove unused code 2017-11-12 20:06:14 -05:00
Leonid Logvinov
d73fb5a23c Fix tests 2017-11-12 20:06:14 -05:00
Leonid Logvinov
610298a25d Remove redundant spaces 2017-11-12 20:06:14 -05:00
Leonid Logvinov
7b50a6490d Don't store empty objects 2017-11-12 20:06:14 -05:00
Leonid Logvinov
fdb82d5dd4 Fix a typo 2017-11-12 20:06:13 -05:00
Leonid Logvinov
a587697883 Remove duplicate operations 2017-11-12 20:06:13 -05:00
Leonid Logvinov
3204c077d1 Remove redundant instance variables 2017-11-12 20:06:13 -05:00
Leonid Logvinov
d52825a5b1 Fix tests 2017-11-12 20:06:13 -05:00
Leonid Logvinov
84c965d459 Remove blockStore and default to numConfirmations === 0 2017-11-12 20:06:13 -05:00
Leonid Logvinov
22cd6989a0 Add a comment 2017-11-12 20:06:13 -05:00
Leonid Logvinov
a9ae555b88 Store number of confirmations in a blockStore 2017-11-12 20:06:13 -05:00
Leonid Logvinov
d4dc428124 Remove tautology check 2017-11-12 20:06:13 -05:00
Leonid Logvinov
f5608d2c94 Pass blockStore to eventWatcher 2017-11-12 20:06:13 -05:00
Leonid Logvinov
bcad937003 Fix last merge conflicts 2017-11-12 20:06:13 -05:00
Leonid Logvinov
53c918cc78 Clear cache on unsubscribe 2017-11-12 20:06:13 -05:00
Leonid Logvinov
009f81fe4f Clear store cache on events 2017-11-12 20:06:13 -05:00
Leonid Logvinov
81ce4a0229 Add more configs for order watcher 2017-11-12 20:06:13 -05:00
Leonid Logvinov
6bcd9adb9e Make subscribe function async and make blockStore operational 2017-11-12 20:06:13 -05:00
Leonid Logvinov
61e7b735dc Adjust tests to new interface 2017-11-12 20:06:13 -05:00
Leonid Logvinov
44c15fc1ef Add more errors 2017-11-12 20:06:12 -05:00
Leonid Logvinov
9d3fe1258a Create stores in orderStateWatcher 2017-11-12 20:06:12 -05:00
Leonid Logvinov
e72ba39c41 Make orderStateUtils operate on stores 2017-11-12 20:05:46 -05:00
Leonid Logvinov
ffcc487763 Create fake blockStore for exchange transfer simulator 2017-11-12 20:03:18 -05:00
Leonid Logvinov
473ce8b617 Add initial incomplete BlockStore implementation 2017-11-12 20:03:18 -05:00
Leonid Logvinov
70436fa535 Make stores accept numConfirmations and blockStore instead of defaultBlock 2017-11-12 20:03:18 -05:00
Leonid Logvinov
4921f61e76 Add LatestBlockNumberNotSet internal error 2017-11-12 20:03:18 -05:00
Leonid Logvinov
75b390cf93 Add functions to clear stores cache 2017-11-12 20:03:18 -05:00
Leonid Logvinov
dcda8fe538 Add store for order filled/cancelled state 2017-11-12 20:03:18 -05:00
Leonid Logvinov
6edae86516 Make store configurable by blockParam 2017-11-12 20:03:18 -05:00
Leonid Logvinov
f163e6d8cc Fix tests 2017-11-12 20:03:18 -05:00
Leonid Logvinov
742660591f Make a store an instance variable of exchange transfer simulator and stop inheriting it 2017-11-12 20:03:18 -05:00
Leonid Logvinov
ddbcf5f470 Refactor out BalanceAndProxyAllowanceLazyStore 2017-11-12 20:03:17 -05:00
Fabio Berger
6becf22a2f Merge pull request #210 from dekz/orderWatcherRemaining
Calculate the remaining order amount in maker units
2017-11-12 19:39:24 -05:00
Jacob Evans
32246fd26b remove comments 2017-11-12 19:37:03 -05:00
Jacob Evans
42e3ab91a7 Perform the division after multiplication to reduce compounding the rounding errors 2017-11-12 19:17:27 -05:00
Fabio Berger
6daf70b745 Merge pull request #207 from 0xProject/orderWatcherTests
Additional order watcher tests
2017-11-12 18:11:45 -05:00
Fabio Berger
12298ea392 Don't return anything 2017-11-12 18:11:30 -05:00
Jacob Evans
5e77e8809a Update comment 2017-11-12 17:30:57 -05:00
Jacob Evans
1b3f84c9ad text description update 2017-11-12 17:28:34 -05:00
Jacob Evans
e06539e76d remove only 2017-11-12 17:25:42 -05:00
Jacob Evans
fdb3fa6801 Added specs for allowance and balance changes 2017-11-12 17:24:31 -05:00
Brandon Millman
1392a855bb 0.23.0 2017-11-12 17:01:58 -05:00
Brandon Millman
d4cab6e62f Update CHANGELOG 2017-11-12 17:01:43 -05:00
Leonid Logvinov
5d2b6585c6 Fix tslint issue 2017-11-12 15:19:10 -05:00
Leonid Logvinov
a2f89347a9 Fix tests 2017-11-12 15:05:06 -05:00
Leonid Logvinov
50ee23ebfa Normalize the way we return the transaction status 2017-11-12 15:05:06 -05:00
Brandon Millman
719c51f61a Merge pull request #209 from 0xProject/fixUnhandledPromiseBug
Fix unhandled promise rejection error on subscriptions
2017-11-12 14:06:39 -05:00
Jacob Evans
3e2a614eb9 Calculate the remaining order amount in maker units 2017-11-12 11:28:01 -05:00
Fabio Berger
abb23631df Update testRPC snapshot used by CircleCi 2017-11-12 10:53:29 -05:00
Fabio Berger
dae5a063cf Fix amounts in tests one last time. Now that we updated the testRPC snapshot, this should no longer be mismatched between CI and locally 2017-11-12 10:43:24 -05:00
Fabio Berger
e57a507ba0 Update testRPC snapshot used by CircleCi 2017-11-12 10:39:09 -05:00
Fabio Berger
4e194d7766 Merge pull request #208 from dekz/fixUnhandledPromiseBug
Clean up subscription state.
2017-11-12 09:40:47 -05:00
Jacob Evans
d34ea79d93 Push unsubscribe to the base class rather than super 2017-11-11 13:42:42 -05:00
Jacob Evans
ee73659f16 Check for null rather than undefined 2017-11-11 12:33:05 -05:00
Jacob Evans
394417ff07 Removed nits 2017-11-11 12:15:24 -05:00
Jacob Evans
a85b1f016d Test case was error then unsubscribe 2017-11-11 12:01:27 -05:00
Fabio Berger
c6f97f20fb Merge branch 'development' into orderWatcher
* development:
  0.22.6
  Add new changes to CHANGELOG
  use util fn
  no race, reject from interval cb and clear
  allow timeout for await transaction mined

# Conflicts:
#	src/types.ts
2017-11-11 11:14:09 -05:00
Fabio Berger
b66600338e Add comment 2017-11-11 11:05:52 -05:00
Jacob Evans
4ae9482d50 Clean up subscription state.
In the case of an exception, keep the state correct between contract wrapper, exchange wrapper and token wrapper.
2017-11-11 11:01:59 -05:00
Fabio Berger
72fcf7b2ab rename isDecodedLog to isLogDecoded 2017-11-11 10:57:39 -05:00
Fabio Berger
a8b6bbd6bc Improve comment 2017-11-11 10:57:27 -05:00
Fabio Berger
e5d04f4467 Fix test given that we now do delete the keys in dependentOrderHashes 2017-11-11 10:50:08 -05:00
Fabio Berger
62ac8e1952 Fix missing renames 2017-11-11 10:22:09 -05:00
Fabio Berger
d61f34ec12 Declare OnOrderStateChangeCallback as either sync or async 2017-11-11 10:21:59 -05:00
Fabio Berger
252fdd03d7 Fix comment 2017-11-11 10:21:40 -05:00
Fabio Berger
0fe5c5dac3 Remove keys from dependentOrderHashes if empty 2017-11-11 10:13:42 -05:00
Fabio Berger
037e992de4 establish convention of initializing empty instances in instance declaration 2017-11-11 09:57:45 -05:00
Fabio Berger
12023073f4 Use enum instead of boolean to avoid potential bugs from isRemoved incorrectly being set to true 2017-11-11 09:54:27 -05:00
Fabio Berger
0db0694aad rename _orders to _orderByOrderhash for clarity 2017-11-11 09:47:32 -05:00
Fabio Berger
d4f763aa68 Add comment above orderStateWatcher class 2017-11-11 09:45:50 -05:00
Fabio Berger
4e708c81ca Fix expected balance 2017-11-11 09:19:51 -05:00
Fabio Berger
041d00301c Fix type declaration in test 2017-11-11 08:58:01 -05:00
Fabio Berger
0ec51b124b Feather the callback down to _emitDifferencesAsync and don't store it as a class instance. This will make supporting multiple subscriptions easier later on and reduces the amount of unsubscription cleanup 2017-11-11 08:57:49 -05:00
Fabio Berger
6012926e82 Throw if trying to subscribe multiple times 2017-11-10 18:07:11 -05:00
Fabio Berger
ca9c1bca4a Fix alignment 2017-11-10 18:06:57 -05:00
Fabio Berger
0d957ea71d Add comment above the eventWatcher class 2017-11-10 17:47:41 -05:00
Fabio Berger
697926641f Rename method since it's not more then just mempool 2017-11-10 17:47:30 -05:00
Fabio Berger
2bf65fda1f Add tests for the numConfirmations config to ensure that the events are being emitted for the confirmation depth specified 2017-11-10 16:34:21 -05:00
Fabio Berger
4262ac3c89 Fix unhandled promise rejection error on subscriptions 2017-11-10 14:13:15 -05:00
Leonid Logvinov
76b66872d8 0.22.6 2017-11-10 11:41:31 -05:00
Leonid Logvinov
2f92aaea0c Add new changes to CHANGELOG 2017-11-10 11:40:31 -05:00
Leonid
c5b347bb15 Merge pull request #206 from lukeautry/await_transaction_timeout
Allow timeout for await transaction mined
2017-11-10 11:38:02 -05:00
Luke Autry
d11087c28f use util fn 2017-11-10 11:35:40 -05:00
Luke Autry
e6139e02b8 no race, reject from interval cb and clear 2017-11-10 11:34:17 -05:00
Luke Autry
583b92e672 allow timeout for await transaction mined 2017-11-10 10:43:52 -05:00
Fabio Berger
d90756e8ef Test that the orderStateWatcher doesn't emit an event when an irrelevant blockchain event is received. 2017-11-10 10:07:29 -05:00
Fabio Berger
9b9ab983d6 Fix test description 2017-11-10 09:04:25 -05:00
Fabio Berger
d5746652a2 Fix test description 2017-11-09 23:37:01 -05:00
Fabio Berger
47f9e171fc Move numConfirmations to constructor call 2017-11-09 23:32:22 -05:00
Fabio Berger
a1bc18e5cf Improve comment 2017-11-09 23:32:04 -05:00
Fabio Berger
0cd5bf7967 Make sure to set the defaultBlock to the blockNumber rather then the number of confirmations 2017-11-09 23:24:46 -05:00
Fabio Berger
0205f9ede3 Simplify to/from block code 2017-11-09 23:16:26 -05:00
Fabio Berger
960c83315b Add assertion 2017-11-09 23:05:46 -05:00
Fabio Berger
f9c84fb6f4 Merge branch 'orderWatcher' of github.com:0xProject/0x.js into orderWatcher
* 'orderWatcher' of github.com:0xProject/0x.js:
  Add forgotten file
2017-11-09 22:58:10 -05:00
Fabio Berger
1b14561748 remove no longer needed arg 2017-11-09 22:58:06 -05:00
Fabio Berger
27519e1dfa rename intervalId to intervalIdIfExists 2017-11-09 22:57:38 -05:00
Leonid Logvinov
46e2da24a4 Add forgotten file 2017-11-09 22:12:29 -05:00
Fabio Berger
dbbcbed344 Merge branch 'orderWatcher' of github.com:0xProject/0x.js into orderWatcher
* 'orderWatcher' of github.com:0xProject/0x.js:
  Add order state watcher tests for LogCancel

# Conflicts:
#	test/order_state_watcher_test.ts
2017-11-09 18:30:20 -05:00
Fabio Berger
c0db88168b Fix bug where we hard-coded using pendingBlock for fetching the orderState. Moved numConfirmations to become a global orderStateWatcher config 2017-11-09 18:29:13 -05:00
Leonid Logvinov
d98435b4dc Add order state watcher tests for LogCancel 2017-11-09 18:28:33 -05:00
Fabio Berger
595dc6de03 Fix comments 2017-11-09 18:04:24 -05:00
Fabio Berger
322e054f1a comment improvements 2017-11-09 17:57:41 -05:00
Fabio Berger
7f606e1e64 Closing paren on same level as open 2017-11-09 17:50:48 -05:00
Fabio Berger
b0491b0ee2 Rename _callbackAsync to _callbackIfExistsAsync for clarity 2017-11-09 17:48:05 -05:00
Fabio Berger
0e69356ca9 Merge branches 'orderWatcher' and 'orderWatcher' of github.com:0xProject/0x.js into orderWatcher
* 'orderWatcher' of github.com:0xProject/0x.js:
  Fix getting events from non-mempool

* 'orderWatcher' of github.com:0xProject/0x.js:
  Fix getting events from non-mempool
2017-11-09 17:45:37 -05:00
Fabio Berger
90348e08c1 use explicit import 2017-11-09 17:45:30 -05:00
Leonid Logvinov
c60d7e2db8 Fix getting events from non-mempool 2017-11-09 17:44:45 -05:00
Fabio Berger
50d3a14825 Remove finished TODOs 2017-11-09 17:39:03 -05:00
Fabio Berger
0ff3ba5250 Merge branch 'orderWatcher' of github.com:0xProject/0x.js into orderWatcher
* 'orderWatcher' of github.com:0xProject/0x.js:
  Revert test amount changes
2017-11-09 17:20:49 -05:00
Fabio Berger
02cc3f9116 Create assert.isValidSignature method and use it in addOrder 2017-11-09 17:18:30 -05:00
Fabio Berger
62861d1e13 Move isValidSignature implementation into signatureUtils 2017-11-09 17:18:03 -05:00
Leonid Logvinov
cd3c7f1b97 Revert test amount changes 2017-11-09 17:14:10 -05:00
Fabio Berger
0c8886ad0c Fix comment 2017-11-09 17:03:54 -05:00
Fabio Berger
9d24325207 Merge branch 'orderWatcher' of github.com:0xProject/0x.js into orderWatcher
* 'orderWatcher' of github.com:0xProject/0x.js:
  Revert "Use _.get for optional configs"

# Conflicts:
#	src/0x.ts
2017-11-09 17:01:30 -05:00
Fabio Berger
126a165f55 Add nested config for orderWatcher 2017-11-09 16:59:41 -05:00
Leonid Logvinov
1c6e6842c6 Revert "Use _.get for optional configs"
This reverts commit ecc54b07c7.
2017-11-09 16:48:45 -05:00
Fabio Berger
6f5a55b5fe Rename MempoolEventCallback to EventWatcherCallback 2017-11-09 16:43:19 -05:00
Fabio Berger
530f5a700e Merge branch 'orderWatcher' of github.com:0xProject/0x.js into orderWatcher
* 'orderWatcher' of github.com:0xProject/0x.js:
  Fix namings
2017-11-09 16:42:06 -05:00
Fabio Berger
441c1f9ab7 rename folder to order_watcher 2017-11-09 16:41:57 -05:00
Leonid Logvinov
d98d885924 Fix namings 2017-11-09 16:37:00 -05:00
Leonid Logvinov
6aa91d89e0 Remove redundant assertions 2017-11-09 16:30:40 -05:00
Fabio Berger
ecc54b07c7 Use _.get for optional configs 2017-11-09 16:30:14 -05:00
Fabio Berger
ce11a38d70 Improve comment 2017-11-09 16:23:39 -05:00
Leonid Logvinov
c9e0b29878 Add SubscriptionAlreadyPresent error 2017-11-09 16:20:31 -05:00
Leonid Logvinov
3a96fec03b Pass numConfirmations 2017-11-09 15:38:23 -05:00
Leonid Logvinov
7a231b3166 Removed unused order adding in tests 2017-11-09 15:30:41 -05:00
Leonid Logvinov
31f6934787 Add a test that a second subscription fails 2017-11-09 15:30:22 -05:00
Fabio Berger
c5dc89886d fix merge conflicts 2017-11-09 15:13:56 -05:00
Fabio Berger
545cc0b026 Add comments to public methods 2017-11-09 15:02:44 -05:00
Fabio Berger
9ff42053c3 Add numConfirmations arg so that caller can decide on numConfirmations at which they want to watch orders 2017-11-09 15:02:28 -05:00
Leonid Logvinov
41a0ce146d Add tests for order removals 2017-11-09 14:54:55 -05:00
Leonid Logvinov
709fa06af6 Pass orderHash instead of an order to removeOrder and adjust the tests 2017-11-09 14:23:53 -05:00
Fabio Berger
5623400557 Merge branch 'orderWatcher' of github.com:0xProject/0x.js into orderWatcher
* 'orderWatcher' of github.com:0xProject/0x.js: (32 commits)
  Remove check for now, we need a more robust check
  Rename test file and add test for a partial fill
  Fix tests by making the expected balance be 2^27 not 2^26
  Add assert.isValidBaseUnitAmount that checks for decimals in amounts that should be in baseUnits. This can sometimes alert developers whenever they accidentally pass in unitAmounts.
  Look for relevant events in the decodedLogs and emit orderState events for orders impacted by the blockchain state changes
  Remove unused import
  Fix typo
  Add todo comments
  fix styling
  remove unused type
  Add naive order state watcher implementation
  Change fields in OrderState to represent taker side values
  Introduce OrderState interface
  Fix config schema
  Add empty implementation of order state watcher
  Add new public types
  Move mempoolPollingIntervalMs to OrderWatcherConfig
  Adjust tests for mempool event watcher
  Clear event cache on unsubscribe
  Remove mempool event watcher config
  ...
2017-11-09 14:12:17 -05:00
Fabio Berger
1351e02065 Remove check for now, we need a more robust check 2017-11-09 14:11:46 -05:00
Fabio Berger
4f030ac45c Rename test file and add test for a partial fill 2017-11-09 14:11:46 -05:00
Fabio Berger
c7c81a1f7e Fix tests by making the expected balance be 2^27 not 2^26 2017-11-09 14:11:46 -05:00
Fabio Berger
ae74965774 Add assert.isValidBaseUnitAmount that checks for decimals in amounts that should be in baseUnits. This can sometimes alert developers whenever they accidentally pass in unitAmounts. 2017-11-09 14:11:46 -05:00
Fabio Berger
e952c98ca8 Look for relevant events in the decodedLogs and emit orderState events for orders impacted by the blockchain state changes 2017-11-09 14:11:46 -05:00
Fabio Berger
6f00c422c7 Remove unused import 2017-11-09 14:11:46 -05:00
Fabio Berger
e592cedbb4 Fix typo 2017-11-09 14:11:46 -05:00
Fabio Berger
a10bb4b2fa Add todo comments 2017-11-09 14:11:46 -05:00
Fabio Berger
c89eec4261 fix styling 2017-11-09 14:11:46 -05:00
Fabio Berger
edc0fec808 remove unused type 2017-11-09 14:11:46 -05:00
Leonid Logvinov
bb5474660c Add naive order state watcher implementation
Revalidate all orders upon event received and emit order states even if
not changed
2017-11-09 14:11:46 -05:00
Leonid Logvinov
63f16b5f99 Change fields in OrderState to represent taker side values 2017-11-09 14:11:46 -05:00
Leonid Logvinov
0b84c469d3 Introduce OrderState interface 2017-11-09 14:11:45 -05:00
Leonid Logvinov
ff5d18d327 Fix config schema 2017-11-09 14:11:45 -05:00
Leonid Logvinov
1980b3fae4 Add empty implementation of order state watcher 2017-11-09 14:11:45 -05:00
Leonid Logvinov
6714b8958b Add new public types 2017-11-09 14:11:45 -05:00
Leonid Logvinov
f601a5d356 Move mempoolPollingIntervalMs to OrderWatcherConfig 2017-11-09 14:11:45 -05:00
Leonid Logvinov
e7f60032bc Adjust tests for mempool event watcher 2017-11-09 14:11:45 -05:00
Leonid Logvinov
589bd8694f Clear event cache on unsubscribe 2017-11-09 14:11:45 -05:00
Leonid Logvinov
eace1a9840 Remove mempool event watcher config 2017-11-09 14:11:45 -05:00
Leonid Logvinov
3ddb203317 Move provider altering logic to Web3Wrapper 2017-11-09 14:11:45 -05:00
Leonid Logvinov
84b8e77aaa Add types for order state watcher 2017-11-09 14:11:45 -05:00
Leonid Logvinov
247eefc33a Add initial interface of an OrderWatcher 2017-11-09 14:11:45 -05:00
Leonid Logvinov
fd54a6a3ad Rename MempoolWatcher to EventWatcher and remove from public interface 2017-11-09 14:11:45 -05:00
Leonid Logvinov
a2ffd7de2e Fix namings 2017-11-09 14:11:45 -05:00
Leonid Logvinov
cea2fb0fe6 Add mempool tests 2017-11-09 14:11:45 -05:00
Leonid Logvinov
23d7d7d140 Don't emit new events if already unsubscribed 2017-11-09 14:11:45 -05:00
Leonid Logvinov
f8179bc5a9 Compare logs by string representation 2017-11-09 14:11:45 -05:00
Leonid Logvinov
a4e93558aa Upgrade web3-typescript-typings 2017-11-09 14:11:45 -05:00
Leonid Logvinov
cb3cae0f30 Add initial mempool watching implememtation 2017-11-09 14:11:45 -05:00
Fabio Berger
04e0199790 Remove check for now, we need a more robust check 2017-11-09 10:22:29 -05:00
Fabio Berger
453f3405a7 Rename test file and add test for a partial fill 2017-11-09 10:21:54 -05:00
Fabio Berger
a8585df81b Fix tests by making the expected balance be 2^27 not 2^26 2017-11-09 10:21:38 -05:00
Fabio Berger
c96c681758 Add assert.isValidBaseUnitAmount that checks for decimals in amounts that should be in baseUnits. This can sometimes alert developers whenever they accidentally pass in unitAmounts. 2017-11-09 10:09:20 -05:00
Fabio Berger
6007609f71 Look for relevant events in the decodedLogs and emit orderState events for orders impacted by the blockchain state changes 2017-11-08 19:01:57 -05:00
Fabio Berger
5a6ed252c4 Remove unused import 2017-11-08 19:00:38 -05:00
Fabio Berger
641dff8991 Fix typo 2017-11-08 19:00:14 -05:00
Fabio Berger
ee3115550e Add todo comments 2017-11-08 18:59:59 -05:00
Fabio Berger
d39852c0cf fix styling 2017-11-08 18:59:40 -05:00
Fabio Berger
c57894633f remove unused type 2017-11-08 18:59:28 -05:00
Fabio Berger
a7bedad9f0 0.22.5 2017-11-07 18:02:57 -05:00
Fabio Berger
92df3d953f Update changelog 2017-11-07 18:02:40 -05:00
Leonid Logvinov
a896904ae7 Add naive order state watcher implementation
Revalidate all orders upon event received and emit order states even if
not changed
2017-10-30 18:49:16 +02:00
Leonid Logvinov
6bfcd253f8 Change fields in OrderState to represent taker side values 2017-10-30 18:49:16 +02:00
Leonid Logvinov
456f7e7304 Introduce OrderState interface 2017-10-30 18:49:16 +02:00
Leonid Logvinov
ed7917f9df Fix config schema 2017-10-30 18:49:16 +02:00
Leonid Logvinov
2a25ece363 Add empty implementation of order state watcher 2017-10-30 18:49:16 +02:00
Leonid Logvinov
1c90c3af42 Add new public types 2017-10-30 18:49:16 +02:00
Leonid Logvinov
6ca6290f6a Move mempoolPollingIntervalMs to OrderWatcherConfig 2017-10-30 18:49:16 +02:00
Leonid Logvinov
fd2c5d46ad Adjust tests for mempool event watcher 2017-10-30 18:49:16 +02:00
Leonid Logvinov
a6c110f558 Clear event cache on unsubscribe 2017-10-30 18:49:16 +02:00
Leonid Logvinov
02b33f988f Remove mempool event watcher config 2017-10-30 18:49:16 +02:00
Leonid Logvinov
7bf6e6188a Move provider altering logic to Web3Wrapper 2017-10-30 18:49:16 +02:00
Leonid Logvinov
26394813f4 Add types for order state watcher 2017-10-30 18:49:16 +02:00
Leonid Logvinov
f21f42f11e Add initial interface of an OrderWatcher 2017-10-30 18:49:16 +02:00
Leonid Logvinov
68a8556cd2 Rename MempoolWatcher to EventWatcher and remove from public interface 2017-10-30 18:49:16 +02:00
Leonid Logvinov
e4d8b1c4d2 Fix namings 2017-10-30 18:49:16 +02:00
Leonid Logvinov
eac467fe9a Add mempool tests 2017-10-30 18:49:16 +02:00
Leonid Logvinov
1bb9c912cd Don't emit new events if already unsubscribed 2017-10-30 18:49:16 +02:00
Leonid Logvinov
02d470892f Compare logs by string representation 2017-10-30 18:49:16 +02:00
Leonid Logvinov
161f62dc27 Upgrade web3-typescript-typings 2017-10-30 18:49:16 +02:00
Leonid Logvinov
f53472e717 Add initial mempool watching implememtation 2017-10-30 18:49:16 +02:00
Fabio Berger
7fa5d34c45 Remove unnecessary dep 2017-10-30 18:48:16 +02:00
Fabio Berger
b49d1dae7d Merge branch 'development' of github.com:0xProject/0x.js into development
* 'development' of github.com:0xProject/0x.js:
  Update CHANGELOG
  0.22.4
  Add HACK comments
  Add a forgotten augmentation file
  Upgrade bignumber to the version with native typings and remove typings
  Downgrade typedoc
  Upgrade bignumber to the version with native typings and remove typings
2017-10-30 16:17:39 +02:00
Fabio Berger
9b0496b049 Fix comment 2017-10-30 16:08:44 +02:00
Leonid Logvinov
fec8f8a881 Update CHANGELOG 2017-10-25 23:05:49 +03:00
Leonid Logvinov
e08c54878c 0.22.4 2017-10-25 23:04:49 +03:00
Leonid
e78398862b Merge pull request #202 from 0xProject/fix/bignumber-types
Bignumber types
2017-10-25 23:04:31 +03:00
Leonid Logvinov
122a5e9b63 Add HACK comments 2017-10-25 23:04:17 +03:00
Leonid Logvinov
5d759d82ed Add a forgotten augmentation file 2017-10-25 22:30:22 +03:00
Leonid Logvinov
744a9b8931 Upgrade bignumber to the version with native typings and remove typings 2017-10-25 22:22:23 +03:00
Leonid Logvinov
45c4042e2b Downgrade typedoc 2017-10-25 22:11:09 +03:00
Leonid Logvinov
bba7704732 Upgrade bignumber to the version with native typings and remove typings 2017-10-25 22:10:09 +03:00
Leonid Logvinov
fa3e88c454 0.22.3 2017-10-25 12:20:47 +03:00
Leonid Logvinov
e0ff550e19 Update CHANGELOG 2017-10-25 12:16:20 +03:00
Leonid
48dbee2e10 Merge pull request #199 from NoteGio/raise-allowance-gas
Increase ALLOWANCE_TO_ZERO_GAS_AMOUNT
2017-10-25 10:22:35 +03:00
Austin Roberts
1ba2df8024 Increase ALLOWANCE_TO_ZERO_GAS_AMOUNT
On TestRPC, I'm seeing a particular transaction that is taking 47275
gas instead of the predefined 47155. It's not at all obvious to me
why this transaction is taking an extra 120 gas, and I've been unable
to reproduce the issue in the 0x.js test suite, but bumping the gas
allowance has resolved the issue for me.

The transactions in question are trying to set an unlimited proxy
allowance on either the WETH or ZRX tokens in the testrpc snapshot,
but run out of gas.
2017-10-24 17:14:35 -05:00
Leonid Logvinov
e17f6979c3 0.22.2 2017-10-24 18:58:40 +03:00
Leonid
8330dabda8 Merge pull request #197 from 0xProject/fix/rounding
Fix rounding of maker fill amount and correctly validate partial fees
2017-10-24 18:54:50 +03:00
Leonid Logvinov
1fd8c2a6e2 Update CHANGELOG 2017-10-24 18:47:22 +03:00
Leonid Logvinov
0c6be94222 Fix index 2017-10-24 18:31:59 +03:00
Leonid Logvinov
89103c40fb Use more meaningful variable names 2017-10-24 18:31:59 +03:00
Leonid Logvinov
fbe34663da Fix the rounding of makerFillAmount and correctly validate partial fees 2017-10-24 18:31:59 +03:00
Leonid Logvinov
9d0ccdfdcc Add tests testing that rounding or makerFillAmount is correct and that we only validate partial fees 2017-10-24 18:31:59 +03:00
Leonid Logvinov
cd1f0c74c1 Revert CHANGELOG 2017-10-24 16:42:50 +03:00
Leonid
3deac0f100 Merge pull request #198 from 0xProject/revert-195-minification
Revert "Reduce final bundle size by 11% (82kB)"
2017-10-24 16:40:50 +03:00
Leonid
641d3b75ea Revert "Reduce final bundle size by 11% (82kB)" 2017-10-24 16:40:38 +03:00
Brandon Millman
fab2fa9adf Merge pull request #196 from 0xProject/bmillman_fix_tslint
Fix lint script to analyze nested files
2017-10-23 10:20:42 -07:00
Brandon Millman
b3d8cefbe6 Fix lint script to analyze nested files 2017-10-19 12:03:49 -07:00
Leonid Logvinov
32e8e52ad7 0.22.1 2017-10-19 17:09:30 +03:00
Leonid Logvinov
77b3a43e17 Update CHANGELOG 2017-10-19 17:09:23 +03:00
Leonid
ddec91ba52 Merge pull request #195 from 0xProject/minification
Reduce final bundle size by 11% (82kB)
2017-10-19 16:31:06 +03:00
Leonid Logvinov
0329b36430 Fix linter errors 2017-10-19 12:55:14 +03:00
Leonid Logvinov
f62dc0f46c Update 0x-json-schemas 2017-10-19 12:44:00 +03:00
Leonid Logvinov
f64638173a Transform lodash-es to commonjs module format 2017-10-19 00:31:10 +03:00
Leonid Logvinov
14a0dcecf5 Fix tests 2017-10-18 23:38:28 +03:00
Leonid Logvinov
e17cca9834 Remove unused parts from artifacts 2017-10-18 17:46:37 +03:00
Leonid Logvinov
9b0f68f9a9 Include only used lodash functions 2017-10-18 17:45:39 +03:00
Leonid Logvinov
f4eb73ca7c Upgrade 0x-json-schemas to the version that doesn't depend on lodash 2017-10-18 17:19:56 +03:00
Leonid Logvinov
4ea6ebb0ae Uprade ethereumjs-blockstream, cause new version doesn't include source maps and is significantly smaller 2017-10-18 17:18:44 +03:00
Leonid Logvinov
8931f2e736 0.22.0 2017-10-16 12:03:31 +03:00
Leonid Logvinov
7ae78ca3c8 Update CHANGELOG 2017-10-16 12:03:20 +03:00
Leonid
d24eeec1a1 Merge pull request #187 from apackin/setFillOrKillToUseRequestInterface
[WIP] Use OrderFillRequest interface for batchFillOrKill
2017-10-16 11:41:04 +03:00
Leonid
a798f32cc8 Merge branch 'development' into setFillOrKillToUseRequestInterface 2017-10-16 11:40:20 +03:00
Leonid Logvinov
df5fe4a84f 0.21.4 2017-10-13 19:00:06 +03:00
Leonid Logvinov
9aef222f79 Add changes to CHANGELOG 2017-10-13 18:59:52 +03:00
Leonid
5591378245 Merge pull request #194 from 0xProject/feature/type-safe-subscriptions
Make logs fetching and subscriptions more type-safe
2017-10-13 17:16:11 +03:00
Leonid Logvinov
dde2268f9f Remove unused code 2017-10-13 13:03:00 +03:00
Leonid Logvinov
0eaca6c691 Make logs fetching and sunscriptions more type-safe 2017-10-13 12:52:59 +03:00
Leonid Logvinov
ba654c04a0 0.21.3 2017-10-12 17:56:13 +03:00
Leonid
f4fbac2694 Merge pull request #193 from 0xProject/fix/allowance-error
Fix an issue causing fills to throw `INSUFFICIENT_TAKER_ALLOWANCE`
2017-10-12 17:51:37 +03:00
Leonid Logvinov
b86f6322e1 Update CHANGELOG 2017-10-12 17:08:46 +03:00
Leonid Logvinov
74c6be3698 Pass correct parameters to validation simulation 2017-10-12 17:02:18 +03:00
Leonid Logvinov
d114613384 Add a regression test 2017-10-12 17:01:55 +03:00
Leonid Logvinov
c23ea1e688 0.21.2 2017-10-11 18:49:26 +03:00
Leonid
f9d4799ebe Merge pull request #190 from 0xProject/fix/export-contract-event-arg
Export ContractEventArg
2017-10-11 18:37:48 +03:00
Leonid Logvinov
9ec4f6dcab Update CHANGELOG 2017-10-11 18:09:10 +03:00
Leonid Logvinov
bcdd063d70 Export ContractEventArg 2017-10-11 18:03:25 +03:00
Leonid Logvinov
22bc7cd692 0.21.1 2017-10-11 15:12:02 +03:00
Leonid
080fe38d1c Merge pull request #189 from 0xProject/fix/getLogsParamsSerialization
Fix a bug in logs fetching
2017-10-11 15:11:40 +03:00
Leonid Logvinov
df32756556 Update CHANGELOG 2017-10-11 14:58:58 +03:00
Leonid Logvinov
d02b7c5fdf Fix a bug in logs fetching 2017-10-11 14:54:49 +03:00
Assaf
c8b54f3bac Use OrderFillRequest interface for batchFillOrKill 2017-10-10 19:52:43 -04:00
Leonid Logvinov
233f97891c 0.21.0 2017-10-10 15:26:46 +03:00
Leonid
056e0f26ab Merge pull request #185 from 0xProject/fix/batch-validation
Fix batch validation
2017-10-10 14:15:57 +03:00
Leonid Logvinov
bda979a6c7 Change tests to test that allowance is checked first 2017-10-10 11:58:18 +03:00
Leonid Logvinov
cfae1a8dfd Throw allowance errors first 2017-10-10 11:48:42 +03:00
Leonid Logvinov
468a20c9ea Remove unused check 2017-10-10 11:48:05 +03:00
Leonid Logvinov
f24c94f1a8 Fix the comment 2017-10-10 11:47:39 +03:00
Leonid Logvinov
ac27937a9c Fix the comment 2017-10-10 11:47:01 +03:00
Leonid Logvinov
2b82354617 Remove redundant constructor 2017-10-10 11:46:33 +03:00
Leonid Logvinov
3fa98ec00e Assign to a variable before assigning 2017-10-10 11:45:57 +03:00
Leonid Logvinov
052fd5783f Change string enum value 2017-10-10 11:44:27 +03:00
Leonid Logvinov
63aa3d0659 Fix CHANGELOG comments 2017-10-10 11:43:55 +03:00
Leonid Logvinov
a4af1065ed Update CHANGELOG 2017-10-09 13:23:51 +03:00
Leonid Logvinov
ef8b2875cf Fix the comment 2017-10-09 13:20:19 +03:00
Leonid Logvinov
1424a7302a Implement transfer Emulator and rewrite tests 2017-10-09 13:07:48 +03:00
Leonid Logvinov
54ac354809 Add types for TradeSide and TransferType 2017-10-06 15:54:17 +03:00
Leonid
f38d2f80a6 Merge pull request #182 from 0xProject/feature/ethereumjs-blockstream
Rewrite subscriptions
2017-10-06 15:24:42 +03:00
Leonid Logvinov
0c112a2a1c Add a hex prefix 2017-10-06 15:13:31 +03:00
Leonid Logvinov
81297b44c6 Add undefined check 2017-10-06 13:15:11 +03:00
Leonid Logvinov
a2cc127ea9 Fix comments 2017-10-06 13:10:45 +03:00
Leonid Logvinov
cfa75ed36c Add a comment 2017-10-06 13:09:14 +03:00
Leonid Logvinov
498cf5333d Fix a typo 2017-10-06 13:08:07 +03:00
Leonid Logvinov
292aab9b18 Use BlockParamLiteral types 2017-10-06 13:07:01 +03:00
Leonid Logvinov
637183e4b2 introduce BlockParamLiteral 2017-10-06 13:04:51 +03:00
Leonid Logvinov
44e2929a4c Check for blockAndLogStreamer to be undefined instead of th filters object to be empty 2017-10-06 13:01:08 +03:00
Leonid Logvinov
1043def46c Install js-sha3 and use it for keccak256 2017-10-06 12:58:17 +03:00
Leonid Logvinov
6af2ba5cff Remove _activeFilters 2017-10-06 12:30:27 +03:00
Leonid
cd5327bc31 Merge pull request #184 from 0xProject/greenkeeper/typedoc-0.9.0
Update typedoc to the latest version 🚀
2017-10-06 12:11:05 +03:00
greenkeeper[bot]
977fe0f8ef chore(package): update typedoc to version 0.9.0 2017-10-06 04:16:50 +00:00
Leonid Logvinov
a406b4d134 Remove unused imports 2017-10-05 17:34:30 +03:00
Leonid Logvinov
1414b8ee8b Add type assertions for callback parameters 2017-10-05 16:32:01 +03:00
Leonid Logvinov
209c31f361 Remove TODOs 2017-10-05 16:28:20 +03:00
Leonid Logvinov
721d969a85 Make it possible to have multiple layers of snapshots 2017-10-05 15:56:28 +03:00
Leonid Logvinov
7bcedc27b8 Update CHANGELOG 2017-10-05 15:43:46 +03:00
Leonid Logvinov
553cbb25f4 Fix comments 2017-10-05 15:35:38 +03:00
Leonid Logvinov
118381c1d1 Move more logic into _stopBlockAndLogStream and _startBlockAndLogStream 2017-10-05 15:35:38 +03:00
Leonid Logvinov
f2100fa36d Remove missing comment 2017-10-05 15:35:38 +03:00
Leonid Logvinov
a537b2e40c Add missing comment 2017-10-05 15:35:37 +03:00
Leonid Logvinov
1b6d3b0f0b Add missing comments 2017-10-05 15:35:37 +03:00
Leonid Logvinov
7dd6352393 Implement subscriptions based on ethereumjs-blockstream 2017-10-05 15:35:37 +03:00
Leonid Logvinov
e37a3155cd Instantiate logAndBlockStreamer 2017-10-05 15:35:37 +03:00
Leonid Logvinov
542cf7b1cb Fix CHANGELOG formatting 2017-10-05 14:55:32 +03:00
Leonid Logvinov
60de7ecc41 0.20.0 2017-10-05 14:52:16 +03:00
Leonid Logvinov
624d108124 Revert "0.20.0"
This reverts commit acdc65c895.
2017-10-05 14:51:54 +03:00
Leonid
46f4c56a3d Merge pull request #183 from 0xProject/fix/getLogs-assertions
Add assertions
2017-10-05 14:49:04 +03:00
Leonid Logvinov
49a50efa9f Add assertion for tokenAddress 2017-10-05 14:43:04 +03:00
Leonid Logvinov
80cbdf469e Add assertions 2017-10-05 14:41:42 +03:00
Leonid Logvinov
acdc65c895 0.20.0 2017-10-05 09:48:27 +03:00
Leonid
0eb7b81636 Merge pull request #181 from 0xProject/feature/order-validation-zrx
Fees validations when one of the tokens is ZRX
2017-10-05 09:47:55 +03:00
Leonid Logvinov
0594667d36 Small reordering 2017-10-05 09:46:54 +03:00
Leonid Logvinov
cd16b35814 Fix a typo 2017-10-05 09:46:09 +03:00
Leonid
5bc7d716e0 Merge pull request #177 from 0xProject/greenkeeper/mocha-4.0.0
Update mocha to the latest version 🚀
2017-10-04 15:42:14 +03:00
Leonid Logvinov
3ec2402a98 Exit after running the tests 2017-10-04 15:16:51 +03:00
greenkeeper[bot]
04978f93d5 chore(package): update mocha to version 4.0.0 2017-10-04 15:11:37 +03:00
Leonid
0fa978c959 Merge pull request #179 from 0xProject/greenkeeper/source-map-support-0.5.0
Update source-map-support to the latest version 🚀
2017-10-04 15:10:38 +03:00
greenkeeper[bot]
f70cef081c chore(package): update source-map-support to version 0.5.0 2017-10-04 15:10:17 +03:00
Leonid Logvinov
b4717b8526 Fix tests 2017-10-04 15:06:38 +03:00
Leonid Logvinov
074040daf5 Add changes to CHANGELOG 2017-10-04 15:01:51 +03:00
Leonid Logvinov
0caab98399 Fi fees validation is one of the tokens transfered is 0x 2017-10-04 14:58:08 +03:00
Leonid Logvinov
8b7caef0db Fix an issue when validation failed, but contract call will succeed 2017-10-04 14:31:09 +03:00
Leonid
836d9be7fe Merge pull request #178 from 0xProject/feature/getLogs
Add zeroEx.getLogsAsync
2017-10-04 14:30:36 +03:00
Leonid Logvinov
e5bdf60460 Move ZRX_NOT_IN_TOKEN_REGISTRY to InternalZeroExError 2017-10-04 14:25:15 +03:00
Leonid Logvinov
11c48ced00 Reduce nesting 2017-10-04 14:23:42 +03:00
Leonid Logvinov
cc3871aca5 Use find 2017-10-04 14:22:47 +03:00
Leonid Logvinov
8fb5e87243 Allign brackets 2017-10-04 14:22:17 +03:00
Leonid Logvinov
504beeb2f3 Add filtering by topic 2017-10-04 13:30:00 +03:00
Leonid Logvinov
9af47eb063 Use a ternary and add a comment 2017-10-04 12:59:46 +03:00
Leonid Logvinov
944f51d66c Use SolidityTypes 2017-10-04 12:55:16 +03:00
Leonid Logvinov
499e60c4a3 Use 0x.length instead of 2 2017-10-04 12:48:45 +03:00
Leonid Logvinov
a6f4f83b5b Add a comment 2017-10-04 11:55:29 +03:00
Leonid Logvinov
2b9418b700 Fix a typo 2017-10-04 11:54:34 +03:00
Leonid Logvinov
aa995ff994 Use _.find instead of _.filter 2017-10-04 11:53:44 +03:00
Leonid Logvinov
d1e4f6efdd Move NoAbiDecoder to InternalZeroExErrors 2017-10-04 11:53:02 +03:00
Leonid Logvinov
f65bfc1ab1 Extract topics to its variable 2017-10-04 11:51:36 +03:00
Leonid Logvinov
f26d49f077 Use Noop instead of NoOp 2017-10-04 11:48:53 +03:00
Leonid Logvinov
ad7ce6c916 Update CHANGELOG 2017-10-04 11:14:20 +03:00
Leonid Logvinov
7c49224c7b Don't export RawLog 2017-10-04 11:14:20 +03:00
Leonid Logvinov
451ded4963 Add tests for zeroEx.exchange.getLogsAsync 2017-10-04 11:14:20 +03:00
Leonid Logvinov
837618c7a0 Implement zeroEx.exchange.getLogsAsync 2017-10-04 11:14:20 +03:00
Leonid Logvinov
e6c138be5a Add _getLogsAsync on contract_wrapper 2017-10-04 11:14:19 +03:00
Leonid Logvinov
087645e59f Add tests for zeroEx.token.getLogsAsync 2017-10-04 11:14:19 +03:00
Leonid Logvinov
0a12fa7f4e Implement getLogsAsync on token contract 2017-10-04 11:14:19 +03:00
Leonid Logvinov
87374d7f46 Refactor abi decoder 2017-10-04 11:14:19 +03:00
Leonid Logvinov
efa85f844b Add tryToDecodeLogOrNoOp and _getEventSignatureFromAbiByName on contract_wrapper 2017-10-04 11:14:19 +03:00
Leonid Logvinov
db08896274 Remove old tests 2017-10-04 11:14:19 +03:00
Leonid Logvinov
44abf283ec Add keccak256 on web3_wrapper 2017-10-04 11:14:19 +03:00
Leonid Logvinov
671bc7c917 Add NO_ABI_DECODER and ContractEvents 2017-10-04 11:14:19 +03:00
Leonid Logvinov
6bbdc98ba2 Move log decoding to AbiDecoder 2017-10-04 11:14:19 +03:00
Leonid Logvinov
a9681072ee Factor out tryToDecodeLogOrNoOp 2017-10-04 11:14:19 +03:00
Leonid Logvinov
16af052a16 Don't text for an exact block hash 2017-10-04 11:14:19 +03:00
Leonid Logvinov
40e0706954 Add changes to CHANGELOG 2017-10-04 11:14:19 +03:00
Leonid Logvinov
b859f4b8ab Add tests for zeroEx.getLogsAsync 2017-10-04 11:14:19 +03:00
Leonid Logvinov
835c17c961 Add zeroEx.getLogsAsync 2017-10-04 11:14:19 +03:00
Leonid Logvinov
7b545aa0e0 Re-export new types 2017-10-04 11:14:19 +03:00
Leonid Logvinov
ea08fc8642 Add getLogsAsync to web3_wrapper 2017-10-04 11:14:19 +03:00
Leonid Logvinov
5410924810 Add type aliases for web3 types 2017-10-04 11:14:19 +03:00
Leonid Logvinov
5d21d10437 Update web3-typescript-typings 2017-10-04 11:14:18 +03:00
Leonid
5d554ab882 Merge pull request #180 from 0xProject/greenkeeper/0x-json-schemas-0.6.0
Update 0x-json-schemas to the latest version 🚀
2017-10-04 11:12:15 +03:00
greenkeeper[bot]
c2ce8732e7 fix(package): update 0x-json-schemas to version 0.6.0 2017-10-04 06:49:52 +00:00
Leonid Logvinov
76c8d7108f 0.19.0 2017-09-29 16:21:22 +02:00
Leonid Logvinov
024bc1756e Fix types 2017-09-29 16:21:08 +02:00
Leonid Logvinov
0cf5cc778a Update CHANGELOG 2017-09-29 15:42:40 +02:00
Leonid
ed4536f57f Merge pull request #175 from 0xProject/fix/set-interval-bug
Fix the bug in transaction mined awaiting
2017-09-29 15:27:51 +02:00
Leonid Logvinov
5bc33257b6 Fix the bug in transaction mined awaiting 2017-09-29 15:22:01 +02:00
Leonid
0c3a14b662 Merge pull request #169 from 0xProject/greenkeeper/sinon-4.0.0
Update sinon to the latest version 🚀
2017-09-29 11:51:41 +02:00
Leonid
4b7b46071f Merge pull request #174 from 0xProject/greenkeeper/coveralls-3.0.0
Update coveralls to the latest version 🚀
2017-09-29 11:51:13 +02:00
Leonid
cbc9e87d65 Merge pull request #173 from 0xProject/feature/ropsten-support
Add Ropsten support
2017-09-28 18:18:19 +02:00
greenkeeper[bot]
1c10440a15 chore(package): update coveralls to version 3.0.0 2017-09-28 16:11:29 +00:00
Brandon Millman
a0af271996 Merge pull request #172 from 0xProject/bmillman_optional_validation
Add OrderTransactionOpts to enable optional validation to exchange_wr…
2017-09-28 09:06:23 -07:00
Brandon Millman
d21fbbc4c8 Fixed nits 2017-09-28 08:44:29 -07:00
Leonid Logvinov
db419ffcc7 Add tests for ropsten artifacts 2017-09-28 14:42:48 +02:00
Leonid Logvinov
b537636b42 Update CHANGELOG 2017-09-28 14:38:51 +02:00
Leonid Logvinov
4e0b4415f0 Add Ropsten artifacts 2017-09-28 14:36:58 +02:00
Brandon Millman
333665370f Add tests 2017-09-27 17:12:38 -07:00
Brandon Millman
1d4506427f Add OrderTransactionOpts to enable optional validation to exchange_wrapper 2017-09-27 13:28:11 -07:00
Fabio Berger
be12c5b538 0.18.0 2017-09-26 16:24:13 +02:00
Fabio Berger
5449fc5093 0.17.0 2017-09-26 16:23:48 +02:00
Fabio Berger
a87dd7af7d Update changelog 2017-09-26 16:23:29 +02:00
Fabio Berger
949fc2fc82 Merge pull request #170 from 0xProject/addOrderValidation
Add validateOrderFillableOrThrowAsync Method
2017-09-26 16:07:42 +02:00
Fabio Berger
5f7afce49d fix test 2017-09-26 15:58:08 +02:00
Fabio Berger
f8d5b72367 fix test 2017-09-26 15:57:36 +02:00
Fabio Berger
ad6e848821 fix merge issue 2017-09-26 15:37:14 +02:00
Fabio Berger
9ee88ba06d Updated changelog 2017-09-26 15:30:54 +02:00
Fabio Berger
deac665b42 Merge branch 'development' into addOrderValidation
* development:
  Update comment
  Add a test for getZRXTokenAddressAsync
  Document changes in CHANGELOG
  Make getZRXTokenAddressAsync public
2017-09-26 15:29:44 +02:00
Fabio Berger
fbac611337 improve comment 2017-09-26 15:29:08 +02:00
Fabio Berger
9886383638 Fix linter issue 2017-09-26 15:28:07 +02:00
Fabio Berger
5bea6ff581 Add success test and regression test for previous bug where comparing makerTokenAmount with a takerTokenAmount 2017-09-26 15:27:59 +02:00
Leonid
3c40526bff Merge pull request #171 from 0xProject/feature/zrx-getter
Make getZRXTokenAddressAsync public
2017-09-26 15:07:14 +02:00
Leonid Logvinov
8a29f12a61 Update comment 2017-09-26 15:02:12 +02:00
Fabio Berger
e704aea643 Add tests for validateOrderFillableOrThrowAsync 2017-09-26 12:39:17 +02:00
Fabio Berger
25116940c0 Refactor our logic checking fillAmountNotZero and expiry 2017-09-26 12:39:05 +02:00
Fabio Berger
2148eb6d99 make opts optional 2017-09-26 12:32:49 +02:00
Leonid Logvinov
ee0adc8a7e Add a test for getZRXTokenAddressAsync 2017-09-26 11:57:32 +02:00
Fabio Berger
d3f729dd71 rename validateOrderFillableThrowIfNotFillableAsync to validateOrderFillableOrThrowAsync 2017-09-26 11:55:07 +02:00
Fabio Berger
9effd57229 Fix bug where we were accidentally comparing a makerTokenAmount to a takerTokenAmount 2017-09-26 11:51:51 +02:00
Leonid Logvinov
e347297aaa Document changes in CHANGELOG 2017-09-26 11:46:31 +02:00
Leonid Logvinov
68c240aa4d Make getZRXTokenAddressAsync public 2017-09-26 11:44:33 +02:00
Fabio Berger
5e6c4e0ec3 improve comment 2017-09-26 11:38:37 +02:00
Fabio Berger
5e92ca039c Add validateOrderFillableThrowIfNotFillableAsync to public methods in order to validate orders in an orderbook without a specific taker in mind 2017-09-26 11:01:33 +02:00
greenkeeper[bot]
d1ce78a64f chore(package): update sinon to version 4.0.0 2017-09-26 08:27:04 +00:00
Leonid Logvinov
0a19a7e8d1 0.16.0 2017-09-20 15:05:43 +02:00
Leonid
d424933d70 Merge pull request #165 from 0xProject/feature/configurable-addresses
Allow users to pass contract addresses as a config
2017-09-20 14:59:48 +02:00
Leonid Logvinov
91679caf93 Update release date 2017-09-20 14:59:21 +02:00
Leonid Logvinov
1efcc5ad62 Fix the typo 2017-09-20 14:57:33 +02:00
Leonid Logvinov
96d853fc4b Add a comment for ZeroExConfig type 2017-09-19 15:09:05 +02:00
Leonid Logvinov
0f942f95f0 Move lower-casing logic 2017-09-19 14:56:41 +02:00
Leonid Logvinov
f1cb3a4f37 Fix a comment 2017-09-19 14:53:58 +02:00
Leonid Logvinov
66db021900 Postfix variable names with 'ifExists' 2017-09-19 14:53:12 +02:00
Leonid Logvinov
e7af0eb20c Prefix HACK comment with HACK 2017-09-19 14:43:42 +02:00
Leonid Logvinov
5e40f76996 Postfix variable names with 'ifExists' 2017-09-19 14:43:14 +02:00
Leonid Logvinov
903e2f4f8a Verify ZeroExConfig 2017-09-19 14:13:06 +02:00
Leonid Logvinov
4aeb6226d5 Add changes to the CHANGELOG 2017-09-19 13:29:15 +02:00
Leonid Logvinov
e19d5b3c78 Fix a typo 2017-09-18 17:26:30 +02:00
Leonid Logvinov
946978e454 Add explanatory comment 2017-09-18 17:24:54 +02:00
Leonid Logvinov
40a0d345b5 Add tests for contracts address config 2017-09-18 16:54:24 +02:00
Leonid Logvinov
504e7a25a5 Make contract addresses configurable 2017-09-18 15:55:26 +02:00
Leonid Logvinov
8db90538a1 Fetch tokenTransferProxy address from exchange contract 2017-09-18 15:18:04 +02:00
Leonid Logvinov
fe9f692a4f 0.15.0 2017-09-08 16:34:19 +02:00
Leonid
e9448953ac Merge pull request #161 from 0xProject/feature/defaultBlock
Add a possibility to specify defaultBlock when calling const blockchain methods
2017-09-08 16:33:45 +02:00
Leonid Logvinov
217c16027e Replace placeholders with actual coments 2017-09-08 16:24:07 +02:00
Leonid Logvinov
be0b9a1d7c Add a comment for MethodOpts 2017-09-08 14:02:03 +02:00
Leonid Logvinov
fdf54668ae Fix CHANGELOG comment 2017-09-08 14:00:39 +02:00
Leonid Logvinov
1d64b542d8 Rename CallOpts to MethodOpts 2017-09-08 13:56:10 +02:00
Leonid Logvinov
e60153a4fb Update CHANGELOG.md 2017-09-08 12:28:18 +02:00
Leonid Logvinov
762d02b2e0 Allow user to specify defaultBlock when calling const exchange methods 2017-09-08 12:25:05 +02:00
Leonid Logvinov
1dcfd4102b Allow user to specify defaultBlock when calling const token methods 2017-09-08 12:03:04 +02:00
Leonid Logvinov
aaae22642e Define CallOpts type 2017-09-08 12:02:37 +02:00
Leonid Logvinov
6999e15972 0.14.2 2017-09-07 21:10:23 +02:00
Leonid
1501b47c10 Merge pull request #160 from 0xProject/fix/bignumber-types
Add bignumber.js types as a dependency
2017-09-07 21:09:30 +02:00
Leonid Logvinov
fbb4e844a7 Update CHANGELOG 2017-09-07 21:05:35 +02:00
Leonid Logvinov
a705a7d612 Make bignumber.js types normal dependency 2017-09-07 20:55:21 +02:00
Leonid Logvinov
a0a39fa4dd 0.14.1 2017-09-07 20:32:40 +02:00
Leonid Logvinov
36de4c7b0f Add release note to CHANGELOG 2017-09-07 20:32:29 +02:00
Leonid
4e22c289af Merge pull request #159 from 0xProject/fix/types
Move Aftifact type definition to 'types'
2017-09-07 20:31:20 +02:00
Leonid Logvinov
af217e316a Move Aftifact type definition to 'types' 2017-09-07 20:28:45 +02:00
Leonid Logvinov
b5435b6ab8 0.14.0 2017-09-06 18:34:30 +02:00
Leonid Logvinov
c7418e131f Fix version number in CHANGELOG 2017-09-06 18:34:05 +02:00
Leonid
c567249819 Merge pull request #157 from 0xProject/feature/throw-for-exchange-errors
Feature/throw for exchange errors
2017-09-06 18:32:02 +02:00
Leonid Logvinov
d2dc4d18be Add zeroEx.exchange.throwLogErrorsAsErrors to CHANGELOG 2017-09-06 18:27:25 +02:00
Leonid Logvinov
67ed341f24 Use LogError type 2017-09-06 18:26:17 +02:00
Leonid Logvinov
0b6e874a0d Fix a comment 2017-09-06 18:25:03 +02:00
Leonid Logvinov
88791f732f Make intervalUtils an object instead of a class and make instance variable local 2017-09-06 18:22:28 +02:00
Leonid Logvinov
b1feb5ac29 Fix a bug in intervalUtils 2017-09-06 17:49:51 +02:00
Leonid Logvinov
873aa26f63 Update CHANGELOG 2017-09-06 17:45:10 +02:00
Leonid Logvinov
a57b22a6bc Fix overlapping async intervals issue 2017-09-06 17:41:40 +02:00
Leonid Logvinov
7c61b09dce Add zeroEx.exchange.throwLogErrorsAsErrors 2017-09-06 17:29:15 +02:00
Leonid Logvinov
b38aff8808 Fix log decoder to return correct types 2017-09-06 17:26:55 +02:00
Leonid Logvinov
912d15cb73 0.13.0 2017-09-06 15:35:15 +02:00
Leonid Logvinov
9dc13360c9 Revert "0.13.0"
This reverts commit 92eb68bf2c.
2017-09-06 15:35:03 +02:00
Leonid
cb44b77d0b Merge pull request #156 from 0xProject/feature/custom-abi-decoder
Custom abi decoder
2017-09-06 15:26:29 +02:00
Leonid Logvinov
1baf065317 Use startsWith instead of includes 2017-09-06 15:26:15 +02:00
Leonid Logvinov
88c96c7052 Use template strings 2017-09-06 15:15:00 +02:00
Leonid Logvinov
9680cc1270 Use _.includes instead of indexOf 2017-09-06 15:14:36 +02:00
Leonid Logvinov
68d051d4a7 Rename methodID to methodId 2017-09-06 15:11:41 +02:00
Leonid Logvinov
f1ed572819 Remove redundant js prefix 2017-09-06 15:11:08 +02:00
Leonid Logvinov
9ae56485a9 Fix type error 2017-09-06 15:10:59 +02:00
Leonid Logvinov
a7ba16ef4a Handle the case, when it's not possible to decode args 2017-09-06 14:31:52 +02:00
Leonid Logvinov
35f3396295 Implement custom ABI decoder 2017-09-06 14:29:52 +02:00
Leonid Logvinov
10817aa337 Add types for web3/lib/solidity/coder.js 2017-09-06 14:29:09 +02:00
Leonid Logvinov
542aae6cd9 Remove abi-decoder 2017-09-06 14:28:29 +02:00
Leonid Logvinov
92eb68bf2c 0.13.0 2017-09-06 13:02:31 +02:00
Leonid Logvinov
aa7d10e510 Update web-typescript-typings 2017-09-06 13:01:33 +02:00
Leonid Logvinov
7377df8a4d Define sendAsync on HDWalletProvider 2017-09-06 13:00:13 +02:00
Leonid Logvinov
70a7f02d0f Fix import in order_validation_utils 2017-09-06 12:51:47 +02:00
Leonid Logvinov
5fb4b54153 Specify the release date 2017-09-06 12:48:47 +02:00
Leonid Logvinov
c64154e33a Add missing separators in CHANGELOG 2017-09-06 10:47:31 +02:00
Leonid
07da617c05 Merge pull request #152 from 0xProject/fix/signature-verification
Add signature verification as a part of order validation
2017-09-06 10:39:43 +02:00
Leonid
35c133caed Merge branch 'development' into fix/signature-verification 2017-09-06 10:35:19 +02:00
Leonid Logvinov
18a52a1ea7 Update CHANGELOG 2017-09-06 10:34:31 +02:00
Leonid Logvinov
501f054d51 Add signature verification as a part of order validation and tests for it 2017-09-06 10:33:34 +02:00
Leonid
f0a5ad2d20 Merge pull request #151 from 0xProject/feature/remove-truffle-contracts
Remove truffle contracts dependency
2017-09-06 10:28:37 +02:00
Leonid Logvinov
258b4fac31 Fix a typo in test name 2017-09-06 10:26:22 +02:00
Leonid Logvinov
8ebc724379 Add lifecycle methods 2017-09-06 00:40:22 +02:00
Leonid Logvinov
df904f80e3 Add test for logs decoding in awaitTransactionMinedAsync 2017-09-06 00:18:07 +02:00
Leonid Logvinov
e6e12e946e Update CHANGELOG 2017-09-05 18:59:46 +02:00
Leonid Logvinov
2fd5f2781b Add forgotten artifacts file 2017-09-05 18:59:18 +02:00
Leonid Logvinov
2f97ddb727 Fix the return types and export the required public types 2017-09-05 18:50:22 +02:00
Leonid Logvinov
a7b2131db7 Decode logs args in awaitTransactionMinedAsync 2017-09-05 18:45:20 +02:00
Leonid Logvinov
f057267955 Update json-schemas 2017-09-05 16:45:40 +02:00
Leonid Logvinov
b0547819fd Define AbiType 2017-09-05 15:44:42 +02:00
Leonid Logvinov
dff63f9b89 Use AbiType 2017-09-05 15:34:52 +02:00
Leonid Logvinov
ee00769be1 Use schema validation to distinguish txData argument 2017-09-05 15:29:29 +02:00
Leonid Logvinov
ec22097efb Don't override function arguments 2017-09-05 13:49:47 +02:00
Leonid Logvinov
bc5fd316df Cast to Artifat type 2017-09-05 13:47:17 +02:00
Leonid Logvinov
92b101fac8 Remove unused code 2017-09-05 13:46:13 +02:00
Leonid Logvinov
78c46d7cc9 Change the order of default overriding 2017-09-05 13:45:32 +02:00
Leonid Logvinov
9f12ef61b0 Rename x.call -> x.callAsync x() -> x.sendTransactionAsync() x.estimateGas() -> x.estimateGasAsync() 2017-09-05 13:43:46 +02:00
Leonid Logvinov
e05dfab1fc Add explaining comment 2017-09-05 13:14:27 +02:00
Leonid Logvinov
b5c6c91962 Increase the default polling interval to 1000 2017-09-05 12:52:44 +02:00
Leonid Logvinov
f6a945dfe4 Fix the comment at awaitTransactionMinedAsync 2017-09-05 12:52:00 +02:00
Leonid Logvinov
a12df1c73a Fix gasPrice regression 2017-09-05 11:38:28 +02:00
Leonid Logvinov
876032a8a7 Update CHANGELOG 2017-09-05 10:42:00 +02:00
Leonid Logvinov
96d2a55eff Add TransationReceipt as a public exported type 2017-09-05 10:29:51 +02:00
Leonid Logvinov
5d57a2f0e9 Increase timeout 2017-09-05 10:22:22 +02:00
Leonid Logvinov
2b547f94a4 Change non-exhange contracts to also return txHash 2017-09-05 10:07:16 +02:00
Leonid Logvinov
c9e490bdae Implement zeroEx.awaitTransactionMined 2017-09-04 19:08:14 +02:00
Leonid Logvinov
6325a03818 Temporarily remove web3_beta, cause it breaks installation and tests 2017-09-04 18:48:18 +02:00
Leonid Logvinov
2577d8f662 Use Web3.ContractInstance type 2017-09-04 18:23:12 +02:00
Leonid Logvinov
1ad395cf86 Make the functions immidiately return txHash instead of awaiting for a transaction to be mined 2017-09-04 18:14:48 +02:00
Leonid Logvinov
1c2d4cbb1a Fix tests descriptions 2017-09-04 16:57:22 +02:00
Leonid Logvinov
9818eb2835 Use custom contract abstraction 2017-09-04 14:45:01 +02:00
Leonid Logvinov
59fed02a8b Remove truffle-contract from deps 2017-09-04 12:07:17 +02:00
Fabio Berger
0275ac9dad Merge pull request #146 from 0xProject/greenkeeper/0x-json-schemas-0.4.0
Update 0x-json-schemas to the latest version 🚀
2017-09-03 10:15:30 +02:00
Leonid Logvinov
62452db5d8 0.12.1 2017-09-02 05:18:31 +02:00
Leonid Logvinov
792646888a Update CHANGELOG version 2017-09-02 05:18:24 +02:00
Leonid Logvinov
cac36e781e 0.12.0 2017-09-02 05:09:38 +02:00
Leonid Logvinov
02f736ac06 Update yarn.lock 2017-09-02 05:08:07 +02:00
Leonid Logvinov
05296b7f48 Update CHANGELOG.md 2017-09-02 05:01:21 +02:00
Leonid
edeed527c2 Merge pull request #148 from BMillman19/bmillman_json_content_type
Add 'content-type' header with value 'application/json' for http requ…
2017-09-01 12:03:34 +02:00
Brandon Millman
4c40b60a2d Add 'content-type' header with value 'application/json' for http requests made JSONRPC endpoints 2017-09-01 00:58:05 -07:00
Leonid
134b9dfb23 Merge pull request #147 from BMillman19/bmillman_contract_types
Fix incorrect types related to contract calls in types.ts
2017-08-31 18:14:36 +02:00
Brandon Millman
18a5f7485c Fix type of ExchangeContract.getOrderHash.call 2017-08-31 08:33:34 -07:00
Brandon Millman
0ff6cc1997 Fix incorrect types related to contract interactions in types.ts 2017-08-31 08:16:28 -07:00
greenkeeper[bot]
66066b9722 fix(package): update 0x-json-schemas to version 0.4.0 2017-08-31 12:37:57 +00:00
Fabio Berger
4620c1c818 Merge branch 'development' of github.com:0xProject/0x.js into development
* 'development' of github.com:0xProject/0x.js:
  Improve the comment
  Add assert.isWeb3Provider
  Use more concise dep pointing
  Don't create whole web3 object in beta tests
  Improve the comment
  Add tests for web3@1.0
  Use zeroEx.getAvailableAddressesAsync instead of web3.eth.getAccounts
  Add web3@1.0 to web3Factory
  Support web3@1.0 providers
  Define web3@1.0 types ;)
  Install web3@1.0.0 as web3_beta
2017-08-30 19:47:14 +02:00
Fabio Berger
4370e19880 update 0x-json-schema 2017-08-30 19:47:04 +02:00
Leonid
5f44b5f711 Merge pull request #142 from 0xProject/feature/support_web3@1.0_provider
Feature/support web3@1.0 provider
2017-08-30 11:24:15 +02:00
Leonid Logvinov
c83e1d57fc Improve the comment 2017-08-30 11:14:01 +02:00
Leonid Logvinov
60ad5024ce Add assert.isWeb3Provider 2017-08-30 11:12:28 +02:00
Leonid Logvinov
5149fcdd74 Use more concise dep pointing 2017-08-30 11:05:23 +02:00
Leonid Logvinov
130a7967aa Don't create whole web3 object in beta tests 2017-08-30 10:56:46 +02:00
Leonid Logvinov
6e34cf2c3b Move CONTRIBUTING and PULL_REQUEST_TEMPLATE to top level 2017-08-30 10:22:47 +02:00
Leonid Logvinov
a98bb1f7ac Improve the comment 2017-08-29 18:45:26 +02:00
Leonid Logvinov
da2661cf33 Add tests for web3@1.0 2017-08-29 18:42:13 +02:00
Leonid Logvinov
7d82d14a7d Use zeroEx.getAvailableAddressesAsync instead of web3.eth.getAccounts 2017-08-29 18:41:29 +02:00
Leonid Logvinov
e5bb3bc75e Add web3@1.0 to web3Factory 2017-08-29 18:41:14 +02:00
Leonid Logvinov
3f99281309 Support web3@1.0 providers 2017-08-29 18:40:49 +02:00
Leonid Logvinov
28b4ff42ea Define web3@1.0 types ;) 2017-08-29 18:39:06 +02:00
Leonid Logvinov
372fc39a6b Install web3@1.0.0 as web3_beta 2017-08-29 17:04:57 +02:00
Leonid
c6b99fcca0 Merge pull request #141 from 0xProject/feature/CONTRIBUTING.md
Add a CONTRIBUTING.md and PULL_REQUEST_TEMPLATE.md
2017-08-29 13:21:22 +02:00
Leonid Logvinov
b4a95428c1 Add a CONTRIBUTING.md and PULL_REQUEST_TEMPLATE.md 2017-08-29 11:11:09 +02:00
Leonid
07a872f802 Merge pull request #139 from 0xProject/feature/gas-price-config
Gas price config
2017-08-29 10:03:00 +02:00
Leonid Logvinov
9516a50f64 Document changes in CHANGELOG 2017-08-29 10:01:53 +02:00
Leonid Logvinov
bfac021085 Use zeroExConfig in tests 2017-08-29 10:01:53 +02:00
Leonid Logvinov
a19b40b051 Pass config object to a constructor instead of gasPrice 2017-08-29 10:01:53 +02:00
Leonid Logvinov
836cea6fd7 Document gasPrice in ZeroExConfig 2017-08-29 10:01:13 +02:00
Leonid Logvinov
66dd659a2f Add ZeroExConfig type to public interface 2017-08-29 10:01:13 +02:00
Leonid Logvinov
c765f115ae Add ZeroExConfig type 2017-08-29 10:01:13 +02:00
Leonid Logvinov
e372b0c61f Fix CHANGELOG message 2017-08-29 10:01:13 +02:00
Leonid Logvinov
0f646da970 Update CHANGELOG 2017-08-29 10:01:13 +02:00
Leonid Logvinov
8eb8037f9b Revert "Add a unit parameter to web3Wrapper.toWei"
This reverts commit 4503c6a09dd9b97fb3b13f0222954b8f1f0db62e.
2017-08-29 10:01:13 +02:00
Leonid Logvinov
5b60d9f0f4 Remove default value for gasPrice 2017-08-29 10:01:13 +02:00
Leonid Logvinov
dcfc0ecac6 Specify gasPrice in WETH tests 2017-08-29 10:01:13 +02:00
Leonid Logvinov
a6a1601799 Allow user to specify the gas price 2017-08-29 10:01:13 +02:00
Leonid Logvinov
a8fd3f30cf Add a unit parameter to web3Wrapper.toWei 2017-08-29 10:01:13 +02:00
Leonid
05ce9733da Merge pull request #140 from 0xProject/0x-json-schemas
Use 0x-json-schemas
2017-08-28 18:01:39 +02:00
Leonid Logvinov
96da2c26dc Use 0x-json-schemas 2017-08-28 16:49:57 +02:00
Leonid Logvinov
0afc95982b Fix UMD tests 2017-08-24 23:23:50 +02:00
Leonid Logvinov
b132860f1f 0.11.0 2017-08-24 22:55:30 +02:00
Leonid Logvinov
f9a8392d2c Add release date for 0.11.0 2017-08-24 22:55:02 +02:00
Leonid
1e590ce4ba Merge pull request #137 from 0xProject/unlimited-allowance
Add setUnlimitedProxyAllowanceAsync and setUnlimitedAllowanceAsync
2017-08-24 22:49:11 +02:00
Leonid Logvinov
bd67cf0f9f Improve comments 2017-08-24 22:48:51 +02:00
Leonid Logvinov
5a3a8ae7d5 Refactor UNLIMITED_ALLOWANCE_IN_BASE_UNITS to constants 2017-08-24 22:48:51 +02:00
Leonid Logvinov
a2d579b201 Add an explanatory comment 2017-08-24 22:48:51 +02:00
Leonid Logvinov
79dcc1660e Add a test that unlimited allowance reduces gas cost 2017-08-24 22:48:51 +02:00
Leonid Logvinov
6f227c152d Add tests for unlimited allowance 2017-08-24 22:48:51 +02:00
Leonid Logvinov
af242278c3 Update CHANGELOG 2017-08-24 22:48:51 +02:00
Leonid Logvinov
9b66b168ed Add setUnlimitedProxyAllowanceAsync and setUnlimitedAllowanceAsync 2017-08-24 22:48:51 +02:00
Leonid Logvinov
9e76b2dd98 Fix test:commonjs 2017-08-24 22:48:51 +02:00
Leonid Logvinov
6d6688ddda Rename build:commonjs:dev to build:commonjs 2017-08-24 22:48:51 +02:00
Leonid Logvinov
2b1dc7c266 0.10.4 2017-08-24 22:48:51 +02:00
Leonid
3e1c436fa6 Merge pull request #136 from 0xProject/commonjs-build
Rename build:commonjs:dev to build:commonjs
2017-08-24 14:06:02 +02:00
Leonid Logvinov
02ae853718 Fix test:commonjs 2017-08-24 13:13:34 +02:00
Leonid Logvinov
b9f9581db9 Rename build:commonjs:dev to build:commonjs 2017-08-24 13:07:55 +02:00
Leonid Logvinov
31ce891beb Merge branch 'master' into development 2017-08-24 12:50:45 +02:00
Leonid Logvinov
6f29239211 0.10.4 2017-08-24 12:46:23 +02:00
Leonid
ea7c6be128 Merge pull request #135 from 0xProject/artifacts-addresses
Artifacts addresses
2017-08-24 12:46:08 +02:00
Leonid Logvinov
b4970d5bb9 Update CHANGELOG 2017-08-24 12:45:44 +02:00
Leonid Logvinov
73b2f59caa Update CHANGELOG 2017-08-24 12:40:16 +02:00
Leonid Logvinov
d92340903f Convert artifacts addresses lo lower case before using 2017-08-24 12:37:21 +02:00
Leonid Logvinov
44ec05de1f 0.10.3 2017-08-24 12:27:20 +02:00
Leonid Logvinov
2356c0e30e Bump the version 2017-08-24 12:24:52 +02:00
Leonid Logvinov
4e517b32f8 0.10.2 2017-08-24 12:01:46 +02:00
Leonid Logvinov
c21a0512af Add v0.10.2 CHANGELOG 2017-08-24 12:01:37 +02:00
Leonid Logvinov
ee4182c149 Hot fix the checksummed addresses in artifacts 2017-08-24 12:00:28 +02:00
Leonid
2d714d33c6 Merge pull request #134 from 0xProject/release-script
Specify tag and other values in the release script
2017-08-24 11:27:23 +02:00
Leonid Logvinov
92cbb48e15 Specify tag and other values in the release script 2017-08-24 11:15:10 +02:00
Leonid Logvinov
f3fe3fb0c5 0.10.1 2017-08-24 11:04:23 +02:00
Leonid Logvinov
dd75f8bf96 Bump patch version due to the publishing issue with 0.10.0 2017-08-24 11:04:13 +02:00
Leonid Logvinov
dcc4b894e0 0.10.0 2017-08-24 10:51:36 +02:00
Leonid
640825d18d Merge pull request #132 from 0xProject/token-registry
Add public Token Registry getters
2017-08-24 10:45:31 +02:00
Leonid Logvinov
933242bd9d Change the unregistered token in tests 2017-08-24 10:05:53 +02:00
Leonid Logvinov
5dce4c3b3b Rename _getTokenByMetadata to _createTokenFromMetadata 2017-08-24 10:04:56 +02:00
Leonid Logvinov
0ba0d2f8d1 Remove redundant else's 2017-08-24 10:02:45 +02:00
Leonid Logvinov
846eec6269 Document changes in a CHANGELOG 2017-08-24 10:00:29 +02:00
Leonid Logvinov
a41ea299e5 Add tests for tokenRegistry public getters 2017-08-24 09:59:10 +02:00
Leonid Logvinov
e4f5b9cdb3 Add all public tokenRegistry functions 2017-08-24 09:59:10 +02:00
Leonid Logvinov
0d7b75801a Add test for getTokenAddressesAsync 2017-08-24 09:59:10 +02:00
Leonid Logvinov
82ef8b19f0 Add zeroEx.tokenRegistry.getTokenAddressesAsync() 2017-08-24 09:59:10 +02:00
Leonid
e216f2ff6d Merge pull request #128 from 0xProject/verifyOrder
Add implementation for public order validation functions
2017-08-24 09:56:34 +02:00
Leonid Logvinov
8d6045c1d5 Add validation for the case where the order is fully filled or canceled and a test 2017-08-24 09:55:02 +02:00
Leonid Logvinov
dc3756bc99 Simplify the validation check for ExchangeContractErrs.OrderAlreadyCancelledOrFilled 2017-08-24 09:55:02 +02:00
Leonid Logvinov
32b2141794 Remove unused var 2017-08-24 09:55:02 +02:00
Leonid Logvinov
1e7a87e2a3 Add newline 2017-08-24 09:55:02 +02:00
Leonid Logvinov
c6e35fbc9d Fix comments 2017-08-24 09:55:02 +02:00
Leonid Logvinov
c7ce966516 Update CHANGELOG 2017-08-24 09:55:02 +02:00
Leonid Logvinov
dd9561797f Fix order validation tests 2017-08-24 09:55:02 +02:00
Leonid Logvinov
5dc32c32a6 Add a comment for isRoundingErrorAsync 2017-08-24 09:55:02 +02:00
Leonid Logvinov
202d619435 Fix isRoundingError name in CHANGELOG 2017-08-24 09:55:01 +02:00
Leonid Logvinov
37676d338e Remove And's from names 2017-08-24 09:55:01 +02:00
Leonid Logvinov
ae1cd90b9a Separate order validation errors tests from exchange tests 2017-08-24 09:55:01 +02:00
Leonid Logvinov
8695f64322 Add the changes to CHANGELOG 2017-08-24 09:55:01 +02:00
Leonid Logvinov
f58c203653 Move order validation functions to orderValidationUtils and make isRoundingError public 2017-08-24 09:55:01 +02:00
Leonid Logvinov
e0a92419e4 Add initial implementation for public order validation functions 2017-08-24 09:55:01 +02:00
Fabio Berger
18f2a93950 Merge pull request #131 from 0xProject/addTokenRegistryMethod
Add public method to TokenRegistry
2017-08-23 18:22:50 +02:00
Fabio Berger
98be786764 rename method for clarity since we return a Token and not tokenMetadata 2017-08-23 18:14:19 +02:00
Fabio Berger
c12e48d28a Add assertion to public method 2017-08-23 18:13:50 +02:00
Fabio Berger
2a7da4fc4f use non-checksummed address 2017-08-23 18:13:26 +02:00
Fabio Berger
bd7102efbe Merge pull request #130 from 0xProject/addProxyAddressMethod
Add public TokenTransferProxy address getter
2017-08-23 17:37:31 +02:00
Fabio Berger
f7010dfa3a Return variable instead of expression 2017-08-23 17:32:10 +02:00
Fabio Berger
8ba3d608c3 Add PR numbers to changelog items 2017-08-23 17:30:53 +02:00
Fabio Berger
fedded3ec1 Add public method getTokenMetadataIfExistsAsync to TokenRegistry wrapper, refactor getTokensAsync to use getTokenMetadataIfExistsAsync under the hood and added unit tests 2017-08-23 17:27:54 +02:00
Fabio Berger
e4393fdd09 Add note about the added public method in CHANGELOG 2017-08-23 17:02:48 +02:00
Fabio Berger
e3f7b18deb Add getContractAddressAsync public method to proxy instance 2017-08-23 17:01:45 +02:00
Fabio Berger
9dca3b76b5 rename proxy_wrapper_test to token_transfer_proxy_wrapper_test 2017-08-23 16:58:56 +02:00
Leonid
d837e27739 Merge pull request #127 from 0xProject/shouldThrowOnInsufficientBalanceOrAllowance
Fix the docs for shouldThrowOnInsufficientBalanceOrAllowance
2017-08-23 14:42:45 +02:00
Leonid Logvinov
894ade168d Rename shouldCheckTransfer to shouldThrowOnInsufficientBalanceOrAllowance in tests 2017-08-22 16:15:10 +02:00
Leonid Logvinov
df274591f7 Update CHANGELOG 2017-08-22 15:20:10 +02:00
Leonid Logvinov
b809839ed4 Fix the docs for shouldThrowOnInsufficientBalanceOrAllowance 2017-08-22 15:17:36 +02:00
Leonid
51f2c46ed0 Merge pull request #126 from 0xProject/token-transfer-proxy-rename
Rename internally Proxy to TokenTransferProxy
2017-08-22 13:38:41 +02:00
Leonid Logvinov
b2b5abadb2 Rename internally Proxy to TokenTransferProxy 2017-08-22 13:28:05 +02:00
Leonid
0bc9083bff Merge pull request #124 from 0xProject/reject-checksummed-addresses
Reject checksummed addresses
2017-08-22 13:27:40 +02:00
Leonid Logvinov
4207400f8a Fix merge conflicts in a changelog 2017-08-22 11:11:33 +02:00
Leonid Logvinov
40f4ccd888 Include variableName in error message for checksummed address 2017-08-22 11:10:54 +02:00
Leonid Logvinov
c10a2d4fe4 Put the last test address on it's own line 2017-08-22 11:08:45 +02:00
Leonid Logvinov
45aa9ef542 Change CHANGELOG text 2017-08-22 11:02:28 +02:00
Leonid Logvinov
f77cc87271 Use lowercase address in tests 2017-08-22 11:02:13 +02:00
Leonid Logvinov
40ce3a9c06 Update CHANGELOG.md 2017-08-22 11:02:13 +02:00
Leonid Logvinov
52ac8c2251 Reject checksummed addresses 2017-08-22 11:00:44 +02:00
Leonid Logvinov
e376189bc6 0.9.3 2017-08-22 10:42:32 +02:00
Leonid
2a8c42688e Merge pull request #125 from 0xProject/0.9.3
Update CHANGELOG.md
2017-08-22 10:41:25 +02:00
Leonid Logvinov
b2fc0abdfb Update CHANGELOG.md 2017-08-22 10:40:00 +02:00
Fabio Berger
ac03cbbd48 Merge branch 'master' of github.com:0xProject/0x.js
* 'master' of github.com:0xProject/0x.js:
  Add subproviders to the list of folders required by UMD tests
2017-08-21 18:21:52 +02:00
Leonid Logvinov
87e0fe43f7 Add subproviders to the list of folders required by UMD tests 2017-08-21 18:10:18 +02:00
Fabio Berger
b2f5fc218d 0.9.2 2017-08-21 17:32:37 +02:00
Fabio Berger
984f9e1201 Merge branch 'master' of github.com:0xProject/0x.js
* 'master' of github.com:0xProject/0x.js:
  try 4000 timeout
  try longer timeout
2017-08-21 17:32:21 +02:00
Fabio Berger
be354d703a Update changelog 2017-08-21 17:31:52 +02:00
Fabio Berger
1ff24f0338 Merge pull request #123 from 0xProject/fixCi
Increase test timeout
2017-08-21 17:26:24 +02:00
Fabio Berger
798620d0ef try 4000 timeout 2017-08-21 17:19:13 +02:00
Fabio Berger
13d7037e8a try longer timeout 2017-08-21 17:14:49 +02:00
Fabio Berger
01eed19abd Update testrpc snapshot and testrpc artifacts 2017-08-21 14:44:41 +02:00
Fabio Berger
1311dfe7f5 Update artifacts and rename proxy to tokenTransferProxy 2017-08-21 07:20:06 -05:00
Fabio Berger
dd6997423f Merge pull request #118 from 0xProject/artifacts-update
Update artifacts with the latest mainnet version
2017-08-21 07:02:50 -05:00
Leonid Logvinov
69668d07c1 0.9.1 2017-08-16 23:26:44 -05:00
Leonid Logvinov
f2ff14f500 Update CHANGELOG.md before v0.9.1 2017-08-16 23:26:21 -05:00
Leonid
c394073653 Merge pull request #120 from 0xProject/addTestWithWeb3WithoutAddresses
Remove unnecessary assertions & add regression tests
2017-08-16 23:23:32 -05:00
Leonid Logvinov
b95d93a43b Add JSONRPCPayload type and remove unused import 2017-08-16 23:22:24 -05:00
Fabio Berger
b5bfcc772a set default value to hasAddresses boolean 2017-08-16 21:06:41 -07:00
Fabio Berger
20045a438a remove unnecessary assertion and add regression test 2017-08-16 15:44:39 -07:00
Fabio Berger
2e668a771a remove unneeded assertion from _isRoundingErrorAsync since one can make static calls without an available address 2017-08-16 15:44:20 -07:00
Fabio Berger
a32b94bac4 Remove isUserAddressAvailable assertion from getBalanceAsync and add regression test 2017-08-16 15:34:09 -07:00
Fabio Berger
6ec3c8728e Update yarn.lock 2017-08-16 15:18:11 -07:00
Leonid Logvinov
9099ef4ee5 Remove url from token registry 2017-08-14 19:32:41 -05:00
Leonid Logvinov
c4dfda9485 Update testrpc artifacts 2017-08-14 19:32:03 -05:00
Leonid Logvinov
9979e6796b Update contracts snapshot hash 2017-08-14 19:08:43 -05:00
Leonid Logvinov
6f93583d41 --no-edit 2017-08-14 18:55:42 -05:00
Leonid Logvinov
a7924cef04 Update Exchange artifacts and adjust ExchangeWrapper 2017-08-14 18:46:38 -05:00
Leonid Logvinov
23e3546073 Update TokenRegistry artifacts 2017-08-14 18:24:12 -05:00
Leonid Logvinov
52e88a63b9 Update EtherToken artifacts 2017-08-14 18:09:52 -05:00
Leonid Logvinov
a44375a6fc Update Token artifacts 2017-08-14 18:08:40 -05:00
Leonid Logvinov
fa65bcc115 Remove Mintable artifacts 2017-08-14 18:08:00 -05:00
Leonid
1c553cb6b7 Merge pull request #117 from 0xProject/greenkeeper/sinon-3.0.0
Update sinon to the latest version 🚀
2017-08-04 16:39:00 +02:00
greenkeeper[bot]
36d5510d07 chore(package): update sinon to version 3.0.0 2017-08-03 14:40:25 +00:00
Leonid
617ca799c5 Merge pull request #116 from 0xProject/greenkeeper/typedoc-0.8.0
Update typedoc to the latest version 🚀
2017-07-28 09:35:40 +02:00
greenkeeper[bot]
42a5de1ec1 chore(package): update typedoc to version 0.8.0 2017-07-27 17:22:34 +00:00
Leonid Logvinov
d175009d55 Add PR links to CHANGELOG.md 2017-07-26 17:53:20 +02:00
Leonid Logvinov
7f58a778d8 0.9.0 2017-07-26 17:26:16 +02:00
Leonid Logvinov
b3601fc7bc Add release date for 0.9.0 2017-07-26 17:26:07 +02:00
Leonid
ac92ebc54f Merge pull request #115 from 0xProject/pre-0.9.0-CHANGELOG
Update CHANGELOG.md
2017-07-26 17:24:53 +02:00
Leonid Logvinov
ea2317be11 Update CHANGELOG.md 2017-07-26 17:14:09 +02:00
Leonid Logvinov
a89e9461b6 Merge branch 'greenkeeper/web3-typescript-typings-0.3.0' 2017-07-26 17:05:54 +02:00
Leonid Logvinov
fffc807823 Update yarn.lock 2017-07-26 17:04:08 +02:00
Leonid
da97be645b Merge pull request #114 from 0xProject/greenkeeper/web3-typescript-typings-0.3.0
Update web3-typescript-typings to the latest version 🚀
2017-07-26 15:42:22 +02:00
greenkeeper[bot]
028a9a4880 chore(package): update web3-typescript-typings to version 0.3.0 2017-07-26 13:31:18 +00:00
Leonid
89aa19f6e4 Merge pull request #109 from 0xProject/fees-balance-allowance-validation
Fees balance allowance validation
2017-07-25 22:26:14 +02:00
Leonid Logvinov
660aa224ca Indent callbacks 2017-07-25 22:25:57 +02:00
Leonid Logvinov
c6e0acdb04 Rearrange imports 2017-07-25 22:25:57 +02:00
Leonid Logvinov
1690aae1cf Simplify order checks 2017-07-25 22:25:56 +02:00
Leonid Logvinov
4d27b89fe3 Store tokenWrapper inside of OrdervalidationUtils 2017-07-25 22:25:56 +02:00
Leonid Logvinov
31d068b83f Remove and from names 2017-07-25 22:25:56 +02:00
Leonid Logvinov
73e8f890b5 Remove unused imports 2017-07-25 22:25:56 +02:00
Leonid Logvinov
c11ba988c7 Fix tests 2017-07-25 22:25:56 +02:00
Leonid Logvinov
4dda6c0949 Factor out order validation tests 2017-07-25 22:25:56 +02:00
Leonid Logvinov
defd09459d Cover all possible branches of order validation errors with tests 2017-07-25 22:25:56 +02:00
Leonid Logvinov
58d2b799d6 Refactor OrderValidationUtils to check for the case when ZRX is one of the tokens traded 2017-07-25 22:25:56 +02:00
Leonid Logvinov
d9a8b96154 Pass tokenWrapper to validateFillOrderBalancesAndAllowancesAndThrowIfInvalidAsync 2017-07-25 22:25:56 +02:00
Leonid Logvinov
c7d89d98f3 Move _validateFillOrderBalancesAndAllowancesAndThrowIfInvalidAsync to orderValidationUtils 2017-07-25 22:25:56 +02:00
Leonid Logvinov
bdbd01f965 Add a test: should throw when maker has balance to cover fees or transfer but not both 2017-07-25 22:25:56 +02:00
Leonid
97e680aba1 Merge pull request #113 from 0xProject/ethereumjs-util-types
Add ethereumjs-utils types
2017-07-21 15:48:14 -07:00
Leonid Logvinov
64f4a276ff Add ethereumjs-utils types 2017-07-21 15:42:42 -07:00
Leonid
5d31d43cf8 Merge pull request #112 from 0xProject/bn.js-types
Add bn.js types
2017-07-21 15:39:23 -07:00
Leonid Logvinov
f7fac34e03 Add bn.js types 2017-07-21 15:34:47 -07:00
Leonid
569cff01f3 Merge pull request #108 from 0xProject/greenkeeper/web3-0.20.0
Update web3 to the latest version 🚀
2017-07-18 15:02:06 -07:00
Leonid
d741fe5f1b Merge pull request #110 from 0xProject/greenkeeper/web3-typescript-typings-0.2.1
Update web3-typescript-typings to the latest version 🚀
2017-07-18 10:22:08 -07:00
greenkeeper[bot]
106e096304 chore(package): update web3-typescript-typings to version 0.2.1 2017-07-18 16:42:09 +00:00
greenkeeper[bot]
745bdb6c3f fix(package): update web3 to version 0.20.0 2017-07-17 10:01:33 +00:00
Leonid
5fe128ccf6 Merge pull request #104 from 0xProject/ts-2.4
Update to typescript@2.4
2017-07-11 18:22:22 -07:00
Leonid Logvinov
41f0be48f1 Use actual exception values in test names 2017-07-11 18:21:12 -07:00
Leonid Logvinov
b376f03102 Add a comment explaining any 2017-07-11 18:12:35 -07:00
Leonid Logvinov
468c95a4c2 Add forgotten meger conflict resolution 2017-07-11 18:00:17 -07:00
Leonid Logvinov
6033c1a5d5 Use PascalCase names as string enum keys 2017-07-11 17:54:57 -07:00
Leonid Logvinov
38fbf028a6 Migrate to using native string enums 2017-07-11 17:46:24 -07:00
Leonid Logvinov
ef88c71b27 Update to typescript@2.4 2017-07-11 17:46:24 -07:00
Leonid
89236fff41 Merge pull request #107 from 0xProject/static-get-order-hash-hex
Static get order hash hex
2017-07-11 17:45:46 -07:00
Leonid Logvinov
6c62c92f0c Reformat CHANGELOG to use past tense 2017-07-11 17:45:35 -07:00
Leonid Logvinov
c05737e7a6 Update CHANGELOG.md 2017-07-11 17:45:35 -07:00
Leonid Logvinov
fbf89aea1c Make getOrderHashHex static 2017-07-11 17:45:35 -07:00
Leonid
98e8a6dd70 Merge pull request #106 from 0xProject/single-exchange
Single exchange
2017-07-11 17:44:24 -07:00
Leonid Logvinov
4efba2a4bc Fix the comment 2017-07-11 17:40:37 -07:00
Leonid Logvinov
d8fb58379e Update CHANGELOG.md 2017-07-11 16:15:08 -07:00
Leonid Logvinov
8052625e76 Migrate to using a single Exchange contract 2017-07-11 16:15:08 -07:00
Leonid Logvinov
2787bdc46b Remove exchange artifacts by name 2017-07-11 16:15:08 -07:00
Leonid Logvinov
ba46a2558d Flatten artifacts 2017-07-11 16:15:08 -07:00
Leonid
9bb14a1d69 Merge pull request #105 from 0xProject/chai-bignumber
Stop using custom chai-bignumber fork
2017-07-11 13:17:44 -07:00
Leonid Logvinov
aa344d268c Stop using custom chai-bignumber fork 2017-07-11 13:17:27 -07:00
Leonid
2ab2ad5902 Merge pull request #103 from 0xProject/jsonschema-types
Jsonschema types
2017-07-11 13:16:02 -07:00
Leonid
5506f7a240 Add the source for the schema 2017-07-11 13:14:23 -07:00
Leonid Logvinov
c832cc35cc Use custom Schema types 2017-07-11 10:51:22 -07:00
Leonid Logvinov
232bf22af6 Add jsonschema Schema declaration 2017-07-11 10:49:29 -07:00
Fabio Berger
2a15fe0ffe Merge pull request #101 from 0xProject/new-contracts
Migrate to using a new Exchange contract
2017-07-11 00:33:54 -07:00
Fabio Berger
56bedf724f Merge branch 'new-contracts'
* new-contracts: (29 commits)
  Fix a typo
  Fix a typo in comment
  Rename shouldCheckTransfer to shouldThrowOnInsufficientBalanceOrAllowance
  Simplify BigNumber hack
  use yarn on CI
  Upgrade to a new node version
  Make CONTRACTS_COMMIT_HASH a string
  Use never testrpc snapshot
  Migrate the rest of the artifacts
  Change arguments order at isRoundingError
  Migrate events
  Migrate constructor arguments
  Migrate fillOrKillOrder
  Migrate ZRX_TOKEN_AMOUNT
  Migrate getUnavailableTakerTokenAmount
  Migrate PROXY_CONTRACT
  Migrate batchFillOrKillOrders
  Migrate batchFillOrders
  Migrate fillOrder
  Migrate fillOrdersUpTo and remove min
  ...
2017-07-11 00:30:55 -07:00
Leonid Logvinov
054843d599 Fix a typo 2017-07-11 00:30:14 -07:00
Leonid Logvinov
e54e9dfa2c Fix a typo in comment 2017-07-11 00:30:14 -07:00
Leonid Logvinov
987d7a7d8a Rename shouldCheckTransfer to shouldThrowOnInsufficientBalanceOrAllowance 2017-07-11 00:30:14 -07:00
Leonid Logvinov
183ea1b33d Simplify BigNumber hack 2017-07-11 00:30:14 -07:00
Leonid Logvinov
994b51590f use yarn on CI 2017-07-11 00:30:14 -07:00
Leonid Logvinov
4fb2b5cf2b Upgrade to a new node version 2017-07-11 00:30:14 -07:00
Leonid Logvinov
e7bb280d67 Make CONTRACTS_COMMIT_HASH a string 2017-07-11 00:30:14 -07:00
Leonid Logvinov
3d974854bc Use never testrpc snapshot 2017-07-11 00:30:14 -07:00
Leonid Logvinov
48314941bd Migrate the rest of the artifacts 2017-07-11 00:30:14 -07:00
Leonid Logvinov
23ca4047f3 Change arguments order at isRoundingError 2017-07-11 00:30:14 -07:00
Leonid Logvinov
a8c9945a0f Migrate events 2017-07-11 00:30:14 -07:00
Leonid Logvinov
be1f7db2df Migrate constructor arguments 2017-07-11 00:30:14 -07:00
Leonid Logvinov
722c24d127 Migrate fillOrKillOrder 2017-07-11 00:30:14 -07:00
Leonid Logvinov
720b2a2506 Migrate ZRX_TOKEN_AMOUNT 2017-07-11 00:30:14 -07:00
Leonid Logvinov
79762a2e38 Migrate getUnavailableTakerTokenAmount 2017-07-11 00:30:14 -07:00
Leonid Logvinov
89167c8297 Migrate PROXY_CONTRACT 2017-07-11 00:30:14 -07:00
Leonid Logvinov
dffc047f56 Migrate batchFillOrKillOrders 2017-07-11 00:30:14 -07:00
Leonid Logvinov
7cbd408c24 Migrate batchFillOrders 2017-07-11 00:30:14 -07:00
Leonid Logvinov
b774a9f91c Migrate fillOrder 2017-07-11 00:30:14 -07:00
Leonid Logvinov
5a8297649f Migrate fillOrdersUpTo and remove min 2017-07-11 00:30:14 -07:00
Leonid Logvinov
540ac54dee Migrate batchCancelOrders 2017-07-11 00:30:14 -07:00
Leonid Logvinov
caaad46991 Migrate getPartialAmount 2017-07-11 00:30:14 -07:00
Leonid Logvinov
4ecfac6cb4 Migrate cencelOrder 2017-07-11 00:30:14 -07:00
Leonid Logvinov
00c1198b34 Revert "Migrate isRoundingError parameter changes"
This reverts commit 9a200c67210599faf5eb735893abae99f72a4d1f.
2017-07-11 00:30:14 -07:00
Leonid Logvinov
15f68f9b54 Revert "Rename ZRX to ZRX_TOKEN_CONTRACT"
This reverts commit 6f0b8a185b6fcf58b7427fb907599dbc82c10eaf.
2017-07-11 00:30:14 -07:00
Leonid Logvinov
dce13796ac Update binaries and timestamps 2017-07-11 00:30:14 -07:00
Leonid Logvinov
197e38adae Migrate isRoundingError parameter changes 2017-07-11 00:30:14 -07:00
Leonid Logvinov
c21c322056 Rename ZRX to ZRX_TOKEN_CONTRACT 2017-07-11 00:30:14 -07:00
Leonid Logvinov
15fe8afd1e Add contracts artifacts for contracts that didn't change 2017-07-11 00:30:14 -07:00
Leonid Logvinov
dc70e3522a Fix a typo 2017-07-10 19:24:09 -07:00
Leonid Logvinov
2b7b9c8f8b Fix a typo in comment 2017-07-10 18:58:05 -07:00
Leonid Logvinov
8180225d1f Rename shouldCheckTransfer to shouldThrowOnInsufficientBalanceOrAllowance 2017-07-10 18:55:01 -07:00
Leonid
b98f3fc094 Merge pull request #102 from 0xProject/greenkeeper/dirty-chai-2.0.1
Update dirty-chai to the latest version 🚀
2017-07-10 10:28:17 -07:00
greenkeeper[bot]
18ab31814f chore(package): update dirty-chai to version 2.0.1 2017-07-10 14:09:09 +00:00
Leonid Logvinov
643a7e6b3a Simplify BigNumber hack 2017-07-07 18:35:07 -07:00
Leonid Logvinov
baa7668cda use yarn on CI 2017-07-07 18:34:56 -07:00
Leonid Logvinov
48a79a8488 Upgrade to a new node version 2017-07-07 18:34:42 -07:00
Leonid Logvinov
c975094df0 Make CONTRACTS_COMMIT_HASH a string 2017-07-07 17:45:41 -07:00
Leonid Logvinov
6e598792cd Use never testrpc snapshot 2017-07-07 17:45:41 -07:00
Leonid Logvinov
b0eb6efaae Migrate the rest of the artifacts 2017-07-07 17:45:40 -07:00
Leonid Logvinov
9bfe0c2090 Change arguments order at isRoundingError 2017-07-07 17:45:40 -07:00
Leonid Logvinov
c522cd5020 Migrate events 2017-07-07 17:45:40 -07:00
Leonid Logvinov
1441d1098f Migrate constructor arguments 2017-07-07 17:45:40 -07:00
Leonid Logvinov
1f9710590a Migrate fillOrKillOrder 2017-07-07 17:45:40 -07:00
Leonid Logvinov
cf6efc6596 Migrate ZRX_TOKEN_AMOUNT 2017-07-07 17:45:40 -07:00
Leonid Logvinov
8d53c78661 Migrate getUnavailableTakerTokenAmount 2017-07-07 17:45:40 -07:00
Leonid Logvinov
d21ef4db82 Migrate PROXY_CONTRACT 2017-07-07 17:45:40 -07:00
Leonid Logvinov
1aaa0020d0 Migrate batchFillOrKillOrders 2017-07-07 17:45:40 -07:00
Leonid Logvinov
53b38105dd Migrate batchFillOrders 2017-07-07 17:45:40 -07:00
Leonid Logvinov
6f9a14929b Migrate fillOrder 2017-07-07 17:45:39 -07:00
Leonid Logvinov
f92b0e918e Migrate fillOrdersUpTo and remove min 2017-07-07 17:45:39 -07:00
Leonid Logvinov
e2696c259b Migrate batchCancelOrders 2017-07-07 17:45:39 -07:00
Leonid Logvinov
406763ff61 Migrate getPartialAmount 2017-07-07 17:45:39 -07:00
Leonid Logvinov
f3e66110be Migrate cencelOrder 2017-07-07 17:45:39 -07:00
Leonid Logvinov
bc300a3797 Revert "Migrate isRoundingError parameter changes"
This reverts commit 9a200c67210599faf5eb735893abae99f72a4d1f.
2017-07-07 17:45:39 -07:00
Leonid Logvinov
049a3be102 Revert "Rename ZRX to ZRX_TOKEN_CONTRACT"
This reverts commit 6f0b8a185b6fcf58b7427fb907599dbc82c10eaf.
2017-07-07 17:45:39 -07:00
Leonid Logvinov
b21a02424c Update binaries and timestamps 2017-07-07 17:45:39 -07:00
Leonid Logvinov
1e54dec280 Migrate isRoundingError parameter changes 2017-07-07 17:45:39 -07:00
Leonid Logvinov
1d8ca6c4f3 Rename ZRX to ZRX_TOKEN_CONTRACT 2017-07-07 17:45:38 -07:00
Leonid Logvinov
db888912d0 Add contracts artifacts for contracts that didn't change 2017-07-07 17:45:38 -07:00
Leonid Logvinov
305b98ee21 Merge branch 'master' of github.com:0xProject/0x.js 2017-07-07 17:43:52 -07:00
Leonid Logvinov
39daf6f963 Update yarn.lock to include latest webpack version 2017-07-07 17:43:44 -07:00
Fabio Berger
6b80134f48 Merge pull request #100 from 0xProject/improveSignOrder
Improve signOrderHashAsync
2017-07-07 17:43:31 -07:00
Leonid Logvinov
d5b4032b25 Add --bail option to mocha run command 2017-07-07 16:34:11 -07:00
Fabio Berger
68120ad1da Move private helper methods into signatureUtils so that they don't show up in the ZeroEx classes auto-complete list 2017-07-07 14:21:47 -07:00
Leonid
3eb21a76c1 Merge pull request #95 from 0xProject/cache_net_version
Cache `net_version` requests
2017-07-07 14:21:25 -07:00
Leonid Logvinov
73a48ddb0d Refactor net_version caching logic 2017-07-07 14:21:00 -07:00
Fabio Berger
bdfbfb829b Remove duplication of 27, 28 v values 2017-07-07 14:20:59 -07:00
Leonid
0876fc6cab Merge branch 'master' into cache_net_version 2017-07-07 14:08:34 -07:00
Leonid
6593ddf35c Merge pull request #97 from 0xProject/speedup-tests
Paralellize fill scenarios
2017-07-07 14:07:41 -07:00
Leonid
23f32b6bba Add noop comment 2017-07-07 14:07:26 -07:00
Leonid
f7515b489d Merge pull request #98 from 0xProject/typos
Typos
2017-07-07 13:58:26 -07:00
Leonid
33f713e0cc Merge pull request #99 from 0xProject/greenkeeper/web3-typescript-typings-0.0.11
Update web3-typescript-typings to the latest version 🚀
2017-07-07 13:58:14 -07:00
Fabio Berger
712a1ba36e Modify signOrderHashAsync to parse the signatureHex string as V + R + S AND R + S + V and check both for a valid signature in order to fix the issue of different nodes returning it differently 2017-07-07 13:49:02 -07:00
Fabio Berger
e9509b4ff3 Remove space after it keywork in tests 2017-07-07 11:50:23 -07:00
greenkeeper[bot]
014a458525 chore(package): update web3-typescript-typings to version 0.0.11 2017-07-07 18:10:54 +00:00
Leonid Logvinov
b46d7f9cca Update CHANGELOG.md 2017-07-07 10:56:47 -07:00
Leonid Logvinov
96596b1c2b Rename batchCancelOrderAsync to batchCancelOrdersAsync 2017-07-07 10:31:22 -07:00
Leonid Logvinov
c0a90fe84e Rename batchFillOrderAsync to batchFillOrdersAsync 2017-07-07 10:31:02 -07:00
Leonid Logvinov
198cd364db Paralellize fill scenarios 2017-07-07 09:58:56 -07:00
Leonid
03a6e1dac5 Merge pull request #96 from 0xProject/greenkeeper/webpack-3.1.0
Update webpack to the latest version 🚀
2017-07-07 09:56:41 -07:00
Leonid Logvinov
90ddfe58a9 Rename networkId to networkIdIfExists 2017-07-06 15:43:35 -07:00
Leonid Logvinov
0f3f557e0b Fix a typo in a filename 2017-07-06 15:42:00 -07:00
Leonid Logvinov
21cb428b38 Rename RPC_NETWORK_ID to TESTRPC_NETWORK_ID 2017-07-06 15:41:27 -07:00
Leonid Logvinov
de76ed478f Fix CHANGELOG.md comment 2017-07-06 15:40:32 -07:00
Leonid Logvinov
2ad6a64664 Remove only 2017-07-06 15:23:55 -07:00
Leonid Logvinov
092e0c4273 Update CHANGELOG.md 2017-07-06 15:20:39 -07:00
Leonid Logvinov
e19c222f30 Add tests for networkId caching and invalidation 2017-07-06 15:18:56 -07:00
Leonid Logvinov
8b88ad835c Cache networkId in web3Wrapper 2017-07-06 15:18:56 -07:00
greenkeeper[bot]
afc12ac497 chore(package): update webpack to version 3.1.0 2017-07-06 22:13:48 +00:00
Leonid
18050b7ea3 Merge pull request #94 from 0xProject/moveExchangeAddressGetters
Moves exchange contract address getters to zeroEx top level
2017-07-06 14:51:44 -07:00
Leonid Logvinov
9f89dbc8e4 Inline _isExchangeContractAddressProxyAuthorizedAsync 2017-07-06 10:19:22 -07:00
Leonid Logvinov
b1667cdd89 Fix comments to use web3 provider instead of web3 instance 2017-07-06 10:18:38 -07:00
Leonid Logvinov
87f2658fc9 Update CHANGELOG.md 2017-07-05 14:22:23 -07:00
Leonid Logvinov
9a9fd7d926 Move zeroEx.exchange.getAvailableContractAddressesAsync to zeroEx.getAvailableExchangeContractAddressesAsync and zeroEx.exchange.getProxyAuthorizedContractAddressesAsync to zeroEx.getProxyAuthorizedExchangeContractAddressesAsync 2017-07-05 14:18:46 -07:00
Leonid Logvinov
f2611d5b2b 0.8.0 2017-07-04 19:00:55 -07:00
Leonid Logvinov
370b82ee18 Add publish date for 0.8.0 in CHANGELOG.md 2017-07-04 19:00:12 -07:00
Leonid
74b2308488 Merge pull request #90 from 0xProject/subscribe-token
Add implementation and tests for zeroEx.token.subscribeAsync
2017-07-04 18:17:57 -07:00
Leonid Logvinov
371acc0ba1 Merge branch 'master' into subscribe-token 2017-07-04 17:55:08 -07:00
Leonid Logvinov
3302d18f6e Run umd tests only on master 2017-07-04 17:54:31 -07:00
Leonid Logvinov
d6595f171a Add order hash schema 2017-07-04 17:49:25 -07:00
Leonid Logvinov
61a6040e74 Merge branch 'master' into subscribe-token 2017-07-04 17:44:32 -07:00
Leonid
c81855e119 Merge pull request #93 from 0xProject/testrpc-snapshot
Testrpc snapshots
2017-07-04 17:43:42 -07:00
Leonid Logvinov
db53c5a41f Rename CONTRACTS_COMMIT to CONTRACTS_COMMIT_HASH 2017-07-04 17:43:30 -07:00
Leonid Logvinov
9c4f3b2cba Rearrange methods in event utils 2017-07-04 17:37:02 -07:00
Leonid Logvinov
4cb544f4f5 Add underscore in front of _getBigNumberWrappingEventCallback 2017-07-04 17:36:33 -07:00
Leonid Logvinov
6f73589d40 Use string template 2017-07-04 17:35:51 -07:00
Leonid Logvinov
ea6583d47e Make all fields of subscriptionOpts schema optional 2017-07-04 17:35:02 -07:00
Leonid Logvinov
464c16be73 move order hash schema to a separate file 2017-07-04 17:33:35 -07:00
Leonid Logvinov
4d522db474 Fix CHANGELOG entry 2017-07-04 17:21:14 -07:00
Leonid Logvinov
33494c2206 Change prepublish to prepublishOnly 2017-07-04 16:38:57 -07:00
Leonid Logvinov
ea2dbaabeb Use testrpc snapshots in tests 2017-07-04 16:30:55 -07:00
Leonid
8f8b678e7c Change gitter link badge to 0xproject/Lobby 2017-07-04 13:51:44 -07:00
Leonid
5f62aed80a Add npm version badge 2017-07-04 12:47:13 -07:00
Leonid Logvinov
82c1d7ca7c Add exchangeContractAddress to an order in schema tests 2017-07-04 12:29:14 -07:00
Leonid Logvinov
e570ad28dd Fix order schema (add exchangeContractAddress) 2017-07-04 11:59:08 -07:00
Leonid Logvinov
a45f6ff4af Fix the bug when didn't invalidate etherToken contract instance 2017-07-04 11:48:41 -07:00
Leonid Logvinov
74e991db94 Update CHANGELOG.md 2017-07-04 11:36:22 -07:00
Leonid Logvinov
33216ea53f Make this.proxy.invalidateContractInstance and this.tokenRegistry.invalidateContractInstance private 2017-07-04 11:22:12 -07:00
Leonid Logvinov
4ebf046cea Make invalidateContractInstancesAsync private on exchange and token 2017-07-04 11:12:56 -07:00
Leonid Logvinov
43bebf6d61 Add parameter validation for subscribeAsync 2017-07-04 11:06:13 -07:00
Leonid Logvinov
40d1d30b58 Add assert.doesBelongToStringEnum 2017-07-04 10:59:11 -07:00
Leonid Logvinov
196194c04a Add StringEnum type 2017-07-04 10:58:36 -07:00
Leonid Logvinov
c5dca95f89 Use .bignumber for BigNumber comparation 2017-07-04 10:31:07 -07:00
Leonid Logvinov
b1c7291d3c Use orderHashSchema to validate order hash 2017-07-04 10:27:31 -07:00
Leonid Logvinov
5611df82f9 Refactor event tests 2017-07-04 10:26:43 -07:00
Leonid Logvinov
f39a2134b9 Add tests for order hash Schema 2017-07-04 10:05:45 -07:00
Leonid Logvinov
551b6db35e Add orderHashSchema 2017-07-03 22:31:59 -07:00
Leonid Logvinov
64cf47f297 Add tests for subscriptionOptsSchema and blockParamSchema 2017-07-03 21:59:42 -07:00
Leonid Logvinov
7d7bef2b1a Handle errors from pseudo-async subscription tests 2017-07-03 18:26:31 -07:00
Leonid Logvinov
7b24809698 Register new schemas within schema validator 2017-07-03 18:24:11 -07:00
Leonid Logvinov
ca92502d34 Add index_filter_values_schema.ts and subscription_opts_schema.ts 2017-07-03 18:23:35 -07:00
Leonid Logvinov
12b71b20f0 Make IndexedFilterValues type scricter 2017-07-03 16:54:08 -07:00
Leonid Logvinov
90f99e48e1 Add CHANGELOG.md entry 2017-07-03 16:50:24 -07:00
Leonid Logvinov
4fae4b4493 Fix comments 2017-07-03 16:49:37 -07:00
Leonid
6d234c09af Merge branch 'master' into subscribe-token 2017-07-03 16:37:15 -07:00
Leonid
2892f45ab7 Merge pull request #89 from 0xProject/proxy
Add zeroEx.proxy
2017-07-03 16:24:22 -07:00
Leonid Logvinov
e6fcf9cdbf Use call instead of use in the comments 2017-07-03 16:24:10 -07:00
Leonid
997964f3e2 Merge pull request #87 from 0xProject/wrap-log-bignumber
Wrap all event args in a newer version of BigNumber and test it
2017-07-03 16:13:16 -07:00
Leonid Logvinov
4633637efe Fix the comment 2017-07-03 16:11:37 -07:00
Leonid Logvinov
5a8eb77ff0 Add initial implementation and tests for zeroEx.token.subscribeAsync 2017-07-03 15:54:05 -07:00
Leonid Logvinov
99051bdfdf Bump the minor version in CHANGELOG.md 2017-07-03 15:13:35 -07:00
Leonid Logvinov
20f630d1ae Update CHANGELOG.md 2017-07-03 15:05:21 -07:00
Leonid Logvinov
1275f243a3 Add zeroEx.proxy.getAuthorizedAddressesAsync and tests 2017-07-03 15:03:33 -07:00
Leonid Logvinov
dacf19ecae Make proxy wrapper public on zeroEx instance 2017-07-03 14:48:11 -07:00
Leonid Logvinov
c9edeae6d8 Rename _wrapEventCallback to _getBigNumberWrappingEventCallback 2017-07-03 14:41:50 -07:00
Leonid Logvinov
3a4a3b9aa1 Fix merge problems 2017-07-03 14:35:13 -07:00
Leonid
86c742cb11 Merge branch 'master' into wrap-log-bignumber 2017-07-03 14:31:40 -07:00
Leonid Logvinov
92c6144b6a Check for a BigNumber instance 2017-07-03 14:26:48 -07:00
Leonid
d4cef89587 Merge pull request #82 from 0xProject/add-exchange-address-to-order-struct
Allow multiple Exchange contracts and multiple artifacts
2017-07-03 12:28:34 -07:00
Leonid Logvinov
8151523d33 Use _.isString instead of instanceof 2017-07-03 12:08:14 -07:00
Leonid
8204409c6d Merge branch 'master' into add-exchange-address-to-order-struct 2017-07-03 12:05:46 -07:00
Leonid Logvinov
4bcad26024 Stop passing exchangeContractAddress to utils.getOrderHashHex 2017-07-03 12:04:07 -07:00
Leonid Logvinov
15bd31e629 Await ZRX call 2017-07-03 12:00:43 -07:00
Leonid Logvinov
287e9c7c85 Fix the comment 2017-07-03 11:58:58 -07:00
Leonid Logvinov
f09a0fca75 Rename invalidateContractInstanceAsync to invalidateContractInstancesAsync 2017-07-03 11:57:05 -07:00
Leonid Logvinov
649d55f0a2 Fix _getProxyContractAsync function name 2017-07-03 11:43:36 -07:00
Leonid Logvinov
b7705f0871 Fix comment 2017-07-03 11:42:58 -07:00
Leonid
d506a1f985 Merge pull request #88 from 0xProject/greenkeeper/chai-as-promised-7.1.0
Update chai-as-promised to the latest version 🚀
2017-07-03 11:38:42 -07:00
Leonid
8e6fbc214b Merge pull request #86 from 0xProject/subscribe-async-event-names
Assert correct event names in subscribeAsync tests
2017-07-03 08:18:47 -07:00
Leonid
5cb1e5853e Merge pull request #85 from 0xProject/greenkeeper/ethereumjs-testrpc-4.0.1
Greenkeeper/ethereumjs testrpc 4.0.1
2017-07-03 08:18:28 -07:00
greenkeeper[bot]
86e38f45fc chore(package): update chai-as-promised to version 7.1.0 2017-07-02 18:25:13 +00:00
Leonid Logvinov
0e54418dbb Wrap all event args in a newer version of BigNumber and test it 2017-07-01 19:44:17 -07:00
Leonid Logvinov
6e0edb8d8e Fix contracts repo commit in circle.yml 2017-07-01 19:40:13 -07:00
Leonid Logvinov
c0d4b30828 Assert correct event names in subscribeAsync tests 2017-07-01 08:39:57 -07:00
Leonid Logvinov
74ef0458f5 Fix test failures caused by testrpc new eth_sign behaviour 2017-06-30 19:08:07 -07:00
Leonid Logvinov
c5a93b0945 Fix comment 2017-06-30 14:21:58 -07:00
Leonid Logvinov
24e2ee831d Fix comment 2017-06-30 14:21:28 -07:00
Leonid Logvinov
cc9f0f17af Remove constructor 2017-06-30 14:20:52 -07:00
Leonid Logvinov
8f90ce2cf7 Fix proxy comment 2017-06-30 14:20:34 -07:00
Leonid Logvinov
7cedeb0be9 Fix naming 2017-06-30 14:19:54 -07:00
Leonid Logvinov
43848f45ec Fix a typo in authorized 2017-06-30 14:15:49 -07:00
Leonid Logvinov
fc3b0ce553 Fix a bug in getProxyAuthorizedContractAddressesAsync 2017-06-30 14:14:34 -07:00
Leonid Logvinov
a85c2b61ce Move schema assertion up to prevent the _.map failure 2017-06-30 14:04:24 -07:00
Leonid Logvinov
0c07490ae5 Change 'changes' to 'latest changes' for no good reason in CHANGELOG.md 2017-06-30 14:03:29 -07:00
Leonid Logvinov
6aa37ad3e4 Add tests for getProxyAuthorizedContractAddressesAsync 2017-06-29 13:41:35 -07:00
Leonid Logvinov
1321ea5beb Remove unused code from test/proxy_wrapper_test.ts 2017-06-29 13:15:20 -07:00
Leonid Logvinov
7ca113b59b Add a test for a ProxyWrapper 2017-06-29 13:11:50 -07:00
Leonid Logvinov
fd242a1e06 Fix a typo in authorized 2017-06-29 13:11:22 -07:00
Leonid Logvinov
83eeeb85b2 Rename _proxy to _proxyWrapper 2017-06-29 13:11:06 -07:00
Leonid Logvinov
fa3963199e Make zeroEx.getOrderHashHex non-async 2017-06-29 12:54:41 -07:00
Leonid Logvinov
e1e79519b9 Fix typo in getAvailableContractAddressesAsync 2017-06-29 12:54:03 -07:00
Leonid Logvinov
b1573fc6a7 Implement getProxyAuthorizedContractAddressesAsync 2017-06-29 12:20:41 -07:00
Leonid Logvinov
cbe17aa44b Store ProxyWrapper instance in ExchangeWrapper 2017-06-29 12:17:51 -07:00
Leonid Logvinov
d009b9b525 Add ProxyWrapper instance to zeroEx 2017-06-29 12:16:50 -07:00
Leonid Logvinov
889410d605 Add Proxy wrapper 2017-06-29 12:14:49 -07:00
Leonid Logvinov
82cceb8605 Add type for a ProxyContract 2017-06-29 12:14:00 -07:00
Leonid Logvinov
83bc740911 Make it clear that we are using a fake address in tests 2017-06-29 11:25:58 -07:00
Leonid Logvinov
bc92968c5e Rename Exchange.json to Exchange_v1.json 2017-06-29 11:21:04 -07:00
Leonid Logvinov
d0830d55ad Factor out ZRXtokenAddress variable 2017-06-29 11:19:51 -07:00
Leonid Logvinov
9395b53af4 Rename ZeroExError.CONTRACT_DOES_NOT_EXIST to ZeroExError.EXCHANGE_CONTRACT_DOES_NOT_EXIST 2017-06-29 11:18:15 -07:00
Leonid Logvinov
f6ec388916 Fix a typo in a name 2017-06-29 11:08:33 -07:00
Leonid Logvinov
3f7bdfa67a Factor out exchangeArtifacts variable 2017-06-29 11:05:56 -07:00
Leonid Logvinov
260def1aef Check that artefacts by networkId are not undefined before getting the address 2017-06-29 11:02:52 -07:00
Leonid Logvinov
330a1cff11 Fix a typo in a name 2017-06-29 10:54:20 -07:00
Leonid Logvinov
91e2857645 Fix a typo in a name 2017-06-29 10:53:11 -07:00
Leonid Logvinov
5e5acdc56e Move schema assertion up to prevent the _.map failure 2017-06-29 10:51:24 -07:00
Leonid Logvinov
b896a723c2 Move schema assertion up to prevent the _.map failure 2017-06-29 10:50:22 -07:00
Leonid Logvinov
3acdeaf518 Mve schema assertion up to prevent the _.map failure 2017-06-29 10:49:44 -07:00
Leonid Logvinov
e9db532727 Make getOrderHashHex a non-async function 2017-06-29 10:34:49 -07:00
Leonid Logvinov
dd590ca79e Improve CHANGELOG comments 2017-06-29 10:30:14 -07:00
greenkeeper[bot]
6a8c54e8de chore(package): update ethereumjs-testrpc to version 4.0.1
Closes #83
2017-06-28 16:07:40 +00:00
Leonid Logvinov
70c7914c4c Update CHANGELOG.md 2017-06-27 11:36:18 -07:00
Leonid Logvinov
a4ce7ed21e Update contract artefacts 2017-06-27 11:32:06 -07:00
Leonid Logvinov
6bf594bb4b Remove update_contracts call from circleci.yml 2017-06-27 11:16:00 -07:00
Leonid Logvinov
75711f348a Remove custom Schema type and use one from jsonschema 2017-06-27 11:04:27 -07:00
Leonid Logvinov
56cfb41d54 Add CHANGELOG.md entry 2017-06-26 19:48:24 -07:00
Leonid Logvinov
3d55f97c0a Remove _getExchangeAddressAsync 2017-06-26 19:44:21 -07:00
Leonid Logvinov
de0e436aad Allow multiple exchange versions t be functional at the same time 2017-06-26 19:44:21 -07:00
Leonid Logvinov
2c5f221073 Update copyfiles to copy nested artifacts 2017-06-26 19:44:21 -07:00
Leonid Logvinov
df751a2af5 Move exchange artifacts to an exchange subfolder 2017-06-26 19:44:21 -07:00
Fabio Berger
79b79a5795 Add the 0xproject profile flag to the AWS cli command so that devs can have their personal AWS creds be the default in .aws/credentials 2017-06-26 15:31:15 -07:00
Fabio Berger
540faac79c 0.7.1 2017-06-26 15:26:51 -07:00
Fabio Berger
dfff718972 Add 0.7.1 release notes 2017-06-26 15:25:30 -07:00
Fabio Berger
40636f1609 Change all the dates from July to June in changelog 2017-06-26 15:22:34 -07:00
Fabio Berger
6c48e6c74f Additional EtherToken comment changes 2017-06-26 14:54:04 -07:00
Fabio Berger
718b801f48 Improve EtherToken comments 2017-06-26 14:14:03 -07:00
Leonid
73eb78d793 Merge pull request #81 from 0xProject/addWrappedETHSupport
Add Wrapped ETH Support
2017-06-26 13:23:02 -07:00
Fabio Berger
f15451ebfd Merge branch 'addWrappedETHSupport' of github.com:0xProject/0x.js into addWrappedETHSupport
# Conflicts:
#	test/ether_token_wrapper_test.ts
2017-06-26 11:21:09 -07:00
Fabio Berger
41098c6a35 refactor getBalanceInEthAsync to getBalanceInWeiAsync and change the test assertions to check if the discrepancy between the existing ETH balance and expected balance is small enough to simply be the gas cost used by the transaction. 2017-06-26 11:20:16 -07:00
Leonid Logvinov
e780664b40 Remove .only from describe 2017-06-26 10:34:45 -07:00
Leonid Logvinov
efb5556e4e Rename INSUFFICIENT_WETH_BALANCE_FOR_WITHDRAWL to INSUFFICIENT_WETH_BALANCE_FOR_WITHDRAWAL 2017-06-26 10:33:53 -07:00
Fabio Berger
0f413febd3 Fix typo 2017-06-26 10:30:09 -07:00
Fabio Berger
60b3f3e6dd Implement EtherTokenWrapper and tests, with deposit and withdraw methods 2017-06-25 14:50:11 -07:00
Fabio Berger
7d001240c1 Add missing return comment 2017-06-25 14:49:12 -07:00
Fabio Berger
a2c495a983 Re-wrap BigNumber returned from web3 in getBalanceInEthAsync 2017-06-25 14:48:48 -07:00
Leonid
d5ed5865ca Merge pull request #79 from 0xProject/integration-tests
Add kovan integration tests
2017-06-23 17:17:06 +02:00
Leonid Logvinov
75ae305a6e Rename KOVAN_URL to KOVAN_RPC_URL 2017-06-23 17:10:43 +02:00
Leonid
0c5ba2a68e Merge pull request #80 from 0xProject/greenkeeper/web3-typescript-typings-0.0.10
Update web3-typescript-typings to the latest version 🚀
2017-06-23 14:25:33 +02:00
greenkeeper[bot]
d21b716cb3 chore(package): update web3-typescript-typings to version 0.0.10 2017-06-23 11:26:40 +00:00
Leonid Logvinov
845aee35d3 Simplify integration tests 2017-06-23 12:12:16 +02:00
Leonid Logvinov
9a6a9fc28b Add comment before declarations 2017-06-23 12:05:48 +02:00
Leonid Logvinov
3f962585e9 Refactor KOVAN_URL to constants and fetch mnemonic from package.json 2017-06-23 12:03:40 +02:00
Fabio Berger
13dfc263b6 Fix version in CHANGELOG 2017-06-22 16:18:49 -07:00
Fabio Berger
4eb050967f 0.7.0 2017-06-22 16:18:27 -07:00
Fabio Berger
cb3127c568 Add changelog for v0.7.2 2017-06-22 16:16:50 -07:00
Leonid Logvinov
dcd08e40e6 Add kovan integration tests 2017-06-22 23:36:43 +02:00
Leonid Logvinov
438b821835 Fix incorrect merge consequences 2017-06-22 23:15:25 +02:00
Leonid
c52d6753ce Merge pull request #72 from 0xProject/fill-order-amuont
Return filledAmount from fillOrderAsync
2017-06-22 22:50:35 +02:00
Leonid
e5785532ed Merge branch 'master' into fill-order-amuont 2017-06-22 22:50:16 +02:00
Fabio Berger
49e43c9876 Merge pull request #78 from 0xProject/update-contracts
Update contracts
2017-06-22 12:04:25 -07:00
Leonid Logvinov
0cd9875369 Update contracts 2017-06-22 17:47:56 +02:00
Leonid
1375126e4c Merge pull request #77 from 0xProject/revert-71-lodash-tree-shake
Revert "Use different lodash import syntax which allows to include only used functions"
2017-06-22 16:22:20 +02:00
Leonid
94cab6f694 Revert "Use different lodash import syntax which allows to include only used functions" 2017-06-22 16:21:56 +02:00
Leonid Logvinov
bd9fa3d335 Add test for return amount from fillOrdersUpToAsync 2017-06-22 14:15:35 +02:00
Leonid Logvinov
9c2a332b69 Return filledTakerTokenAmount from fillOrdersUpToAsync 2017-06-22 14:12:17 +02:00
Leonid Logvinov
b28b0fad7a Add test for cancelOrderAsync return value 2017-06-22 13:45:43 +02:00
Leonid Logvinov
0dbad86d23 Return cancelledAmount from cancelOrderAsync 2017-06-22 13:41:07 +02:00
Leonid
25a9ba90f5 Merge pull request #73 from 0xProject/json-docs
Auto-upload json docs on release
2017-06-22 13:32:14 +02:00
Leonid Logvinov
5001e5fc70 Set content type 2017-06-22 13:29:39 +02:00
Leonid Logvinov
d088dcdd36 Add simple test checking that fillOrderAsync return filled amount 2017-06-22 00:16:35 +02:00
Leonid Logvinov
7b471858fa Fix return comment 2017-06-22 00:16:15 +02:00
Leonid Logvinov
e7152ed58c Grant read permissions to all users 2017-06-22 00:07:32 +02:00
Leonid Logvinov
c5139bca26 Auto-upload json docs on release 2017-06-21 18:07:04 +02:00
Leonid Logvinov
42c61ecda5 Return filledAmount from fillOrderAsync 2017-06-21 17:55:21 +02:00
Leonid Logvinov
656d74518d Rename Log*Args to Log*ContractEventArgs 2017-06-21 16:38:20 +02:00
Leonid Logvinov
8d2b67bce2 0.6.2 2017-06-21 15:35:02 +02:00
Leonid Logvinov
de29c23ad7 Revert "Temporarily use forked version of truffle-contract to reduce the bundle"
This reverts commit ef96c58b7f.
truffle-contract is not compatible with web3 0.19.0 cause it checks the
number of arguments and they pass incorrect number of arguments
2017-06-21 15:15:42 +02:00
Leonid Logvinov
41e62d078f Updat CHANGELOG.md with v0.6.2 2017-06-21 15:15:42 +02:00
Leonid
d49057dbfb Merge pull request #70 from 0xProject/greenkeeper/@types/node-8.0.1
Update @types/node to the latest version 🚀
2017-06-21 15:08:44 +02:00
Leonid
8af7d2303e Merge pull request #71 from 0xProject/lodash-tree-shake
Use different lodash import syntax which allows to include only used functions
2017-06-21 15:04:13 +02:00
Leonid Logvinov
ef96c58b7f Temporarily use forked version of truffle-contract to reduce the bundle
truffle-contract uses web3 0.18.0. We use web3 0.19.0 which results in 2
versions of web3 being bundled with the package
This commit temporarily switches to custom truffle-contract fork
We'll switch back when the PR would be accepted
2017-06-21 15:02:09 +02:00
Leonid Logvinov
a1c363a8af Fall back to import x = require() syntax 2017-06-21 14:11:06 +02:00
Leonid Logvinov
40a7be0690 Use different lodash import syntax which allows to include only used functions 2017-06-21 13:56:14 +02:00
greenkeeper[bot]
060ee5e9d3 chore(package): update @types/node to version 8.0.1 2017-06-20 20:57:09 +00:00
Leonid Logvinov
096d3bdb26 Connect to github over https so that it works without authentication 2017-06-20 16:50:15 +02:00
Leonid
6b044a966a Add Greenkeeper badge 2017-06-20 12:24:16 +02:00
Leonid Logvinov
9fe042733d Move out of @0xproject scope 2017-06-20 09:05:41 +02:00
Fabio Berger
6aaa7a0856 Merge pull request #69 from 0xProject/improveReadme
Improve README
2017-06-19 17:51:03 -07:00
Fabio Berger
8135f98029 Add documentation section 2017-06-19 17:48:29 -07:00
Fabio Berger
6386c43e01 Include two links to the documentation 2017-06-19 17:46:11 -07:00
Fabio Berger
f86d177cd4 Add the installation instructions to the README 2017-06-19 17:44:22 -07:00
Fabio Berger
20f59d556d Add missing semi-colon 2017-06-19 17:38:34 -07:00
Fabio Berger
1ad54ba742 Add newline between type defs 2017-06-19 17:38:21 -07:00
Fabio Berger
dc7c2082df Improve comment 2017-06-19 17:38:08 -07:00
Fabio Berger
999cf1be7c Improve the README 2017-06-19 08:57:27 -07:00
687 changed files with 62445 additions and 6699 deletions

28
.circleci/config.yml Normal file
View File

@@ -0,0 +1,28 @@
version: 2
jobs:
build:
docker:
- image: circleci/node:6.12
environment:
CONTRACTS_COMMIT_HASH: '9ed05f5'
steps:
- checkout
- run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV
- run:
name: yarn
command: yarn
- save_cache:
key: dependency-cache-{{ checksum "package.json" }}
paths:
- ~/.cache/yarn
- run: wget https://s3.amazonaws.com/testrpc-shapshots/${CONTRACTS_COMMIT_HASH}.zip
- run: unzip ${CONTRACTS_COMMIT_HASH}.zip -d testrpc_snapshot
- run: node ./node_modules/lerna/bin/lerna.js bootstrap
- run: yarn lerna:run build
- run:
name: testrpc
command: npm run testrpc -- --db testrpc_snapshot
background: true
- run: yarn lerna:run test:circleci
- run: yarn lerna:run lint

11
.gitignore vendored
View File

@@ -58,9 +58,16 @@ typings/
.env
# built library using in commonjs module syntax
lib
lib/
# UMD bundles that export the global variable
_bundles
# generated documentation
docs
generated_docs/
TODO.md
packages/website/public/bundle*
# generated binaries
bin/

View File

@@ -1,15 +0,0 @@
# CHANGELOG
v0.6.1 - _Jul. 19, 2017_
------------------------
* Improve documentation
v0.6.0 - _Jul. 19, 2017_
------------------------
* Made `ZeroEx` class accept `Web3Provider` instance instead of `Web3` instance
* Added types for contract event arguments
v0.5.2 - _Jul. 15, 2017_
------------------------
* Fixed the bug in `postpublish` script that caused that only unminified UMD bundle was uploaded to release page
v0.5.1 - _Jul. 15, 2017_
------------------------
* Added `postpublish` script to publish to Github Releases with assets.

50
CONTRIBUTING.md Normal file
View File

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

2
PULL_REQUEST_TEMPLATE.md Normal file
View File

@@ -0,0 +1,2 @@
This PR:
*

104
README.md
View File

@@ -1,4 +1,104 @@
# 0x.js
<img src="https://github.com/0xProject/branding/blob/master/0x_Black_CMYK.png" width="200px" >
---
[0x][website-url] is an open protocol that facilitates trustless, low friction exchange of Ethereum-based assets. A full description of the protocol may be found in our [whitepaper][whitepaper-url].
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)
[![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)
[![Coverage Status](https://coveralls.io/repos/github/0xProject/0x.js/badge.svg?branch=master&t=fp0cXD)](https://coveralls.io/github/0xProject/0x.js?branch=master)
[![Discord](https://img.shields.io/badge/chat-rocket.chat-yellow.svg?style=flat
)](https://chat.0xproject.com)
[![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/)
### Published Packages
| Package | Version | Description |
|---------|---------|-------------|
| [`0x.js`](/packages/0x.js) | [![npm](https://img.shields.io/npm/v/0x.js.svg)](https://www.npmjs.com/package/0x.js) | A Javascript library for interacting with the 0x protocol |
| [`@0xproject/abi-gen`](/packages/abi-gen) | [![npm](https://img.shields.io/npm/v/@0xproject/abi-gen.svg)](https://www.npmjs.com/package/@0xproject/abi-gen) | Tool to generate TS wrappers from smart contract ABIs |
| [`@0xproject/assert`](/packages/assert) | [![npm](https://img.shields.io/npm/v/@0xproject/assert.svg)](https://www.npmjs.com/package/@0xproject/assert) | Type and schema assertions used by our packages |
| [`@0xproject/connect`](/packages/connect) | [![npm](https://img.shields.io/npm/v/@0xproject/connect.svg)](https://www.npmjs.com/package/@0xproject/connect) | A Javascript library for interacting with the standard relayer api |
| [`@0xproject/json-schemas`](/packages/json-schemas) | [![npm](https://img.shields.io/npm/v/@0xproject/json-schemas.svg)](https://www.npmjs.com/package/@0xproject/json-schemas) | 0x-related json schemas |
| [`@0xproject/subproviders`](/packages/subproviders) | [![npm](https://img.shields.io/npm/v/@0xproject/subproviders.svg)](https://www.npmjs.com/package/@0xproject/subproviders) | Useful web3 subproviders (e.g LedgerSubprovider) |
| [`@0xproject/tslint-config`](/packages/tslint-config) | [![npm](https://img.shields.io/npm/v/@0xproject/tslint-config.svg)](https://www.npmjs.com/package/@0xproject/tslint-config) | Custom 0x development TSLint rules |
| [`@0xproject/types`](/packages/types) | [![npm](https://img.shields.io/npm/v/@0xproject/types.svg)](https://www.npmjs.com/package/@0xproject/types) | Shared type declarations |
| [`@0xproject/utils`](/packages/utils) | [![npm](https://img.shields.io/npm/v/@0xproject/utils.svg)](https://www.npmjs.com/package/@0xproject/utils) | Shared utilities |
| [`@0xproject/web3-wrapper`](/packages/web3-wrapper) | [![npm](https://img.shields.io/npm/v/@0xproject/web3-wrapper.svg)](https://www.npmjs.com/package/@0xproject/web3-wrapper) | Web3 wrapper |
### Private Packages
| Package | Description |
|---------|-------------|
| [`@0xproject/contracts`](/packages/contracts) | 0x solidity smart contracts & tests |
| [`@0xproject/kovan_faucets`](/packages/kovan-faucets) | A faucet micro-service that dispenses test ERC20 tokens or Ether |
| [`@0xproject/monorepo-scripts`](/packages/monorepo-scripts) | Shared monorepo scripts |
| [`@0xproject/website`](/packages/website) | 0x website & Portal DApp |
## Usage
Dedicated documentation pages:
- [0x.js Library](https://0xproject.com/docs/0xjs)
- [0x Connect](https://0xproject.com/docs/connect)
- [Smart contracts](https://0xproject.com/docs/contracts)
- [Standard Relayer API](https://github.com/0xProject/standard-relayer-api/blob/master/README.md)
## Contributing
We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](./CONTRIBUTING.md) before getting started.
### Install dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
```bash
yarn config set workspaces-experimental true
```
Then install dependencies
```bash
yarn install
```
### Build
Build all packages
```bash
yarn lerna:run build
```
### Lint
Lint all packages
```bash
yarn lerna:run lint
```
### Run Tests
Before running the tests, you will need to spin up a [TestRPC](https://www.npmjs.com/package/ethereumjs-testrpc) instance and deploy all the 0x smart contracts.
In a separate terminal, start TestRPC (a convenience command is provided as part of this repo)
```bash
yarn testrpc
```
Then in your main terminal run
```
cd packages/contracts
yarn migrate
cd ..
```
And finally from the root project directory run
```bash
yarn lerna:run test
```

View File

@@ -1,15 +0,0 @@
machine:
node:
version: 6.1.0
test:
override:
- npm run testrpc:
background: true
- git clone git@github.com:0xProject/contracts.git ../contracts
- cd ../contracts; git checkout 38c2b4c; npm install && npm run migrate
- npm run update_contracts
- npm run test:coverage
- npm run report_test_coverage
- npm run test:umd
- npm run lint

9
lerna.json Normal file
View File

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

View File

@@ -1,101 +1,24 @@
{
"name": "@0xproject/0x.js",
"version": "0.6.1",
"description": "A javascript library for interacting with the 0x protocol",
"keywords": [
"0x.js",
"0xproject",
"ethereum",
"tokens",
"exchange"
],
"main": "lib/src/index.js",
"types": "lib/src/index.d.ts",
"scripts": {
"prebuild": "npm run clean",
"build": "run-p build:*:prod",
"prepublish": "run-p build:umd:prod build:commonjs:dev",
"postpublish": "publish-release --assets _bundles/index.js,_bundles/index.min.js",
"lint": "tslint src/*.ts test/*.ts",
"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;",
"testrpc": "testrpc -p 8545 --networkId 50 -m \"${npm_package_config_mnemonic}\"",
"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:dev": "npm run clean && run-p build:*:dev",
"build:umd:dev": "webpack",
"build:umd:prod": "NODE_ENV=production webpack",
"build:commonjs:dev": "tsc; copyfiles -u 2 ./src/artifacts/*.json ../0x.js/lib/src/artifacts;",
"test:commonjs": "run-s build:commonjs:dev run_mocha",
"pretest:umd": "run-s clean build:*:dev",
"substitute_umd_bundle": "npm run remove_src_files_not_used_by_tests; shx mv _bundles/* lib/src",
"remove_src_files_not_used_by_tests": "find ./lib/src \\( -path ./lib/src/utils -o -path ./lib/src/schemas -o -path \"./lib/src/types.*\" \\) -prune -o -type f -print | xargs rm",
"run_mocha": "mocha lib/test/**/*_test.js --timeout 3000"
},
"config": {
"artifacts": "Proxy Exchange TokenRegistry Token Mintable EtherToken",
"mnemonic": "concert load couple harbor equip island argue ramp clarify fence smart topic"
},
"repository": {
"type": "git",
"url": "https://github.com/0xProject/0x.js"
},
"license": "Apache-2.0",
"engines": {
"node": ">=6.0.0"
},
"devDependencies": {
"@types/bignumber.js": "^4.0.2",
"@types/jsonschema": "^1.1.1",
"@types/lodash": "^4.14.64",
"@types/mocha": "^2.2.41",
"@types/node": "^7.0.22",
"@types/sinon": "^2.2.2",
"awesome-typescript-loader": "^3.1.3",
"bignumber.js": "^4.0.2",
"chai": "^4.0.1",
"chai-as-promised": "^6.0.0",
"chai-as-promised-typescript-typings": "0.0.3",
"chai-bignumber": "git+ssh://git@github.com:0xProject/chai-bignumber.git",
"chai-typescript-typings": "^0.0.0",
"copyfiles": "^1.2.0",
"coveralls": "^2.13.1",
"dirty-chai": "^1.2.2",
"ethereumjs-testrpc": "3.0.5",
"json-loader": "^0.5.4",
"mocha": "^3.4.1",
"npm-run-all": "^4.0.2",
"nyc": "^11.0.1",
"opn-cli": "^3.1.0",
"request": "^2.81.0",
"request-promise-native": "^1.0.4",
"shx": "^0.2.2",
"sinon": "^2.3.2",
"source-map-support": "^0.4.15",
"tslint": "^5.3.2",
"tslint-config-0xproject": "^0.0.2",
"typedoc": "^0.7.1",
"typescript": "^2.3.3",
"web3-provider-engine": "^13.0.1",
"web3-typescript-typings": "^0.0.9",
"webpack": "^2.6.0"
},
"dependencies": {
"bignumber.js": "^4.0.2",
"compare-versions": "^3.0.1",
"es6-promisify": "^5.0.0",
"ethereumjs-abi": "^0.6.4",
"ethereumjs-util": "^5.1.1",
"find-versions": "^2.0.0",
"jsonschema": "^1.1.1",
"lodash": "^4.17.4",
"publish-release": "^1.3.3",
"truffle-contract": "^2.0.1",
"web3": "^0.19.0"
}
"private": true,
"name": "0x.js",
"workspaces": [
"packages/*"
],
"scripts": {
"testrpc": "testrpc -p 8545 --networkId 50 -m \"${npm_package_config_mnemonic}\"",
"lerna:run": "lerna run",
"lerna:rebuild": "lerna run clean; lerna run build;",
"lerna:publish": "yarn install; lerna run clean; lerna run build; lerna publish --registry=https://registry.npmjs.org/"
},
"config": {
"mnemonic": "concert load couple harbor equip island argue ramp clarify fence smart topic"
},
"devDependencies": {
"@0xproject/utils": "^0.1.0",
"async-child-process": "^1.1.1",
"ethereumjs-testrpc": "6.0.3",
"lerna": "^2.5.1",
"publish-release": "0xproject/publish-release",
"semver-sort": "^0.0.4"
}
}

261
packages/0x.js/CHANGELOG.md Normal file
View File

@@ -0,0 +1,261 @@
# CHANGELOG
v0.29.0 - _December 28, 2017_
------------------------
* Assert baseUnit amount supplied to `toUnitAmount` is integer amount. (#287)
* `toBaseUnitAmount` throws if amount supplied has too many decimals (#287)
v0.28.0 - _December 20, 2017_
------------------------
* Add `etherTokenAddress` arg to `depositAsync` and `withdrawAsync` methods on `zeroEx.etherToken` (#267)
* Removed accidentally included `unsubscribeAll` method from `zeroEx.proxy`, `zeroEx.etherToken` and `zeroEx.tokenRegistry` (#267)
* Removed `etherTokenContractAddress` from `ZeroEx` constructor arg `ZeroExConfig` (#267)
* Rename `SubscriptionOpts` to `BlockRange` (#272)
* Add `zeroEx.etherToken.subscribe`, `zeroEx.etherToken.unsubscribe`, `zeroEx.etherToken.unsubscribeAll` (#277)
* Add `zeroEx.etherToken.getLogsAsync` (#277)
* Add new public types `BlockParamLiteral`, `EtherTokenEvents`, `EtherTokenContractEventArgs`, `DepositContractEventArgs`, `WithdrawalContractEventArgs` (#277)
* Support `Deposit` and `Withdraw` events on etherToken (#277)
* Improve the error message when taker is not a string (#278)
v0.27.1 - _November 28, 2017_
------------------------
* Export `TransactionOpts` type
v0.27.0 - _November 28, 2017_
------------------------
* 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
v0.22.6 - _November 10, 2017_
------------------------
* Add a timeout parameter to transaction awaiting (#206)
v0.22.5 - _November 7, 2017_
------------------------
* Re-publish v0.22.4 to fix publishing issue
v0.22.4 - _October 25, 2017_
------------------------
* Upgraded bignumber.js to a new version that ships with native typings
v0.22.3 - _October 25, 2017_
------------------------
* Fixed an issue with new version of testrpc and unlimited proxy allowance (#199)
v0.22.2 - _October 24, 2017_
------------------------
* Fixed rounding of maker fill amount and incorrect validation of partial fees (#197)
v0.22.0 - _October 16, 2017_
------------------------
* Started using `OrderFillRequest` interface instead of `OrderFillOrKillRequest` interface for `zeroEx.exchange.batchFillOrKill` (#187)
* Removed `OrderFillOrKillRequest` (#187)
v0.21.4 - _October 13, 2017_
------------------------
* Made 0x.js more type-safe by making `getLogsAsync` and `subscribe/subscribeAsync` generics parametrized with arg type (#194)
v0.21.3 - _October 12, 2017_
------------------------
* Fixed a bug causing order fills to throw `INSUFFICIENT_TAKER_ALLOWANCE` (#193)
v0.21.2 - _October 11, 2017_
------------------------
* Exported `ContractEventArg` as a public type (#190)
v0.21.1 - _October 11, 2017_
------------------------
* Fixed a bug in subscriptions (#189)
v0.21.0 - _October 10, 2017_
------------------------
* Complete rewrite of subscription logic (#182)
* Subscriptions no longer return historical logs. If you want them - use `getLogsAsync`
* Subscriptions now use [ethereumjs-blockstream](https://github.com/ethereumjs/ethereumjs-blockstream) under the hood
* Subscriptions correctly handle block re-orgs (forks)
* Subscriptions correctly backfill logs (connection problems)
* They no longer setup filters on the underlying nodes, so you can use them with infura without a filter Subprovider
* Removed `ContractEventEmitter` and added `LogEvent`
* Renamed `zeroEx.token.subscribeAsync` to `zeroEx.token.subscribe`
* Added `zeroEx.token.unsubscribe` and `zeroEx.exchange.unsubscribe`
* Renamed `zeroEx.exchange.stopWatchingAllEventsAsync` to `zeroEx.exhange.unsubscribeAll`
* Renamed `zeroEx.token.stopWatchingAllEventsAsync` to `zeroEx.token.unsubscribeAll`
* Fixed the batch fills validation by emulating all balance & proxy allowance changes (#185)
v0.20.0 - _October 5, 2017_
------------------------
* Add `zeroEx.token.getLogsAsync` (#178)
* Add `zeroEx.exchange.getLogsAsync` (#178)
* Fixed fees validation when one of the tokens transferred is ZRX (#181)
v0.19.0 - _September 29, 2017_
------------------------
* Made order validation optional (#172)
* Added Ropsten testnet support (#173)
* Fixed a bug causing awaitTransactionMinedAsync to DDos backend nodes (#175)
v0.18.0 - _September 26, 2017_
------------------------
* Added `zeroEx.exchange.validateOrderFillableOrThrowAsync` to simplify orderbook pruning (#170)
v0.17.0 - _September 26, 2017_
------------------------
* Made `zeroEx.exchange.getZRXTokenAddressAsync` public (#171)
v0.16.0 - _September 20, 2017_
------------------------
* Added the ability to specify custom contract addresses to be used with 0x.js (#165)
* ZeroExConfig.exchangeContractAddress
* ZeroExConfig.tokenRegistryContractAddress
* ZeroExConfig.etherTokenContractAddress
* Added `zeroEx.tokenRegistry.getContractAddressAsync` (#165)
v0.15.0 - _September 8, 2017_
------------------------
* Added the ability to specify a historical `blockNumber` at which to query the blockchain's state when calling a token or exchange method (#161)
v0.14.2 - _September 7, 2017_
------------------------
* Fixed an issue with bignumber.js types not found (#160)
v0.14.1 - _September 7, 2017_
------------------------
* Fixed an issue with Artifact type not found (#159)
v0.14.0 - _September 6, 2017_
------------------------
* Added `zeroEx.exchange.throwLogErrorsAsErrors` method to public interface (#157)
* Fixed an issue with overlapping async intervals in `zeroEx.awaitTransactionMinedAsync` (#157)
* Fixed an issue with log decoder returning `BigNumber`s as `strings` (#157)
v0.13.0 - _September 6, 2017_
------------------------
* Made all the functions submitting transactions to the network to immediately return transaction hash (#151)
* Added `zeroEx.awaitTransactionMinedAsync` (#151)
* Added `TransactionReceiptWithDecodedLogs`, `LogWithDecodedArgs`, `DecodedLogArgs` to public types (#151)
* Added signature validation to `validateFillOrderThrowIfInvalidAsync` (#152)
v0.12.1 - _September 2, 2017_
------------------------
* Added the support for web3@1.x.x provider (#142)
* Added the optional `zeroExConfig` parameter to the constructor of `ZeroEx` (#139)
* Added the ability to specify `gasPrice` when instantiating `ZeroEx` (#139)
v0.11.0 - _August 24, 2017_
------------------------
* Added `zeroEx.token.setUnlimitedProxyAllowanceAsync` (#137)
* Added `zeroEx.token.setUnlimitedAllowanceAsync` (#137)
* Added `zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS` (#137)
v0.10.4 - _Aug 24, 2017_
------------------------
* Fixed a bug where checksummed addresses were being pulled from artifacts and not lower-cased. (#135)
v0.10.1 - _Aug 24, 2017_
------------------------
* Added `zeroEx.exchange.validateFillOrderThrowIfInvalidAsync` (#128)
* Added `zeroEx.exchange.validateFillOrKillOrderThrowIfInvalidAsync` (#128)
* Added `zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync` (#128)
* Added `zeroEx.exchange.isRoundingErrorAsync` (#128)
* Added `zeroEx.proxy.getContractAddressAsync` (#130)
* Added `zeroEx.tokenRegistry.getTokenAddressesAsync` (#132)
* Added `zeroEx.tokenRegistry.getTokenAddressBySymbolIfExistsAsync` (#132)
* Added `zeroEx.tokenRegistry.getTokenAddressByNameIfExistsAsync` (#132)
* Added `zeroEx.tokenRegistry.getTokenBySymbolIfExistsAsync` (#132)
* Added `zeroEx.tokenRegistry.getTokenByNameIfExistsAsync` (#132)
* Added clear error message when checksummed address is passed to a public method (#124)
* Fixes the description of `shouldThrowOnInsufficientBalanceOrAllowance` in docs (#127)
v0.9.3 - _Aug 22, 2017_
------------------------
* Update contract artifacts to include latest Kovan and Mainnet deploys (#118)
v0.9.2 - _Aug 21, 2017_
------------------------
* *This version was unpublished because of a publishing issue.*
* Update contract artifacts to include latest Kovan and Mainnet deploys (#118)
v0.9.1 - _Aug. 16, 2017_
------------------------
* Fixed the bug causing `zeroEx.token.getBalanceAsync()` to fail if no addresses available (#120)
v0.9.0 - _Jul. 26, 2017_
------------------------
* Migrated to the new version of smart contracts (#101)
* Removed the ability to call methods on multiple authorized Exchange smart contracts (#106)
* Made `zeroEx.getOrderHashHex` a static method (#107)
* Cached `net_version` requests and invalidate the cache on calls to `setProvider` (#95)
* Renamed `zeroEx.exchange.batchCancelOrderAsync` to `zeroEx.exchange.batchCancelOrdersAsync`
* Renamed `zeroEx.exchange.batchFillOrderAsync` to `zeroEx.exchange.batchFillOrdersAsync`
* Updated to typescript v2.4 (#104)
* Fixed an issue with incorrect balance/allowance validation when ZRX is one of the tokens traded (#109)
v0.8.0 - _Jul. 4, 2017_
------------------------
* Added the ability to call methods on different authorized versions of the Exchange smart contract (#82)
* Updated contract artifacts to reflect latest changes to the smart contracts (0xproject/contracts#59)
* Added `zeroEx.proxy.isAuthorizedAsync` and `zeroEx.proxy.getAuthorizedAddressesAsync` (#89)
* Added `zeroEx.token.subscribeAsync` (#90)
* Made contract invalidation functions private (#90)
* `zeroEx.token.invalidateContractInstancesAsync`
* `zeroEx.exchange.invalidateContractInstancesAsync`
* `zeroEx.proxy.invalidateContractInstance`
* `zeroEx.tokenRegistry.invalidateContractInstance`
* Fixed the bug where `zeroEx.setProviderAsync` didn't invalidate etherToken contract's instance
v0.7.1 - _Jun. 26, 2017_
------------------------
* Added the ability to convert Ether to wrapped Ether tokens and back via `zeroEx.etherToken.depostAsync` and `zeroEx.etherToken.withdrawAsync` (#81)
v0.7.0 - _Jun. 22, 2017_
------------------------
* Added Kovan smart contract artifacts (#78)
* Started returning fillAmount from `fillOrderAsync` and `fillUpToAsync` (#72)
* Started returning cancelledAmount from `cancelOrderAsync` (#72)
* Renamed type `LogCancelArgs` to `LogCancelContractEventArgs` and `LogFillArgs` to `LogFillContractEventArgs`
v0.6.2 - _Jun. 21, 2017_
------------------------
* Reduced bundle size
* Improved documentation
v0.6.1 - _Jun. 19, 2017_
------------------------
* Improved documentation
v0.6.0 - _Jun. 19, 2017_
------------------------
* Made `ZeroEx` class accept `Web3Provider` instance instead of `Web3` instance
* Added types for contract event arguments
v0.5.2 - _Jun. 15, 2017_
------------------------
* Fixed the bug in `postpublish` script that caused that only unminified UMD bundle was uploaded to release page
v0.5.1 - _Jun. 15, 2017_
------------------------
* Added `postpublish` script to publish to Github Releases with assets.

40
packages/0x.js/README.md Normal file
View File

@@ -0,0 +1,40 @@
0x.js
-----
## Installation
0x.js ships as both a [UMD](https://github.com/umdjs/umd) module and a [CommonJS](https://en.wikipedia.org/wiki/CommonJS) package.
#### CommonJS *(recommended)*:
**Install**
```bash
npm install 0x.js --save
```
**Import**
```javascript
import {ZeroEx} from '0x.js';
```
#### UMD:
**Install**
Download the UMD module from our [releases page](https://github.com/0xProject/0x.js/releases) and add it to your project.
**Import**
```html
<script type="text/javascript" src="0x.js"></script>
```
## Documentation
Extensive documentation of 0x.js can be found on [our website][docs-url].
[website-url]: https://0xproject.com/
[whitepaper-url]: https://0xproject.com/pdfs/0x_white_paper.pdf
[docs-url]: https://0xproject.com/docs/0xjs

View File

@@ -0,0 +1,26 @@
/**
* This file is auto-generated using abi-gen. Don't edit directly.
* Templates can be found at https://github.com/0xProject/0x.js/tree/development/packages/abi-gen-templates.
*/
// tslint:disable-next-line:no-unused-variable
import {TxData, TxDataPayable} from '@0xproject/types';
import {classUtils, promisify} from '@0xproject/utils';
import {BigNumber} from 'bignumber.js';
import * as Web3 from 'web3';
import {BaseContract} from './base_contract';
export class {{contractName}}Contract extends BaseContract {
{{#each methods}}
{{#this.constant}}
{{> call contractName=../contractName}}
{{/this.constant}}
{{^this.constant}}
{{> tx contractName=../contractName}}
{{/this.constant}}
{{/each}}
constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) {
super(web3ContractInstance, defaults);
classUtils.bindAll(this, ['web3ContractInstance', 'defaults']);
}
} // tslint:disable:max-file-line-count

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

104
packages/0x.js/package.json Normal file
View File

@@ -0,0 +1,104 @@
{
"name": "0x.js",
"version": "0.29.0",
"description": "A javascript library for interacting with the 0x protocol",
"keywords": [
"0x.js",
"0xproject",
"ethereum",
"tokens",
"exchange"
],
"main": "lib/src/index.js",
"types": "lib/src/index.d.ts",
"scripts": {
"prebuild": "run-s clean generate_contract_wrappers",
"build": "run-p build:umd:prod build:commonjs; exit 0;",
"docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_DIR",
"upload_docs_json": "aws s3 cp generated_docs/index.json $S3_URL --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type application/json",
"generate_contract_wrappers": "node ../abi-gen/lib/index.js --abiGlob 'src/artifacts/@(Exchange|Token|TokenTransferProxy|EtherToken|TokenRegistry|DummyToken).json' --templates contract_templates --output src/contract_wrappers/generated",
"lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'",
"test:circleci": "run-s test:coverage report_test_coverage && if [ $CIRCLE_BRANCH = \"development\" ]; then yarn test:umd; fi",
"test": "run-s clean test:commonjs",
"test:umd": "./scripts/test_umd.sh",
"test:coverage": "nyc npm run test --all",
"report_test_coverage": "nyc report --reporter=text-lcov | coveralls",
"update_contracts": "for i in ${npm_package_config_artifacts}; do copyfiles -u 4 ../contracts/build/contracts/$i.json ../0x.js/src/artifacts; done;",
"clean": "shx rm -rf _bundles lib test_temp",
"build:umd:dev": "webpack",
"build:umd:prod": "NODE_ENV=production webpack",
"build:commonjs": "tsc && copyfiles -u 2 './src/artifacts/**/*.json' ./lib/src/artifacts;",
"test:commonjs": "run-s build:commonjs run_mocha",
"pretest:umd": "run-s clean build:umd:dev build:commonjs",
"substitute_umd_bundle": "shx mv _bundles/* lib/src",
"run_mocha": "mocha lib/test/**/*_test.js --timeout 10000 --bail --exit"
},
"config": {
"artifacts": "TokenTransferProxy Exchange TokenRegistry Token EtherToken"
},
"repository": {
"type": "git",
"url": "https://github.com/0xProject/0x.js"
},
"license": "Apache-2.0",
"engines": {
"node": ">=6.0.0"
},
"devDependencies": {
"@0xproject/abi-gen": "^0.0.4",
"@0xproject/dev-utils": "^0.0.3",
"@0xproject/tslint-config": "^0.4.0",
"@0xproject/types": "^0.1.2",
"@types/bintrees": "^1.0.2",
"@types/jsonschema": "^1.1.1",
"@types/lodash": "^4.14.86",
"@types/mocha": "^2.2.42",
"@types/node": "^8.0.53",
"@types/sinon": "^2.2.2",
"@types/uuid": "^3.4.2",
"awesome-typescript-loader": "^3.1.3",
"chai": "^4.0.1",
"chai-as-promised": "^7.1.0",
"chai-as-promised-typescript-typings": "^0.0.3",
"chai-bignumber": "^2.0.1",
"chai-typescript-typings": "^0.0.1",
"copyfiles": "^1.2.0",
"coveralls": "^3.0.0",
"dirty-chai": "^2.0.1",
"json-loader": "^0.5.4",
"mocha": "^4.0.1",
"npm-run-all": "^4.1.2",
"nyc": "^11.0.1",
"opn-cli": "^3.1.0",
"request": "^2.81.0",
"request-promise-native": "^1.0.4",
"shx": "^0.2.2",
"sinon": "^4.0.0",
"source-map-support": "^0.5.0",
"truffle-hdwallet-provider": "^0.0.3",
"tslint": "5.8.0",
"typedoc": "~0.8.0",
"typescript": "~2.6.1",
"web3-provider-engine": "^13.0.1",
"web3-typescript-typings": "^0.7.2",
"webpack": "^3.1.0"
},
"dependencies": {
"@0xproject/assert": "^0.0.9",
"@0xproject/json-schemas": "^0.7.1",
"@0xproject/utils": "^0.1.2",
"@0xproject/web3-wrapper": "^0.1.2",
"bignumber.js": "~4.1.0",
"bintrees": "^1.0.2",
"bn.js": "^4.11.8",
"compare-versions": "^3.0.1",
"ethereumjs-abi": "^0.6.4",
"ethereumjs-blockstream": "^2.0.6",
"ethereumjs-util": "^5.1.1",
"find-versions": "^2.0.0",
"js-sha3": "^0.6.1",
"lodash": "^4.17.4",
"uuid": "^3.1.0",
"web3": "^0.20.0"
}
}

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

336
packages/0x.js/src/0x.ts Normal file
View File

@@ -0,0 +1,336 @@
import {schemas, SchemaValidator} from '@0xproject/json-schemas';
import {bigNumberConfigs, intervalUtils} from '@0xproject/utils';
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import BigNumber from 'bignumber.js';
import * as ethUtil from 'ethereumjs-util';
import * as _ from 'lodash';
import {artifacts} from './artifacts';
import {EtherTokenWrapper} from './contract_wrappers/ether_token_wrapper';
import {ExchangeWrapper} from './contract_wrappers/exchange_wrapper';
import {TokenRegistryWrapper} from './contract_wrappers/token_registry_wrapper';
import {TokenTransferProxyWrapper} from './contract_wrappers/token_transfer_proxy_wrapper';
import {TokenWrapper} from './contract_wrappers/token_wrapper';
import {OrderStateWatcher} from './order_watcher/order_state_watcher';
import {zeroExConfigSchema} from './schemas/zero_ex_config_schema';
import {
ECSignature,
Order,
SignedOrder,
TransactionReceiptWithDecodedLogs,
Web3Provider,
ZeroExConfig,
ZeroExError,
} from './types';
import {AbiDecoder} from './utils/abi_decoder';
import {assert} from './utils/assert';
import {constants} from './utils/constants';
import {decorators} from './utils/decorators';
import {signatureUtils} from './utils/signature_utils';
import {utils} from './utils/utils';
// Customize our BigNumber instances
bigNumberConfigs.configure();
/**
* The ZeroEx class is the single entry-point into the 0x.js library. It contains all of the library's functionality
* and all calls to the library should be made through a ZeroEx instance.
*/
export class ZeroEx {
/**
* When creating an order without a specified taker or feeRecipient you must supply the Solidity
* address null type (as opposed to Javascripts `null`, `undefined` or empty string). We expose
* this constant for your convenience.
*/
public static NULL_ADDRESS = constants.NULL_ADDRESS;
/**
* An instance of the ExchangeWrapper class containing methods for interacting with the 0x Exchange smart contract.
*/
public exchange: ExchangeWrapper;
/**
* An instance of the TokenRegistryWrapper class containing methods for interacting with the 0x
* TokenRegistry smart contract.
*/
public tokenRegistry: TokenRegistryWrapper;
/**
* An instance of the TokenWrapper class containing methods for interacting with any ERC20 token smart contract.
*/
public token: TokenWrapper;
/**
* An instance of the EtherTokenWrapper class containing methods for interacting with the
* wrapped ETH ERC20 token smart contract.
*/
public etherToken: EtherTokenWrapper;
/**
* An instance of the TokenTransferProxyWrapper class containing methods for interacting with the
* tokenTransferProxy smart contract.
*/
public proxy: TokenTransferProxyWrapper;
/**
* An instance of the OrderStateWatcher class containing methods for watching a set of orders for relevant
* blockchain state changes.
*/
public orderStateWatcher: OrderStateWatcher;
private _web3Wrapper: Web3Wrapper;
private _abiDecoder: AbiDecoder;
/**
* Verifies that the elliptic curve signature `signature` was generated
* by signing `data` with the private key corresponding to the `signerAddress` address.
* @param data The hex encoded data signed by the supplied signature.
* @param signature An object containing the elliptic curve signature parameters.
* @param signerAddress The hex encoded address that signed the data, producing the supplied signature.
* @return Whether the signature is valid for the supplied signerAddress and data.
*/
public static isValidSignature(data: string, signature: ECSignature, signerAddress: string): boolean {
assert.isHexString('data', data);
assert.doesConformToSchema('signature', signature, schemas.ecSignatureSchema);
assert.isETHAddressHex('signerAddress', signerAddress);
const isValidSignature = signatureUtils.isValidSignature(data, signature, signerAddress);
return isValidSignature;
}
/**
* Generates a pseudo-random 256-bit salt.
* The salt can be included in an 0x order, ensuring that the order generates a unique orderHash
* and will not collide with other outstanding orders that are identical in all other parameters.
* @return A pseudo-random 256-bit number that can be used as a salt.
*/
public static generatePseudoRandomSalt(): BigNumber {
// BigNumber.random returns a pseudo-random number between 0 & 1 with a passed in number of decimal places.
// Source: https://mikemcl.github.io/bignumber.js/#random
const randomNumber = BigNumber.random(constants.MAX_DIGITS_IN_UNSIGNED_256_INT);
const factor = new BigNumber(10).pow(constants.MAX_DIGITS_IN_UNSIGNED_256_INT - 1);
const salt = randomNumber.times(factor).round();
return salt;
}
/**
* Checks if the supplied hex encoded order hash is valid.
* Note: Valid means it has the expected format, not that an order with the orderHash exists.
* Use this method when processing orderHashes submitted as user input.
* @param orderHash Hex encoded orderHash.
* @return Whether the supplied orderHash has the expected format.
*/
public static isValidOrderHash(orderHash: string): boolean {
// Since this method can be called to check if any arbitrary string conforms to an orderHash's
// format, we only assert that we were indeed passed a string.
assert.isString('orderHash', orderHash);
const schemaValidator = new SchemaValidator();
const isValidOrderHash = schemaValidator.validate(orderHash, schemas.orderHashSchema).valid;
return isValidOrderHash;
}
/**
* A unit amount is defined as the amount of a token above the specified decimal places (integer part).
* E.g: If a currency has 18 decimal places, 1e18 or one quintillion of the currency is equivalent
* to 1 unit.
* @param amount The amount in baseUnits that you would like converted to units.
* @param decimals The number of decimal places the unit amount has.
* @return The amount in units.
*/
public static toUnitAmount(amount: BigNumber, decimals: number): BigNumber {
assert.isValidBaseUnitAmount('amount', amount);
assert.isNumber('decimals', decimals);
const aUnit = new BigNumber(10).pow(decimals);
const unit = amount.div(aUnit);
return unit;
}
/**
* A baseUnit is defined as the smallest denomination of a token. An amount expressed in baseUnits
* is the amount expressed in the smallest denomination.
* E.g: 1 unit of a token with 18 decimal places is expressed in baseUnits as 1000000000000000000
* @param amount The amount of units that you would like converted to baseUnits.
* @param decimals The number of decimal places the unit amount has.
* @return The amount in baseUnits.
*/
public static toBaseUnitAmount(amount: BigNumber, decimals: number): BigNumber {
assert.isBigNumber('amount', amount);
assert.isNumber('decimals', decimals);
const unit = new BigNumber(10).pow(decimals);
const baseUnitAmount = amount.times(unit);
const hasDecimals = baseUnitAmount.decimalPlaces() !== 0;
if (hasDecimals) {
throw new Error(`Invalid unit amount: ${amount.toString()} - Too many decimal places`);
}
return baseUnitAmount;
}
/**
* Computes the orderHash for a supplied order.
* @param order An object that conforms to the Order or SignedOrder interface definitions.
* @return The resulting orderHash from hashing the supplied order.
*/
@decorators.syncZeroExErrorHandler
public static getOrderHashHex(order: Order|SignedOrder): string {
assert.doesConformToSchema('order', order, schemas.orderSchema);
const orderHashHex = utils.getOrderHashHex(order);
return orderHashHex;
}
/**
* Instantiates a new ZeroEx instance that provides the public interface to the 0x.js library.
* @param provider The Web3.js Provider instance you would like the 0x.js library to use for interacting with
* the Ethereum network.
* @param config The configuration object. Look up the type for the description.
* @return An instance of the 0x.js ZeroEx class.
*/
constructor(provider: Web3Provider, config: ZeroExConfig) {
assert.isWeb3Provider('provider', provider);
assert.doesConformToSchema('config', config, zeroExConfigSchema);
const artifactJSONs = _.values(artifacts);
const abiArrays = _.map(artifactJSONs, artifact => artifact.abi);
this._abiDecoder = new AbiDecoder(abiArrays);
const defaults = {
gasPrice: config.gasPrice,
};
this._web3Wrapper = new Web3Wrapper(provider, defaults);
this.proxy = new TokenTransferProxyWrapper(
this._web3Wrapper,
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._abiDecoder, this.token,
);
this.orderStateWatcher = new OrderStateWatcher(
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 setProvider(provider: Web3Provider, networkId: number): void {
this._web3Wrapper.setProvider(provider, networkId);
(this.exchange as any)._invalidateContractInstances();
(this.tokenRegistry as any)._invalidateContractInstance();
(this.token as any)._invalidateContractInstances();
(this.proxy as any)._invalidateContractInstance();
(this.etherToken as any)._invalidateContractInstance();
}
/**
* Get user Ethereum addresses available through the supplied web3 provider available for sending transactions.
* @return An array of available user Ethereum addresses.
*/
public async getAvailableAddressesAsync(): Promise<string[]> {
const availableAddresses = await this._web3Wrapper.getAvailableAddressesAsync();
return availableAddresses;
}
/**
* Signs an orderHash and returns it's elliptic curve signature.
* This method currently supports TestRPC, Geth and Parity above and below V1.6.6
* @param orderHash Hex encoded orderHash to sign.
* @param signerAddress The hex encoded Ethereum address you wish to sign it with. This address
* must be available via the Web3.Provider supplied to 0x.js.
* @return An object containing the Elliptic curve signature parameters generated by signing the orderHash.
*/
public async signOrderHashAsync(orderHash: string, signerAddress: string): Promise<ECSignature> {
assert.isHexString('orderHash', orderHash);
await assert.isSenderAddressAsync('signerAddress', signerAddress, this._web3Wrapper);
let msgHashHex;
const nodeVersion = await this._web3Wrapper.getNodeVersionAsync();
const isParityNode = utils.isParityNode(nodeVersion);
const isTestRpc = utils.isTestRpc(nodeVersion);
if (isParityNode || isTestRpc) {
// Parity and TestRpc nodes add the personalMessage prefix itself
msgHashHex = orderHash;
} else {
const orderHashBuff = ethUtil.toBuffer(orderHash);
const msgHashBuff = ethUtil.hashPersonalMessage(orderHashBuff);
msgHashHex = ethUtil.bufferToHex(msgHashBuff);
}
const signature = await this._web3Wrapper.signTransactionAsync(signerAddress, msgHashHex);
// HACK: There is no consensus on whether the signatureHex string should be formatted as
// v + r + s OR r + s + v, and different clients (even different versions of the same client)
// return the signature params in different orders. In order to support all client implementations,
// we parse the signature in both ways, and evaluate if either one is a valid signature.
const validVParamValues = [27, 28];
const ecSignatureVRS = signatureUtils.parseSignatureHexAsVRS(signature);
if (_.includes(validVParamValues, ecSignatureVRS.v)) {
const isValidVRSSignature = ZeroEx.isValidSignature(orderHash, ecSignatureVRS, signerAddress);
if (isValidVRSSignature) {
return ecSignatureVRS;
}
}
const ecSignatureRSV = signatureUtils.parseSignatureHexAsRSV(signature);
if (_.includes(validVParamValues, ecSignatureRSV.v)) {
const isValidRSVSignature = ZeroEx.isValidSignature(orderHash, ecSignatureRSV, signerAddress);
if (isValidRSVSignature) {
return ecSignatureRSV;
}
}
throw new Error(ZeroExError.InvalidSignature);
}
/**
* Waits for a transaction to be mined and returns the transaction receipt.
* @param txHash Transaction hash
* @param pollingIntervalMs How often (in ms) should we check if the transaction is mined.
* @param timeoutMs How long (in ms) to poll for transaction mined until aborting.
* @return Transaction receipt with decoded log args.
*/
public async awaitTransactionMinedAsync(
txHash: string, pollingIntervalMs = 1000, timeoutMs?: number): Promise<TransactionReceiptWithDecodedLogs> {
let timeoutExceeded = false;
if (timeoutMs) {
setTimeout(() => timeoutExceeded = true, timeoutMs);
}
const txReceiptPromise = new Promise(
(resolve: (receipt: TransactionReceiptWithDecodedLogs) => void, reject) => {
const intervalId = intervalUtils.setAsyncExcludingInterval(async () => {
if (timeoutExceeded) {
intervalUtils.clearAsyncExcludingInterval(intervalId);
return reject(ZeroExError.TransactionMiningTimeout);
}
const transactionReceipt = await this._web3Wrapper.getTransactionReceiptAsync(txHash);
if (!_.isNull(transactionReceipt)) {
intervalUtils.clearAsyncExcludingInterval(intervalId);
const logsWithDecodedArgs = _.map(
transactionReceipt.logs,
this._abiDecoder.tryToDecodeLogOrNoop.bind(this._abiDecoder),
);
const transactionReceiptWithDecodedLogArgs: TransactionReceiptWithDecodedLogs = {
...transactionReceipt,
logs: logsWithDecodedArgs,
};
resolve(transactionReceiptWithDecodedLogArgs);
}
}, pollingIntervalMs);
});
return txReceiptPromise;
}
/*
* HACK: `TokenWrapper` needs a token transfer proxy address. `TokenTransferProxy` address is fetched from
* an `ExchangeWrapper`. `ExchangeWrapper` needs `TokenWrapper` to validate orders, creating a dependency cycle.
* In order to break this - we create this function here and pass it as a parameter to the `TokenWrapper`
* and `ProxyWrapper`.
*/
private async _getTokenTransferProxyAddressAsync(): Promise<string> {
const tokenTransferProxyAddress = await (this.exchange as any)._getTokenTransferProxyAddressAsync();
return tokenTransferProxyAddress;
}
}

View File

@@ -0,0 +1,18 @@
import * as DummyTokenArtifact from './artifacts/DummyToken.json';
import * as EtherTokenArtifact from './artifacts/EtherToken.json';
import * as ExchangeArtifact from './artifacts/Exchange.json';
import * as TokenArtifact from './artifacts/Token.json';
import * as TokenRegistryArtifact from './artifacts/TokenRegistry.json';
import * as TokenTransferProxyArtifact from './artifacts/TokenTransferProxy.json';
import * as ZRXArtifact from './artifacts/ZRX.json';
import {Artifact} from './types';
export const artifacts = {
ZRXArtifact: ZRXArtifact as any as Artifact,
DummyTokenArtifact: DummyTokenArtifact as any as Artifact,
TokenArtifact: TokenArtifact as any as Artifact,
ExchangeArtifact: ExchangeArtifact as any as Artifact,
EtherTokenArtifact: EtherTokenArtifact as any as Artifact,
TokenRegistryArtifact: TokenRegistryArtifact as any as Artifact,
TokenTransferProxyArtifact: TokenTransferProxyArtifact as any as Artifact,
};

View File

@@ -0,0 +1,23 @@
{
"contract_name": "DummyToken",
"abi":
[
{
"constant": false,
"inputs": [
{
"name": "_target",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "setBalance",
"outputs": [],
"payable": false,
"type": "function"
}
]
}

View File

@@ -0,0 +1,284 @@
{
"contract_name": "EtherToken",
"abi": [
{
"constant": true,
"inputs": [],
"name": "name",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_spender",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "amount",
"type": "uint256"
}
],
"name": "withdraw",
"outputs": [],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "decimals",
"outputs": [
{
"name": "",
"type": "uint8"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [],
"name": "deposit",
"outputs": [],
"payable": true,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
},
{
"name": "_spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"payable": true,
"type": "fallback"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_from",
"type": "address"
},
{
"indexed": true,
"name": "_to",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_owner",
"type": "address"
},
{
"indexed": true,
"name": "_spender",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_owner",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Deposit",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_owner",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Withdrawal",
"type": "event"
}
],
"networks": {
"1": {
"address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
},
"3": {
"address": "0xc00fd9820cd2898cc4c054b7bf142de637ad129a"
},
"42": {
"address": "0x653e49e301e508a13237c0ddc98ae7d4cd2667a1"
},
"50": {
"address": "0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c"
}
}
}

View File

@@ -0,0 +1,607 @@
{
"contract_name": "Exchange",
"abi": [
{
"constant": true,
"inputs": [
{
"name": "numerator",
"type": "uint256"
},
{
"name": "denominator",
"type": "uint256"
},
{
"name": "target",
"type": "uint256"
}
],
"name": "isRoundingError",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "",
"type": "bytes32"
}
],
"name": "filled",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "",
"type": "bytes32"
}
],
"name": "cancelled",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "orderAddresses",
"type": "address[5][]"
},
{
"name": "orderValues",
"type": "uint256[6][]"
},
{
"name": "fillTakerTokenAmount",
"type": "uint256"
},
{
"name": "shouldThrowOnInsufficientBalanceOrAllowance",
"type": "bool"
},
{
"name": "v",
"type": "uint8[]"
},
{
"name": "r",
"type": "bytes32[]"
},
{
"name": "s",
"type": "bytes32[]"
}
],
"name": "fillOrdersUpTo",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "orderAddresses",
"type": "address[5]"
},
{
"name": "orderValues",
"type": "uint256[6]"
},
{
"name": "cancelTakerTokenAmount",
"type": "uint256"
}
],
"name": "cancelOrder",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "ZRX_TOKEN_CONTRACT",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "orderAddresses",
"type": "address[5][]"
},
{
"name": "orderValues",
"type": "uint256[6][]"
},
{
"name": "fillTakerTokenAmounts",
"type": "uint256[]"
},
{
"name": "v",
"type": "uint8[]"
},
{
"name": "r",
"type": "bytes32[]"
},
{
"name": "s",
"type": "bytes32[]"
}
],
"name": "batchFillOrKillOrders",
"outputs": [],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "orderAddresses",
"type": "address[5]"
},
{
"name": "orderValues",
"type": "uint256[6]"
},
{
"name": "fillTakerTokenAmount",
"type": "uint256"
},
{
"name": "v",
"type": "uint8"
},
{
"name": "r",
"type": "bytes32"
},
{
"name": "s",
"type": "bytes32"
}
],
"name": "fillOrKillOrder",
"outputs": [],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "orderHash",
"type": "bytes32"
}
],
"name": "getUnavailableTakerTokenAmount",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "signer",
"type": "address"
},
{
"name": "hash",
"type": "bytes32"
},
{
"name": "v",
"type": "uint8"
},
{
"name": "r",
"type": "bytes32"
},
{
"name": "s",
"type": "bytes32"
}
],
"name": "isValidSignature",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "numerator",
"type": "uint256"
},
{
"name": "denominator",
"type": "uint256"
},
{
"name": "target",
"type": "uint256"
}
],
"name": "getPartialAmount",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "TOKEN_TRANSFER_PROXY_CONTRACT",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "orderAddresses",
"type": "address[5][]"
},
{
"name": "orderValues",
"type": "uint256[6][]"
},
{
"name": "fillTakerTokenAmounts",
"type": "uint256[]"
},
{
"name": "shouldThrowOnInsufficientBalanceOrAllowance",
"type": "bool"
},
{
"name": "v",
"type": "uint8[]"
},
{
"name": "r",
"type": "bytes32[]"
},
{
"name": "s",
"type": "bytes32[]"
}
],
"name": "batchFillOrders",
"outputs": [],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "orderAddresses",
"type": "address[5][]"
},
{
"name": "orderValues",
"type": "uint256[6][]"
},
{
"name": "cancelTakerTokenAmounts",
"type": "uint256[]"
}
],
"name": "batchCancelOrders",
"outputs": [],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "orderAddresses",
"type": "address[5]"
},
{
"name": "orderValues",
"type": "uint256[6]"
},
{
"name": "fillTakerTokenAmount",
"type": "uint256"
},
{
"name": "shouldThrowOnInsufficientBalanceOrAllowance",
"type": "bool"
},
{
"name": "v",
"type": "uint8"
},
{
"name": "r",
"type": "bytes32"
},
{
"name": "s",
"type": "bytes32"
}
],
"name": "fillOrder",
"outputs": [
{
"name": "filledTakerTokenAmount",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "orderAddresses",
"type": "address[5]"
},
{
"name": "orderValues",
"type": "uint256[6]"
}
],
"name": "getOrderHash",
"outputs": [
{
"name": "",
"type": "bytes32"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "EXTERNAL_QUERY_GAS_LIMIT",
"outputs": [
{
"name": "",
"type": "uint16"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "VERSION",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"type": "function"
},
{
"inputs": [
{
"name": "_zrxToken",
"type": "address"
},
{
"name": "_tokenTransferProxy",
"type": "address"
}
],
"payable": false,
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "maker",
"type": "address"
},
{
"indexed": false,
"name": "taker",
"type": "address"
},
{
"indexed": true,
"name": "feeRecipient",
"type": "address"
},
{
"indexed": false,
"name": "makerToken",
"type": "address"
},
{
"indexed": false,
"name": "takerToken",
"type": "address"
},
{
"indexed": false,
"name": "filledMakerTokenAmount",
"type": "uint256"
},
{
"indexed": false,
"name": "filledTakerTokenAmount",
"type": "uint256"
},
{
"indexed": false,
"name": "paidMakerFee",
"type": "uint256"
},
{
"indexed": false,
"name": "paidTakerFee",
"type": "uint256"
},
{
"indexed": true,
"name": "tokens",
"type": "bytes32"
},
{
"indexed": false,
"name": "orderHash",
"type": "bytes32"
}
],
"name": "LogFill",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "maker",
"type": "address"
},
{
"indexed": true,
"name": "feeRecipient",
"type": "address"
},
{
"indexed": false,
"name": "makerToken",
"type": "address"
},
{
"indexed": false,
"name": "takerToken",
"type": "address"
},
{
"indexed": false,
"name": "cancelledMakerTokenAmount",
"type": "uint256"
},
{
"indexed": false,
"name": "cancelledTakerTokenAmount",
"type": "uint256"
},
{
"indexed": true,
"name": "tokens",
"type": "bytes32"
},
{
"indexed": false,
"name": "orderHash",
"type": "bytes32"
}
],
"name": "LogCancel",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "errorId",
"type": "uint8"
},
{
"indexed": true,
"name": "orderHash",
"type": "bytes32"
}
],
"name": "LogError",
"type": "event"
}
],
"networks": {
"1": {
"address": "0x12459c951127e0c374ff9105dda097662a027093"
},
"3": {
"address": "0x479cc461fecd078f766ecc58533d6f69580cf3ac"
},
"42": {
"address": "0x90fe2af704b34e0224bf2299c838e04d4dcf1364"
},
"50": {
"address": "0x48bacb9266a570d521063ef5dd96e61686dbe788"
}
}
}

View File

@@ -0,0 +1,172 @@
{
"contract_name": "Token",
"abi": [
{
"constant": false,
"inputs": [
{
"name": "_spender",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"name": "supply",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"name": "balance",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
},
{
"name": "_spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"name": "remaining",
"type": "uint256"
}
],
"payable": false,
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_from",
"type": "address"
},
{
"indexed": true,
"name": "_to",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "_owner",
"type": "address"
},
{
"indexed": true,
"name": "_spender",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
}
]
}

View File

@@ -0,0 +1,544 @@
{
"contract_name": "TokenRegistry",
"abi": [
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_index",
"type": "uint256"
}
],
"name": "removeToken",
"outputs": [],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_name",
"type": "string"
}
],
"name": "getTokenAddressByName",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_symbol",
"type": "string"
}
],
"name": "getTokenAddressBySymbol",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_swarmHash",
"type": "bytes"
}
],
"name": "setTokenSwarmHash",
"outputs": [],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_token",
"type": "address"
}
],
"name": "getTokenMetaData",
"outputs": [
{
"name": "",
"type": "address"
},
{
"name": "",
"type": "string"
},
{
"name": "",
"type": "string"
},
{
"name": "",
"type": "uint8"
},
{
"name": "",
"type": "bytes"
},
{
"name": "",
"type": "bytes"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "owner",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_name",
"type": "string"
},
{
"name": "_symbol",
"type": "string"
},
{
"name": "_decimals",
"type": "uint8"
},
{
"name": "_ipfsHash",
"type": "bytes"
},
{
"name": "_swarmHash",
"type": "bytes"
}
],
"name": "addToken",
"outputs": [],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_name",
"type": "string"
}
],
"name": "setTokenName",
"outputs": [],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "",
"type": "address"
}
],
"name": "tokens",
"outputs": [
{
"name": "token",
"type": "address"
},
{
"name": "name",
"type": "string"
},
{
"name": "symbol",
"type": "string"
},
{
"name": "decimals",
"type": "uint8"
},
{
"name": "ipfsHash",
"type": "bytes"
},
{
"name": "swarmHash",
"type": "bytes"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "",
"type": "uint256"
}
],
"name": "tokenAddresses",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_name",
"type": "string"
}
],
"name": "getTokenByName",
"outputs": [
{
"name": "",
"type": "address"
},
{
"name": "",
"type": "string"
},
{
"name": "",
"type": "string"
},
{
"name": "",
"type": "uint8"
},
{
"name": "",
"type": "bytes"
},
{
"name": "",
"type": "bytes"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getTokenAddresses",
"outputs": [
{
"name": "",
"type": "address[]"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_ipfsHash",
"type": "bytes"
}
],
"name": "setTokenIpfsHash",
"outputs": [],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_symbol",
"type": "string"
}
],
"name": "getTokenBySymbol",
"outputs": [
{
"name": "",
"type": "address"
},
{
"name": "",
"type": "string"
},
{
"name": "",
"type": "string"
},
{
"name": "",
"type": "uint8"
},
{
"name": "",
"type": "bytes"
},
{
"name": "",
"type": "bytes"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_token",
"type": "address"
},
{
"name": "_symbol",
"type": "string"
}
],
"name": "setTokenSymbol",
"outputs": [],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"payable": false,
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "token",
"type": "address"
},
{
"indexed": false,
"name": "name",
"type": "string"
},
{
"indexed": false,
"name": "symbol",
"type": "string"
},
{
"indexed": false,
"name": "decimals",
"type": "uint8"
},
{
"indexed": false,
"name": "ipfsHash",
"type": "bytes"
},
{
"indexed": false,
"name": "swarmHash",
"type": "bytes"
}
],
"name": "LogAddToken",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "token",
"type": "address"
},
{
"indexed": false,
"name": "name",
"type": "string"
},
{
"indexed": false,
"name": "symbol",
"type": "string"
},
{
"indexed": false,
"name": "decimals",
"type": "uint8"
},
{
"indexed": false,
"name": "ipfsHash",
"type": "bytes"
},
{
"indexed": false,
"name": "swarmHash",
"type": "bytes"
}
],
"name": "LogRemoveToken",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "token",
"type": "address"
},
{
"indexed": false,
"name": "oldName",
"type": "string"
},
{
"indexed": false,
"name": "newName",
"type": "string"
}
],
"name": "LogTokenNameChange",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "token",
"type": "address"
},
{
"indexed": false,
"name": "oldSymbol",
"type": "string"
},
{
"indexed": false,
"name": "newSymbol",
"type": "string"
}
],
"name": "LogTokenSymbolChange",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "token",
"type": "address"
},
{
"indexed": false,
"name": "oldIpfsHash",
"type": "bytes"
},
{
"indexed": false,
"name": "newIpfsHash",
"type": "bytes"
}
],
"name": "LogTokenIpfsHashChange",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "token",
"type": "address"
},
{
"indexed": false,
"name": "oldSwarmHash",
"type": "bytes"
},
{
"indexed": false,
"name": "newSwarmHash",
"type": "bytes"
}
],
"name": "LogTokenSwarmHashChange",
"type": "event"
}
],
"networks": {
"1": {
"address": "0x926a74c5c36adf004c87399e65f75628b0f98d2c"
},
"3": {
"address": "0x6b1a50f0bb5a7995444bd3877b22dc89c62843ed"
},
"42": {
"address": "0xf18e504561f4347bea557f3d4558f559dddbae7f"
},
"50": {
"address": "0x0b1ba0af832d7c05fd64161e0db78e85978e8082"
}
}
}

View File

@@ -0,0 +1,184 @@
{
"contract_name": "TokenTransferProxy",
"abi": [
{
"constant": false,
"inputs": [
{
"name": "token",
"type": "address"
},
{
"name": "from",
"type": "address"
},
{
"name": "to",
"type": "address"
},
{
"name": "value",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "target",
"type": "address"
}
],
"name": "addAuthorizedAddress",
"outputs": [],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "",
"type": "uint256"
}
],
"name": "authorities",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "target",
"type": "address"
}
],
"name": "removeAuthorizedAddress",
"outputs": [],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "owner",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "",
"type": "address"
}
],
"name": "authorized",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getAuthorizedAddresses",
"outputs": [
{
"name": "",
"type": "address[]"
}
],
"payable": false,
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"payable": false,
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "target",
"type": "address"
},
{
"indexed": true,
"name": "caller",
"type": "address"
}
],
"name": "LogAuthorizedAddressAdded",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "target",
"type": "address"
},
{
"indexed": true,
"name": "caller",
"type": "address"
}
],
"name": "LogAuthorizedAddressRemoved",
"type": "event"
}
],
"networks": {
"1": {
"address": "0x8da0d80f5007ef1e431dd2127178d224e32c2ef4"
},
"3": {
"address": "0x4e9aad8184de8833365fea970cd9149372fdf1e6"
},
"42": {
"address": "0x087eed4bc1ee3de49befbd66c662b434b15d49d4"
},
"50": {
"address": "0x1dc4c1cefef38a777b15aa20260a54e584b16c48"
}
}
}

View File

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

View File

@@ -0,0 +1,191 @@
import {intervalUtils} from '@0xproject/utils';
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import {Block, BlockAndLogStreamer} from 'ethereumjs-blockstream';
import * as _ from 'lodash';
import * as Web3 from 'web3';
import {
Artifact,
BlockParamLiteral,
BlockRange,
ContractEventArgs,
ContractEvents,
EventCallback,
IndexedFilterValues,
InternalZeroExError,
LogWithDecodedArgs,
RawLog,
ZeroExError,
} from '../types';
import {AbiDecoder} from '../utils/abi_decoder';
import {constants} from '../utils/constants';
import {filterUtils} from '../utils/filter_utils';
const CONTRACT_NAME_TO_NOT_FOUND_ERROR: {[contractName: string]: ZeroExError} = {
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 _blockAndLogStreamerIfExists: BlockAndLogStreamer|undefined;
private _blockAndLogStreamInterval: NodeJS.Timer;
private _filters: {[filterToken: string]: Web3.FilterObject};
private _filterCallbacks: {[filterToken: string]: EventCallback<ContractEventArgs>};
private _onLogAddedSubscriptionToken: string|undefined;
private _onLogRemovedSubscriptionToken: string|undefined;
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder?: AbiDecoder) {
this._web3Wrapper = web3Wrapper;
this._networkId = networkId;
this._abiDecoder = abiDecoder;
this._filters = {};
this._filterCallbacks = {};
this._blockAndLogStreamerIfExists = undefined;
this._onLogAddedSubscriptionToken = undefined;
this._onLogRemovedSubscriptionToken = undefined;
}
protected unsubscribeAll(): void {
const filterTokens = _.keys(this._filterCallbacks);
_.each(filterTokens, filterToken => {
this._unsubscribe(filterToken);
});
}
protected _unsubscribe(filterToken: string, err?: Error): void {
if (_.isUndefined(this._filters[filterToken])) {
throw new Error(ZeroExError.SubscriptionNotFound);
}
if (!_.isUndefined(err)) {
const callback = this._filterCallbacks[filterToken];
callback(err, undefined);
}
delete this._filters[filterToken];
delete this._filterCallbacks[filterToken];
if (_.isEmpty(this._filters)) {
this._stopBlockAndLogStream();
}
}
protected _subscribe<ArgsType extends ContractEventArgs>(
address: string, eventName: ContractEvents, indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi,
callback: EventCallback<ArgsType>): string {
const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi);
if (_.isUndefined(this._blockAndLogStreamerIfExists)) {
this._startBlockAndLogStream();
}
const filterToken = filterUtils.generateUUID();
this._filters[filterToken] = filter;
this._filterCallbacks[filterToken] = callback;
return filterToken;
}
protected async _getLogsAsync<ArgsType extends ContractEventArgs>(
address: string, eventName: ContractEvents, blockRange: BlockRange,
indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi, blockRange);
const logs = await this._web3Wrapper.getLogsAsync(filter);
const logsWithDecodedArguments = _.map(logs, this._tryToDecodeLogOrNoop.bind(this));
return logsWithDecodedArguments;
}
protected _tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>(
log: Web3.LogEntry): LogWithDecodedArgs<ArgsType>|RawLog {
if (_.isUndefined(this._abiDecoder)) {
throw new Error(InternalZeroExError.NoAbiDecoder);
}
const logWithDecodedArgs = this._abiDecoder.tryToDecodeLogOrNoop(log);
return logWithDecodedArgs;
}
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;
}
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 = {
log: decodedLog,
isRemoved,
};
this._filterCallbacks[filterToken](null, logEvent);
}
});
}
private _startBlockAndLogStream(): void {
if (!_.isUndefined(this._blockAndLogStreamerIfExists)) {
throw new Error(ZeroExError.SubscriptionAlreadyPresent);
}
this._blockAndLogStreamerIfExists = new BlockAndLogStreamer(
this._web3Wrapper.getBlockAsync.bind(this._web3Wrapper),
this._web3Wrapper.getLogsAsync.bind(this._web3Wrapper),
);
const catchAllLogFilter = {};
this._blockAndLogStreamerIfExists.addLogFilter(catchAllLogFilter);
this._blockAndLogStreamInterval = intervalUtils.setAsyncExcludingInterval(
this._reconcileBlockAsync.bind(this), constants.DEFAULT_BLOCK_POLLING_INTERVAL,
);
let isRemoved = false;
this._onLogAddedSubscriptionToken = this._blockAndLogStreamerIfExists.subscribeToOnLogAdded(
this._onLogStateChanged.bind(this, isRemoved),
);
isRemoved = true;
this._onLogRemovedSubscriptionToken = this._blockAndLogStreamerIfExists.subscribeToOnLogRemoved(
this._onLogStateChanged.bind(this, isRemoved),
);
}
private _stopBlockAndLogStream(): void {
if (_.isUndefined(this._blockAndLogStreamerIfExists)) {
throw new Error(ZeroExError.SubscriptionNotFound);
}
this._blockAndLogStreamerIfExists.unsubscribeFromOnLogAdded(this._onLogAddedSubscriptionToken as string);
this._blockAndLogStreamerIfExists.unsubscribeFromOnLogRemoved(this._onLogRemovedSubscriptionToken as string);
intervalUtils.clearAsyncExcludingInterval(this._blockAndLogStreamInterval);
delete this._blockAndLogStreamerIfExists;
}
private async _reconcileBlockAsync(): Promise<void> {
try {
const latestBlock = await this._web3Wrapper.getBlockAsync(BlockParamLiteral.Latest);
// We need to coerce to Block type cause Web3.Block includes types for mempool blocks
if (!_.isUndefined(this._blockAndLogStreamerIfExists)) {
// If we clear the interval while fetching the block - this._blockAndLogStreamer will be undefined
await this._blockAndLogStreamerIfExists.reconcileNewBlock(latestBlock as any as Block);
}
} catch (err) {
const filterTokens = _.keys(this._filterCallbacks);
_.each(filterTokens, filterToken => {
this._unsubscribe(filterToken, err);
});
}
}
}

View File

@@ -0,0 +1,161 @@
import {schemas} from '@0xproject/json-schemas';
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import BigNumber from 'bignumber.js';
import * as _ from 'lodash';
import {artifacts} from '../artifacts';
import {
BlockRange,
EtherTokenContractEventArgs,
EtherTokenEvents,
EventCallback,
IndexedFilterValues,
LogWithDecodedArgs,
TransactionOpts,
ZeroExError,
} from '../types';
import {AbiDecoder} from '../utils/abi_decoder';
import {assert} from '../utils/assert';
import {ContractWrapper} from './contract_wrapper';
import {EtherTokenContract} from './generated/ether_token';
import {TokenWrapper} from './token_wrapper';
/**
* This class includes all the functionality related to interacting with a wrapped Ether ERC20 token contract.
* The caller can convert ETH into the equivalent number of wrapped ETH ERC20 tokens and back.
*/
export class EtherTokenWrapper extends ContractWrapper {
private _etherTokenContractsByAddress: {[address: string]: EtherTokenContract} = {};
private _tokenWrapper: TokenWrapper;
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder: AbiDecoder, tokenWrapper: TokenWrapper) {
super(web3Wrapper, networkId, abiDecoder);
this._tokenWrapper = tokenWrapper;
}
/**
* Deposit ETH into the Wrapped ETH smart contract and issues the equivalent number of wrapped ETH tokens
* to the depositor address. These wrapped ETH tokens can be used in 0x trades and are redeemable for 1-to-1
* for ETH.
* @param etherTokenAddress EtherToken address you wish to deposit into.
* @param amountInWei Amount of ETH in Wei the caller wishes to deposit.
* @param depositor The hex encoded user Ethereum address that would like to make the deposit.
* @param txOpts Transaction parameters.
* @return Transaction hash.
*/
public async depositAsync(
etherTokenAddress: string, amountInWei: BigNumber, depositor: string, txOpts: TransactionOpts = {},
): Promise<string> {
assert.isValidBaseUnitAmount('amountInWei', amountInWei);
await assert.isSenderAddressAsync('depositor', depositor, this._web3Wrapper);
const ethBalanceInWei = await this._web3Wrapper.getBalanceInWeiAsync(depositor);
assert.assert(ethBalanceInWei.gte(amountInWei), ZeroExError.InsufficientEthBalanceForDeposit);
const wethContract = await this._getEtherTokenContractAsync(etherTokenAddress);
const txHash = await wethContract.deposit.sendTransactionAsync({
from: depositor,
value: amountInWei,
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
});
return txHash;
}
/**
* Withdraw ETH to the withdrawer's address from the wrapped ETH smart contract in exchange for the
* equivalent number of wrapped ETH tokens.
* @param etherTokenAddress EtherToken address you wish to withdraw from.
* @param amountInWei Amount of ETH in Wei the caller wishes to withdraw.
* @param withdrawer The hex encoded user Ethereum address that would like to make the withdrawl.
* @param txOpts Transaction parameters.
* @return Transaction hash.
*/
public async withdrawAsync(
etherTokenAddress: string, amountInWei: BigNumber, withdrawer: string, txOpts: TransactionOpts = {},
): Promise<string> {
assert.isValidBaseUnitAmount('amountInWei', amountInWei);
await assert.isSenderAddressAsync('withdrawer', withdrawer, this._web3Wrapper);
const WETHBalanceInBaseUnits = await this._tokenWrapper.getBalanceAsync(etherTokenAddress, withdrawer);
assert.assert(WETHBalanceInBaseUnits.gte(amountInWei), ZeroExError.InsufficientWEthBalanceForWithdrawal);
const wethContract = await this._getEtherTokenContractAsync(etherTokenAddress);
const txHash = await wethContract.withdraw.sendTransactionAsync(amountInWei, {
from: withdrawer,
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
});
return txHash;
}
/**
* Gets historical logs without creating a subscription
* @param etherTokenAddress An address of the ether token that emmited the logs.
* @param eventName The ether token contract event you would like to subscribe to.
* @param blockRange Block range to get logs from.
* @param indexFilterValues An object where the keys are indexed args returned by the event and
* the value is the value you are interested in. E.g `{_owner: aUserAddressHex}`
* @return Array of logs that match the parameters
*/
public async getLogsAsync<ArgsType extends EtherTokenContractEventArgs>(
etherTokenAddress: string, eventName: EtherTokenEvents, blockRange: BlockRange,
indexFilterValues: IndexedFilterValues): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
assert.isETHAddressHex('etherTokenAddress', etherTokenAddress);
assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents);
assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
const logs = await this._getLogsAsync<ArgsType>(
etherTokenAddress, eventName, blockRange, indexFilterValues, artifacts.EtherTokenArtifact.abi,
);
return logs;
}
/**
* Subscribe to an event type emitted by the Token contract.
* @param etherTokenAddress The hex encoded address where the ether token is deployed.
* @param eventName The ether token contract event you would like to subscribe to.
* @param indexFilterValues An object where the keys are indexed args returned by the event and
* the value is the value you are interested in. E.g `{_owner: aUserAddressHex}`
* @param callback Callback that gets called when a log is added/removed
* @return Subscription token used later to unsubscribe
*/
public subscribe<ArgsType extends EtherTokenContractEventArgs>(
etherTokenAddress: string, eventName: EtherTokenEvents, indexFilterValues: IndexedFilterValues,
callback: EventCallback<ArgsType>): string {
assert.isETHAddressHex('etherTokenAddress', etherTokenAddress);
assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
assert.isFunction('callback', callback);
const subscriptionToken = this._subscribe<ArgsType>(
etherTokenAddress, eventName, indexFilterValues, artifacts.EtherTokenArtifact.abi, callback,
);
return subscriptionToken;
}
/**
* Cancel a subscription
* @param subscriptionToken Subscription token returned by `subscribe()`
*/
public unsubscribe(subscriptionToken: string): void {
this._unsubscribe(subscriptionToken);
}
/**
* Cancels all existing subscriptions
*/
public unsubscribeAll(): void {
super.unsubscribeAll();
}
private _invalidateContractInstance(): void {
this.unsubscribeAll();
this._etherTokenContractsByAddress = {};
}
private async _getEtherTokenContractAsync(etherTokenAddress: string): Promise<EtherTokenContract> {
let etherTokenContract = this._etherTokenContractsByAddress[etherTokenAddress];
if (!_.isUndefined(etherTokenContract)) {
return etherTokenContract;
}
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
artifacts.EtherTokenArtifact, etherTokenAddress,
);
const contractInstance = new EtherTokenContract(web3ContractInstance, this._web3Wrapper.getContractDefaults());
etherTokenContract = contractInstance;
this._etherTokenContractsByAddress[etherTokenAddress] = etherTokenContract;
return etherTokenContract;
}
}

View File

@@ -0,0 +1,808 @@
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 {artifacts} from '../artifacts';
import {
BlockParamLiteral,
BlockRange,
DecodedLogArgs,
ECSignature,
EventCallback,
ExchangeContractErrCodes,
ExchangeContractErrs,
ExchangeContractEventArgs,
ExchangeEvents,
IndexedFilterValues,
LogErrorContractEventArgs,
LogWithDecodedArgs,
MethodOpts,
Order,
OrderAddresses,
OrderCancellationRequest,
OrderFillRequest,
OrderTransactionOpts,
OrderValues,
SignedOrder,
ValidateOrderFillableOpts,
} from '../types';
import {AbiDecoder} from '../utils/abi_decoder';
import {assert} from '../utils/assert';
import {decorators} from '../utils/decorators';
import {ExchangeTransferSimulator} from '../utils/exchange_transfer_simulator';
import {OrderValidationUtils} from '../utils/order_validation_utils';
import {utils} from '../utils/utils';
import {ContractWrapper} from './contract_wrapper';
import {ExchangeContract} from './generated/exchange';
import {TokenWrapper} from './token_wrapper';
const SHOULD_VALIDATE_BY_DEFAULT = true;
interface ExchangeContractErrCodesToMsgs {
[exchangeContractErrCodes: number]: string;
}
/**
* This class includes all the functionality related to calling methods and subscribing to
* events of the 0x Exchange smart contract.
*/
export class ExchangeWrapper extends ContractWrapper {
private _exchangeContractIfExists?: ExchangeContract;
private _orderValidationUtils: OrderValidationUtils;
private _tokenWrapper: TokenWrapper;
private _exchangeContractErrCodesToMsg: ExchangeContractErrCodesToMsgs = {
[ExchangeContractErrCodes.ERROR_FILL_EXPIRED]: ExchangeContractErrs.OrderFillExpired,
[ExchangeContractErrCodes.ERROR_CANCEL_EXPIRED]: ExchangeContractErrs.OrderFillExpired,
[ExchangeContractErrCodes.ERROR_FILL_NO_VALUE]: ExchangeContractErrs.OrderRemainingFillAmountZero,
[ExchangeContractErrCodes.ERROR_CANCEL_NO_VALUE]: ExchangeContractErrs.OrderRemainingFillAmountZero,
[ExchangeContractErrCodes.ERROR_FILL_TRUNCATION]: ExchangeContractErrs.OrderFillRoundingError,
[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,
order.taker,
order.makerTokenAddress,
order.takerTokenAddress,
order.feeRecipient,
];
const orderValues: OrderValues = [
order.makerTokenAmount,
order.takerTokenAmount,
order.makerFee,
order.takerFee,
order.expirationUnixTimestampSec,
order.salt,
];
return [orderAddresses, orderValues];
}
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder: AbiDecoder,
tokenWrapper: TokenWrapper, contractAddressIfExists?: string) {
super(web3Wrapper, networkId, abiDecoder);
this._tokenWrapper = tokenWrapper;
this._orderValidationUtils = new OrderValidationUtils(this);
this._contractAddressIfExists = contractAddressIfExists;
}
/**
* Returns the unavailable takerAmount of an order. Unavailable amount is defined as the total
* amount that has been filled or cancelled. The remaining takerAmount can be calculated by
* subtracting the unavailable amount from the total order takerAmount.
* @param orderHash The hex encoded orderHash for which you would like to retrieve the
* unavailable takerAmount.
* @param methodOpts Optional arguments this method accepts.
* @return The amount of the order (in taker tokens) that has either been filled or cancelled.
*/
public async getUnavailableTakerAmountAsync(orderHash: string,
methodOpts?: MethodOpts): Promise<BigNumber> {
assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
const exchangeContract = await this._getExchangeContractAsync();
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
let unavailableTakerTokenAmount = await exchangeContract.getUnavailableTakerTokenAmount.callAsync(
orderHash, defaultBlock,
);
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
unavailableTakerTokenAmount = new BigNumber(unavailableTakerTokenAmount);
return unavailableTakerTokenAmount;
}
/**
* Retrieve the takerAmount of an order that has already been filled.
* @param orderHash The hex encoded orderHash for which you would like to retrieve the filled takerAmount.
* @param methodOpts Optional arguments this method accepts.
* @return The amount of the order (in taker tokens) that has already been filled.
*/
public async getFilledTakerAmountAsync(orderHash: string, methodOpts?: MethodOpts): Promise<BigNumber> {
assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
const exchangeContract = await this._getExchangeContractAsync();
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
let fillAmountInBaseUnits = await exchangeContract.filled.callAsync(orderHash, defaultBlock);
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
fillAmountInBaseUnits = new BigNumber(fillAmountInBaseUnits);
return fillAmountInBaseUnits;
}
/**
* Retrieve the takerAmount of an order that has been cancelled.
* @param orderHash The hex encoded orderHash for which you would like to retrieve the
* cancelled takerAmount.
* @param methodOpts Optional arguments this method accepts.
* @return The amount of the order (in taker tokens) that has been cancelled.
*/
public async getCancelledTakerAmountAsync(orderHash: string, methodOpts?: MethodOpts): Promise<BigNumber> {
assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
const exchangeContract = await this._getExchangeContractAsync();
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
let cancelledAmountInBaseUnits = await exchangeContract.cancelled.callAsync(orderHash, defaultBlock);
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
cancelledAmountInBaseUnits = new BigNumber(cancelledAmountInBaseUnits);
return cancelledAmountInBaseUnits;
}
/**
* Fills a signed order with an amount denominated in baseUnits of the taker token.
* Since the order in which transactions are included in the next block is indeterminate, race-conditions
* could arise where a users balance or allowance changes before the fillOrder executes. Because of this,
* we allow you to specify `shouldThrowOnInsufficientBalanceOrAllowance`.
* If false, the smart contract will not throw if the parties
* do not have sufficient balances/allowances, preserving gas costs. Setting it to true forgoes this check
* and causes the smart contract to throw (using all the gas supplied) instead.
* @param signedOrder An object that conforms to the SignedOrder interface.
* @param fillTakerTokenAmount The amount of the order (in taker tokens baseUnits) that
* you wish to fill.
* @param shouldThrowOnInsufficientBalanceOrAllowance Whether or not you wish for the contract call to throw
* if upon execution the tokens cannot be transferred.
* @param takerAddress The user Ethereum address who would like to fill this order.
* Must be available via the supplied Web3.Provider
* passed to 0x.js.
* @param orderTransactionOpts Optional arguments this method accepts.
* @return Transaction hash.
*/
@decorators.asyncZeroExErrorHandler
public async fillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber,
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
takerAddress: string,
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
const exchangeInstance = await this._getExchangeContractAsync();
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
SHOULD_VALIDATE_BY_DEFAULT :
orderTransactionOpts.shouldValidate;
if (shouldValidate) {
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 txHash: string = await exchangeInstance.fillOrder.sendTransactionAsync(
orderAddresses,
orderValues,
fillTakerTokenAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
signedOrder.ecSignature.v,
signedOrder.ecSignature.r,
signedOrder.ecSignature.s,
{
from: takerAddress,
gas: orderTransactionOpts.gasLimit,
gasPrice: orderTransactionOpts.gasPrice,
},
);
return txHash;
}
/**
* Sequentially and atomically fills signedOrders up to the specified takerTokenFillAmount.
* If the fill amount is reached - it succeeds and does not fill the rest of the orders.
* If fill amount is not reached - it fills as much of the fill amount as possible and succeeds.
* @param signedOrders The array of signedOrders that you would like to fill until
* takerTokenFillAmount is reached.
* @param fillTakerTokenAmount The total amount of the takerTokens you would like to fill.
* @param shouldThrowOnInsufficientBalanceOrAllowance Whether or not you wish for the contract call to throw if
* upon execution any of the tokens cannot be transferred.
* If set to false, the call will continue to fill subsequent
* signedOrders even when some cannot be filled.
* @param takerAddress The user Ethereum address who would like to fill these
* orders. Must be available via the supplied Web3.Provider
* passed to 0x.js.
* @param orderTransactionOpts Optional arguments this method accepts.
* @return Transaction hash.
*/
@decorators.asyncZeroExErrorHandler
public async fillOrdersUpToAsync(signedOrders: SignedOrder[], fillTakerTokenAmount: BigNumber,
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
takerAddress: string,
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema);
const takerTokenAddresses = _.map(signedOrders, signedOrder => signedOrder.takerTokenAddress);
assert.hasAtMostOneUniqueValue(takerTokenAddresses,
ExchangeContractErrs.MultipleTakerTokensInFillUpToDisallowed);
const exchangeContractAddresses = _.map(signedOrders, signedOrder => signedOrder.exchangeContractAddress);
assert.hasAtMostOneUniqueValue(exchangeContractAddresses,
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress);
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
SHOULD_VALIDATE_BY_DEFAULT :
orderTransactionOpts.shouldValidate;
if (shouldValidate) {
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);
}
}
if (_.isEmpty(signedOrders)) {
throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
}
const orderAddressesValuesAndSignatureArray = _.map(signedOrders, signedOrder => {
return [
...ExchangeWrapper._getOrderAddressesAndValues(signedOrder),
signedOrder.ecSignature.v,
signedOrder.ecSignature.r,
signedOrder.ecSignature.s,
];
});
// We use _.unzip<any> because _.unzip doesn't type check if values have different types :'(
const [orderAddressesArray, orderValuesArray, vArray, rArray, sArray] = _.unzip<any>(
orderAddressesValuesAndSignatureArray,
);
const exchangeInstance = await this._getExchangeContractAsync();
const txHash = await exchangeInstance.fillOrdersUpTo.sendTransactionAsync(
orderAddressesArray,
orderValuesArray,
fillTakerTokenAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
vArray,
rArray,
sArray,
{
from: takerAddress,
gas: orderTransactionOpts.gasLimit,
gasPrice: orderTransactionOpts.gasPrice,
},
);
return txHash;
}
/**
* Batch version of fillOrderAsync.
* Executes multiple fills atomically in a single transaction.
* If shouldThrowOnInsufficientBalanceOrAllowance is set to false, it will continue filling subsequent orders even
* when earlier ones fail.
* When shouldThrowOnInsufficientBalanceOrAllowance is set to true, if any fill fails, the entire batch fails.
* @param orderFillRequests An array of objects that conform to the
* OrderFillRequest interface.
* @param shouldThrowOnInsufficientBalanceOrAllowance Whether or not you wish for the contract call to throw
* if upon execution any of the tokens cannot be
* transferred. If set to false, the call will continue to
* fill subsequent signedOrders even when some
* cannot be filled.
* @param takerAddress The user Ethereum address who would like to fill
* these orders. Must be available via the supplied
* Web3.Provider passed to 0x.js.
* @param orderTransactionOpts Optional arguments this method accepts.
* @return Transaction hash.
*/
@decorators.asyncZeroExErrorHandler
public async batchFillOrdersAsync(orderFillRequests: OrderFillRequest[],
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
takerAddress: string,
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema);
const exchangeContractAddresses = _.map(
orderFillRequests,
orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress,
);
assert.hasAtMostOneUniqueValue(exchangeContractAddresses,
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress);
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
SHOULD_VALIDATE_BY_DEFAULT :
orderTransactionOpts.shouldValidate;
if (shouldValidate) {
const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
for (const orderFillRequest of orderFillRequests) {
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, orderFillRequest.signedOrder, orderFillRequest.takerTokenFillAmount,
takerAddress, zrxTokenAddress,
);
}
}
if (_.isEmpty(orderFillRequests)) {
throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
}
const orderAddressesValuesAmountsAndSignatureArray = _.map(orderFillRequests, orderFillRequest => {
return [
...ExchangeWrapper._getOrderAddressesAndValues(orderFillRequest.signedOrder),
orderFillRequest.takerTokenFillAmount,
orderFillRequest.signedOrder.ecSignature.v,
orderFillRequest.signedOrder.ecSignature.r,
orderFillRequest.signedOrder.ecSignature.s,
];
});
// We use _.unzip<any> because _.unzip doesn't type check if values have different types :'(
const [orderAddressesArray, orderValuesArray, fillTakerTokenAmounts, vArray, rArray, sArray] = _.unzip<any>(
orderAddressesValuesAmountsAndSignatureArray,
);
const exchangeInstance = await this._getExchangeContractAsync();
const txHash = await exchangeInstance.batchFillOrders.sendTransactionAsync(
orderAddressesArray,
orderValuesArray,
fillTakerTokenAmounts,
shouldThrowOnInsufficientBalanceOrAllowance,
vArray,
rArray,
sArray,
{
from: takerAddress,
gas: orderTransactionOpts.gasLimit,
gasPrice: orderTransactionOpts.gasPrice,
},
);
return txHash;
}
/**
* Attempts to fill a specific amount of an order. If the entire amount specified cannot be filled,
* the fill order is abandoned.
* @param signedOrder An object that conforms to the SignedOrder interface. The
* signedOrder you wish to fill.
* @param fillTakerTokenAmount The total amount of the takerTokens you would like to fill.
* @param takerAddress The user Ethereum address who would like to fill this order.
* Must be available via the supplied Web3.Provider passed to 0x.js.
* @param orderTransactionOpts Optional arguments this method accepts.
* @return Transaction hash.
*/
@decorators.asyncZeroExErrorHandler
public async fillOrKillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber,
takerAddress: string,
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
const exchangeInstance = await this._getExchangeContractAsync();
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
SHOULD_VALIDATE_BY_DEFAULT :
orderTransactionOpts.shouldValidate;
if (shouldValidate) {
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 txHash = await exchangeInstance.fillOrKillOrder.sendTransactionAsync(
orderAddresses,
orderValues,
fillTakerTokenAmount,
signedOrder.ecSignature.v,
signedOrder.ecSignature.r,
signedOrder.ecSignature.s,
{
from: takerAddress,
gas: orderTransactionOpts.gasLimit,
gasPrice: orderTransactionOpts.gasPrice,
},
);
return txHash;
}
/**
* Batch version of fillOrKill. Allows a taker to specify a batch of orders that will either be atomically
* filled (each to the specified fillAmount) or aborted.
* @param orderFillRequests An array of objects that conform to the OrderFillRequest interface.
* @param takerAddress The user Ethereum address who would like to fill there orders.
* Must be available via the supplied Web3.Provider passed to 0x.js.
* @param orderTransactionOpts Optional arguments this method accepts.
* @return Transaction hash.
*/
@decorators.asyncZeroExErrorHandler
public async batchFillOrKillAsync(orderFillRequests: OrderFillRequest[],
takerAddress: string,
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
assert.doesConformToSchema('orderFillRequests', orderFillRequests,
schemas.orderFillRequestsSchema);
const exchangeContractAddresses = _.map(
orderFillRequests,
orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress,
);
assert.hasAtMostOneUniqueValue(exchangeContractAddresses,
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
if (_.isEmpty(orderFillRequests)) {
throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
}
const exchangeInstance = await this._getExchangeContractAsync();
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
SHOULD_VALIDATE_BY_DEFAULT :
orderTransactionOpts.shouldValidate;
if (shouldValidate) {
const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
for (const orderFillRequest of orderFillRequests) {
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, orderFillRequest.signedOrder, orderFillRequest.takerTokenFillAmount,
takerAddress, zrxTokenAddress,
);
}
}
const orderAddressesValuesAndTakerTokenFillAmounts = _.map(orderFillRequests, request => {
return [
...ExchangeWrapper._getOrderAddressesAndValues(request.signedOrder),
request.takerTokenFillAmount,
request.signedOrder.ecSignature.v,
request.signedOrder.ecSignature.r,
request.signedOrder.ecSignature.s,
];
});
// 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 txHash = await exchangeInstance.batchFillOrKillOrders.sendTransactionAsync(
orderAddresses,
orderValues,
fillTakerTokenAmounts,
vParams,
rParams,
sParams,
{
from: takerAddress,
gas: orderTransactionOpts.gasLimit,
gasPrice: orderTransactionOpts.gasPrice,
},
);
return txHash;
}
/**
* Cancel a given fill amount of an order. Cancellations are cumulative.
* @param order An object that conforms to the Order or SignedOrder interface.
* The order you would like to cancel.
* @param cancelTakerTokenAmount The amount (specified in taker tokens) that you would like to cancel.
* @param transactionOpts Optional arguments this method accepts.
* @return Transaction hash.
*/
@decorators.asyncZeroExErrorHandler
public async cancelOrderAsync(order: Order|SignedOrder,
cancelTakerTokenAmount: BigNumber,
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
assert.doesConformToSchema('order', order, schemas.orderSchema);
assert.isValidBaseUnitAmount('takerTokenCancelAmount', cancelTakerTokenAmount);
await assert.isSenderAddressAsync('order.maker', order.maker, this._web3Wrapper);
const exchangeInstance = await this._getExchangeContractAsync();
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
SHOULD_VALIDATE_BY_DEFAULT :
orderTransactionOpts.shouldValidate;
if (shouldValidate) {
const orderHash = utils.getOrderHashHex(order);
const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
OrderValidationUtils.validateCancelOrderThrowIfInvalid(
order, cancelTakerTokenAmount, unavailableTakerTokenAmount);
}
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order);
const txHash = await exchangeInstance.cancelOrder.sendTransactionAsync(
orderAddresses,
orderValues,
cancelTakerTokenAmount,
{
from: order.maker,
gas: orderTransactionOpts.gasLimit,
gasPrice: orderTransactionOpts.gasPrice,
},
);
return txHash;
}
/**
* Batch version of cancelOrderAsync. Atomically cancels multiple orders in a single transaction.
* All orders must be from the same maker.
* @param orderCancellationRequests An array of objects that conform to the OrderCancellationRequest
* interface.
* @param transactionOpts Optional arguments this method accepts.
* @return Transaction hash.
*/
@decorators.asyncZeroExErrorHandler
public async batchCancelOrdersAsync(orderCancellationRequests: OrderCancellationRequest[],
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
assert.doesConformToSchema('orderCancellationRequests', orderCancellationRequests,
schemas.orderCancellationRequestsSchema);
const exchangeContractAddresses = _.map(
orderCancellationRequests,
orderCancellationRequest => orderCancellationRequest.order.exchangeContractAddress,
);
assert.hasAtMostOneUniqueValue(exchangeContractAddresses,
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress);
const makers = _.map(orderCancellationRequests, cancellationRequest => cancellationRequest.order.maker);
assert.hasAtMostOneUniqueValue(makers, ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed);
const maker = makers[0];
await assert.isSenderAddressAsync('maker', maker, this._web3Wrapper);
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
SHOULD_VALIDATE_BY_DEFAULT :
orderTransactionOpts.shouldValidate;
if (shouldValidate) {
for (const orderCancellationRequest of orderCancellationRequests) {
const orderHash = utils.getOrderHashHex(orderCancellationRequest.order);
const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
OrderValidationUtils.validateCancelOrderThrowIfInvalid(
orderCancellationRequest.order, orderCancellationRequest.takerTokenCancelAmount,
unavailableTakerTokenAmount,
);
}
}
if (_.isEmpty(orderCancellationRequests)) {
throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
}
const exchangeInstance = await this._getExchangeContractAsync();
const orderAddressesValuesAndTakerTokenCancelAmounts = _.map(orderCancellationRequests, cancellationRequest => {
return [
...ExchangeWrapper._getOrderAddressesAndValues(cancellationRequest.order),
cancellationRequest.takerTokenCancelAmount,
];
});
// We use _.unzip<any> because _.unzip doesn't type check if values have different types :'(
const [orderAddresses, orderValues, cancelTakerTokenAmounts] =
_.unzip<any>(orderAddressesValuesAndTakerTokenCancelAmounts);
const txHash = await exchangeInstance.batchCancelOrders.sendTransactionAsync(
orderAddresses,
orderValues,
cancelTakerTokenAmounts,
{
from: maker,
gas: orderTransactionOpts.gasLimit,
gasPrice: orderTransactionOpts.gasPrice,
},
);
return txHash;
}
/**
* Subscribe to an event type emitted by the Exchange contract.
* @param eventName The exchange contract event you would like to subscribe to.
* @param indexFilterValues An object where the keys are indexed args returned by the event and
* the value is the value you are interested in. E.g `{maker: aUserAddressHex}`
* @param callback Callback that gets called when a log is added/removed
* @return Subscription token used later to unsubscribe
*/
public subscribe<ArgsType extends ExchangeContractEventArgs>(
eventName: ExchangeEvents, indexFilterValues: IndexedFilterValues,
callback: EventCallback<ArgsType>): string {
assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
assert.isFunction('callback', callback);
const exchangeContractAddress = this.getContractAddress();
const subscriptionToken = this._subscribe<ArgsType>(
exchangeContractAddress, eventName, indexFilterValues, artifacts.ExchangeArtifact.abi, callback,
);
return subscriptionToken;
}
/**
* Cancel a subscription
* @param subscriptionToken Subscription token returned by `subscribe()`
*/
public unsubscribe(subscriptionToken: string): void {
this._unsubscribe(subscriptionToken);
}
/**
* Cancels all existing subscriptions
*/
public unsubscribeAll(): void {
super.unsubscribeAll();
}
/**
* Gets historical logs without creating a subscription
* @param eventName The exchange contract event you would like to subscribe to.
* @param blockRange Block range to get logs from.
* @param indexFilterValues An object where the keys are indexed args returned by the event and
* the value is the value you are interested in. E.g `{_from: aUserAddressHex}`
* @return Array of logs that match the parameters
*/
public async getLogsAsync<ArgsType extends ExchangeContractEventArgs>(
eventName: ExchangeEvents, blockRange: BlockRange, indexFilterValues: IndexedFilterValues,
): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
const exchangeContractAddress = this.getContractAddress();
const logs = await this._getLogsAsync<ArgsType>(
exchangeContractAddress, eventName, blockRange, indexFilterValues, artifacts.ExchangeArtifact.abi,
);
return logs;
}
/**
* Retrieves the Ethereum address of the Exchange contract deployed on the network
* that the user-passed web3 provider is connected to.
* @returns The Ethereum address of the Exchange contract being used.
*/
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
* pruning where you want to remove stale orders without knowing who the taker will be.
* @param signedOrder An object that conforms to the SignedOrder interface. The
* signedOrder you wish to validate.
* @param opts An object that conforms to the ValidateOrderFillableOpts
* interface. Allows specifying a specific fillTakerTokenAmount
* to validate for.
*/
public async validateOrderFillableOrThrowAsync(
signedOrder: SignedOrder, opts?: ValidateOrderFillableOpts,
): Promise<void> {
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
const zrxTokenAddress = this.getZRXTokenAddress();
const expectedFillTakerTokenAmount = !_.isUndefined(opts) ? opts.expectedFillTakerTokenAmount : undefined;
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
await this._orderValidationUtils.validateOrderFillableOrThrowAsync(
exchangeTradeEmulator, signedOrder, zrxTokenAddress, expectedFillTakerTokenAmount,
);
}
/**
* Checks if order fill will succeed and throws an error otherwise.
* @param signedOrder An object that conforms to the SignedOrder interface. The
* signedOrder you wish to fill.
* @param fillTakerTokenAmount The total amount of the takerTokens you would like to fill.
* @param takerAddress The user Ethereum address who would like to fill this order.
* Must be available via the supplied Web3.Provider passed to 0x.js.
*/
public async validateFillOrderThrowIfInvalidAsync(signedOrder: SignedOrder,
fillTakerTokenAmount: BigNumber,
takerAddress: string): Promise<void> {
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress);
}
/**
* Checks if cancelling a given order will succeed and throws an informative error if it won't.
* @param order An object that conforms to the Order or SignedOrder interface.
* The order you would like to cancel.
* @param cancelTakerTokenAmount The amount (specified in taker tokens) that you would like to cancel.
*/
public async validateCancelOrderThrowIfInvalidAsync(
order: Order, cancelTakerTokenAmount: BigNumber): Promise<void> {
assert.doesConformToSchema('order', order, schemas.orderSchema);
assert.isValidBaseUnitAmount('cancelTakerTokenAmount', cancelTakerTokenAmount);
const orderHash = utils.getOrderHashHex(order);
const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
OrderValidationUtils.validateCancelOrderThrowIfInvalid(
order, cancelTakerTokenAmount, unavailableTakerTokenAmount);
}
/**
* Checks if calling fillOrKill on a given order will succeed and throws an informative error if it won't.
* @param signedOrder An object that conforms to the SignedOrder interface. The
* signedOrder you wish to fill.
* @param fillTakerTokenAmount The total amount of the takerTokens you would like to fill.
* @param takerAddress The user Ethereum address who would like to fill this order.
* Must be available via the supplied Web3.Provider passed to 0x.js.
*/
public async validateFillOrKillOrderThrowIfInvalidAsync(signedOrder: SignedOrder,
fillTakerTokenAmount: BigNumber,
takerAddress: string): Promise<void> {
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress);
}
/**
* Checks if rounding error will be > 0.1% when computing makerTokenAmount by doing:
* `(fillTakerTokenAmount * makerTokenAmount) / takerTokenAmount`.
* 0x Protocol does not accept any trades that result in large rounding errors. This means that tokens with few or
* no decimals can only be filled in quantities and ratios that avoid large rounding errors.
* @param fillTakerTokenAmount The amount of the order (in taker tokens baseUnits) that you wish to fill.
* @param takerTokenAmount The order size on the taker side
* @param makerTokenAmount The order size on the maker side
*/
public async isRoundingErrorAsync(fillTakerTokenAmount: BigNumber,
takerTokenAmount: BigNumber,
makerTokenAmount: BigNumber): Promise<boolean> {
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
assert.isValidBaseUnitAmount('takerTokenAmount', takerTokenAmount);
assert.isValidBaseUnitAmount('makerTokenAmount', makerTokenAmount);
const exchangeInstance = await this._getExchangeContractAsync();
const isRoundingError = await exchangeInstance.isRoundingError.callAsync(
fillTakerTokenAmount, takerTokenAmount, makerTokenAmount,
);
return isRoundingError;
}
/**
* Checks if logs contain LogError, which is emmited by Exchange contract on transaction failure.
* @param logs Transaction logs as returned by `zeroEx.awaitTransactionMinedAsync`
*/
public throwLogErrorsAsErrors(logs: Array<LogWithDecodedArgs<DecodedLogArgs>|Web3.LogEntry>): void {
const errLog = _.find(logs, {
event: ExchangeEvents.LogError,
}) as LogWithDecodedArgs<LogErrorContractEventArgs>|undefined;
if (!_.isUndefined(errLog)) {
const logArgs = errLog.args;
const errCode = logArgs.errorId.toNumber();
const errMessage = this._exchangeContractErrCodesToMsg[errCode];
throw new Error(errMessage);
}
}
/**
* Returns the ZRX token address used by the exchange contract.
* @return Address of ZRX token
*/
public getZRXTokenAddress(): string {
const contractAddress = this._getContractAddress(
artifacts.ZRXArtifact, this._zrxContractAddressIfExists,
);
return contractAddress;
}
private _invalidateContractInstances(): void {
this.unsubscribeAll();
delete this._exchangeContractIfExists;
}
private async _isValidSignatureUsingContractCallAsync(dataHex: string, ecSignature: ECSignature,
signerAddressHex: string): Promise<boolean> {
assert.isHexString('dataHex', dataHex);
assert.doesConformToSchema('ecSignature', ecSignature, schemas.ecSignatureSchema);
assert.isETHAddressHex('signerAddressHex', signerAddressHex);
const exchangeInstance = await this._getExchangeContractAsync();
const isValidSignature = await exchangeInstance.isValidSignature.callAsync(
signerAddressHex,
dataHex,
ecSignature.v,
ecSignature.r,
ecSignature.s,
);
return isValidSignature;
}
private async _getOrderHashHexUsingContractCallAsync(order: Order|SignedOrder): Promise<string> {
const exchangeInstance = await this._getExchangeContractAsync();
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order);
const orderHashHex = await exchangeInstance.getOrderHash.callAsync(orderAddresses, orderValues);
return orderHashHex;
}
private async _getExchangeContractAsync(): Promise<ExchangeContract> {
if (!_.isUndefined(this._exchangeContractIfExists)) {
return this._exchangeContractIfExists;
}
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
artifacts.ExchangeArtifact, this._contractAddressIfExists,
);
const contractInstance = new ExchangeContract(web3ContractInstance, this._web3Wrapper.getContractDefaults());
this._exchangeContractIfExists = contractInstance;
return this._exchangeContractIfExists;
}
private async _getTokenTransferProxyAddressAsync(): Promise<string> {
const exchangeInstance = await this._getExchangeContractAsync();
const tokenTransferProxyAddress = await exchangeInstance.TOKEN_TRANSFER_PROXY_CONTRACT.callAsync();
const tokenTransferProxyAddressLowerCase = tokenTransferProxyAddress.toLowerCase();
return tokenTransferProxyAddressLowerCase;
}
} // tslint:disable:max-file-line-count

View File

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

View File

@@ -0,0 +1,33 @@
import {TxData, TxDataPayable} from '@0xproject/types';
import * as _ from 'lodash';
import * as Web3 from 'web3';
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,127 @@
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import * as _ from 'lodash';
import {artifacts} from '../artifacts';
import {Token, TokenMetadata} from '../types';
import {assert} from '../utils/assert';
import {constants} from '../utils/constants';
import {ContractWrapper} from './contract_wrapper';
import {TokenRegistryContract} from './generated/token_registry';
/**
* This class includes all the functionality related to interacting with the 0x Token Registry smart contract.
*/
export class TokenRegistryWrapper extends ContractWrapper {
private _tokenRegistryContractIfExists?: TokenRegistryContract;
private _contractAddressIfExists?: string;
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;
}
/**
* Retrieves all the tokens currently listed in the Token Registry smart contract
* @return An array of objects that conform to the Token interface.
*/
public async getTokensAsync(): Promise<Token[]> {
const addresses = await this.getTokenAddressesAsync();
const tokenPromises: Array<Promise<Token|undefined>> = _.map(
addresses,
async (address: string) => this.getTokenIfExistsAsync(address),
);
const tokens = await Promise.all(tokenPromises);
return tokens as Token[];
}
/**
* Retrieves all the addresses of the tokens currently listed in the Token Registry smart contract
* @return An array of token addresses.
*/
public async getTokenAddressesAsync(): Promise<string[]> {
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
const addresses = await tokenRegistryContract.getTokenAddresses.callAsync();
return addresses;
}
/**
* Retrieves a token by address currently listed in the Token Registry smart contract
* @return An object that conforms to the Token interface or undefined if token not found.
*/
public async getTokenIfExistsAsync(address: string): Promise<Token|undefined> {
assert.isETHAddressHex('address', address);
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
const metadata = await tokenRegistryContract.getTokenMetaData.callAsync(address);
const token = TokenRegistryWrapper._createTokenFromMetadata(metadata);
return token;
}
public async getTokenAddressBySymbolIfExistsAsync(symbol: string): Promise<string|undefined> {
assert.isString('symbol', symbol);
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
const addressIfExists = await tokenRegistryContract.getTokenAddressBySymbol.callAsync(symbol);
if (addressIfExists === constants.NULL_ADDRESS) {
return undefined;
}
return addressIfExists;
}
public async getTokenAddressByNameIfExistsAsync(name: string): Promise<string|undefined> {
assert.isString('name', name);
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
const addressIfExists = await tokenRegistryContract.getTokenAddressByName.callAsync(name);
if (addressIfExists === constants.NULL_ADDRESS) {
return undefined;
}
return addressIfExists;
}
public async getTokenBySymbolIfExistsAsync(symbol: string): Promise<Token|undefined> {
assert.isString('symbol', symbol);
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
const metadata = await tokenRegistryContract.getTokenBySymbol.callAsync(symbol);
const token = TokenRegistryWrapper._createTokenFromMetadata(metadata);
return token;
}
public async getTokenByNameIfExistsAsync(name: string): Promise<Token|undefined> {
assert.isString('name', name);
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
const metadata = await tokenRegistryContract.getTokenByName.callAsync(name);
const token = TokenRegistryWrapper._createTokenFromMetadata(metadata);
return token;
}
/**
* Retrieves the Ethereum address of the TokenRegistry contract deployed on the network
* that the user-passed web3 provider is connected to.
* @returns The Ethereum address of the TokenRegistry contract being used.
*/
public getContractAddress(): string {
const contractAddress = this._getContractAddress(
artifacts.TokenRegistryArtifact, this._contractAddressIfExists,
);
return contractAddress;
}
private _invalidateContractInstance(): void {
delete this._tokenRegistryContractIfExists;
}
private async _getTokenRegistryContractAsync(): Promise<TokenRegistryContract> {
if (!_.isUndefined(this._tokenRegistryContractIfExists)) {
return this._tokenRegistryContractIfExists;
}
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
artifacts.TokenRegistryArtifact, this._contractAddressIfExists,
);
const contractInstance = new TokenRegistryContract(
web3ContractInstance, this._web3Wrapper.getContractDefaults(),
);
this._tokenRegistryContractIfExists = contractInstance;
return this._tokenRegistryContractIfExists;
}
}

View File

@@ -0,0 +1,65 @@
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import * as _ from 'lodash';
import {artifacts} from '../artifacts';
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 _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.
* @param exchangeContractAddress The hex encoded address of the Exchange contract to call.
* @return Whether the exchangeContractAddress is authorized.
*/
public async isAuthorizedAsync(exchangeContractAddress: string): Promise<boolean> {
const tokenTransferProxyContractInstance = await this._getTokenTransferProxyContractAsync();
const isAuthorized = await tokenTransferProxyContractInstance.authorized.callAsync(exchangeContractAddress);
return isAuthorized;
}
/**
* Get the list of all Exchange contract addresses authorized by the TokenTransferProxy contract.
* @return The list of authorized addresses.
*/
public async getAuthorizedAddressesAsync(): Promise<string[]> {
const tokenTransferProxyContractInstance = await this._getTokenTransferProxyContractAsync();
const authorizedAddresses = await tokenTransferProxyContractInstance.getAuthorizedAddresses.callAsync();
return authorizedAddresses;
}
/**
* Retrieves the Ethereum address of the TokenTransferProxy contract deployed on the network
* that the user-passed web3 provider is connected to.
* @returns The Ethereum address of the TokenTransferProxy contract being used.
*/
public getContractAddress(): string {
const contractAddress = this._getContractAddress(
artifacts.TokenTransferProxyArtifact, this._contractAddressIfExists,
);
return contractAddress;
}
private _invalidateContractInstance(): void {
delete this._tokenTransferProxyContractIfExists;
}
private async _getTokenTransferProxyContractAsync(): Promise<TokenTransferProxyContract> {
if (!_.isUndefined(this._tokenTransferProxyContractIfExists)) {
return this._tokenTransferProxyContractIfExists;
}
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
artifacts.TokenTransferProxyArtifact, this._contractAddressIfExists,
);
const contractInstance = new TokenTransferProxyContract(
web3ContractInstance, this._web3Wrapper.getContractDefaults(),
);
this._tokenTransferProxyContractIfExists = contractInstance;
return this._tokenTransferProxyContractIfExists;
}
}

View File

@@ -0,0 +1,330 @@
import {schemas} from '@0xproject/json-schemas';
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import BigNumber from 'bignumber.js';
import * as _ from 'lodash';
import {artifacts} from '../artifacts';
import {
BlockRange,
EventCallback,
IndexedFilterValues,
LogWithDecodedArgs,
MethodOpts,
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';
/**
* This class includes all the functionality related to interacting with ERC20 token contracts.
* All ERC20 method calls are supported, along with some convenience methods for getting/setting allowances
* to the 0x Proxy smart contract.
*/
export class TokenWrapper extends ContractWrapper {
public UNLIMITED_ALLOWANCE_IN_BASE_UNITS = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
private _tokenContractsByAddress: {[address: string]: TokenContract};
private _tokenTransferProxyWrapper: TokenTransferProxyWrapper;
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder: AbiDecoder,
tokenTransferProxyWrapper: TokenTransferProxyWrapper) {
super(web3Wrapper, networkId, abiDecoder);
this._tokenContractsByAddress = {};
this._tokenTransferProxyWrapper = tokenTransferProxyWrapper;
}
/**
* Retrieves an owner's ERC20 token balance.
* @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
* @param ownerAddress The hex encoded user Ethereum address whose balance you would like to check.
* @param methodOpts Optional arguments this method accepts.
* @return The owner's ERC20 token balance in base units.
*/
public async getBalanceAsync(tokenAddress: string, ownerAddress: string,
methodOpts?: MethodOpts): Promise<BigNumber> {
assert.isETHAddressHex('ownerAddress', ownerAddress);
assert.isETHAddressHex('tokenAddress', tokenAddress);
const tokenContract = await this._getTokenContractAsync(tokenAddress);
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
let balance = await tokenContract.balanceOf.callAsync(ownerAddress, defaultBlock);
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
balance = new BigNumber(balance);
return balance;
}
/**
* Sets the spender's allowance to a specified number of baseUnits on behalf of the owner address.
* Equivalent to the ERC20 spec method `approve`.
* @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
* @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 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, 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);
const txHash = await tokenContract.approve.sendTransactionAsync(spenderAddress, amountInBaseUnits, {
from: ownerAddress,
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
});
return txHash;
}
/**
* Sets the spender's allowance to an unlimited number of baseUnits on behalf of the owner address.
* Equivalent to the ERC20 spec method `approve`.
* Setting an unlimited allowance will lower the gas cost for filling orders involving tokens that forego updating
* allowances set to the max amount (e.g ZRX, WETH)
* @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
* @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, txOpts: TransactionOpts = {}): Promise<string> {
const txHash = await this.setAllowanceAsync(
tokenAddress, ownerAddress, spenderAddress, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, txOpts,
);
return txHash;
}
/**
* Retrieves the owners allowance in baseUnits set to the spender's address.
* @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
* @param ownerAddress The hex encoded user Ethereum address whose allowance to spenderAddress
* you would like to retrieve.
* @param spenderAddress The hex encoded user Ethereum address who can spend the allowance you are fetching.
* @param methodOpts Optional arguments this method accepts.
*/
public async getAllowanceAsync(tokenAddress: string, ownerAddress: string,
spenderAddress: string, methodOpts?: MethodOpts): Promise<BigNumber> {
assert.isETHAddressHex('ownerAddress', ownerAddress);
assert.isETHAddressHex('tokenAddress', tokenAddress);
const tokenContract = await this._getTokenContractAsync(tokenAddress);
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
let allowanceInBaseUnits = await tokenContract.allowance.callAsync(ownerAddress, spenderAddress, defaultBlock);
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
allowanceInBaseUnits = new BigNumber(allowanceInBaseUnits);
return allowanceInBaseUnits;
}
/**
* Retrieves the owner's allowance in baseUnits set to the 0x proxy contract.
* @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
* @param ownerAddress The hex encoded user Ethereum address whose proxy contract allowance we are retrieving.
* @param methodOpts Optional arguments this method accepts.
*/
public async getProxyAllowanceAsync(tokenAddress: string, ownerAddress: string,
methodOpts?: MethodOpts): Promise<BigNumber> {
assert.isETHAddressHex('ownerAddress', ownerAddress);
assert.isETHAddressHex('tokenAddress', tokenAddress);
const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress();
const allowanceInBaseUnits = await this.getAllowanceAsync(tokenAddress, ownerAddress, proxyAddress, methodOpts);
return allowanceInBaseUnits;
}
/**
* Sets the 0x proxy contract's allowance to a specified number of a tokens' baseUnits on behalf
* of an owner address.
* @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 amountInBaseUnits The allowance amount specified in baseUnits.
* @param txOpts Transaction parameters.
* @return Transaction hash.
*/
public async setProxyAllowanceAsync(tokenAddress: string, ownerAddress: string,
amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise<string> {
assert.isETHAddressHex('ownerAddress', ownerAddress);
assert.isETHAddressHex('tokenAddress', tokenAddress);
assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress();
const txHash = await this.setAllowanceAsync(
tokenAddress, ownerAddress, proxyAddress, amountInBaseUnits, txOpts,
);
return txHash;
}
/**
* Sets the 0x proxy contract's allowance to a unlimited number of a tokens' baseUnits on behalf
* of an owner address.
* Setting an unlimited allowance will lower the gas cost for filling orders involving tokens that forego updating
* allowances set to the max amount (e.g ZRX, WETH)
* @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, txOpts: TransactionOpts = {},
): Promise<string> {
const txHash = await this.setProxyAllowanceAsync(
tokenAddress, ownerAddress, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, txOpts,
);
return txHash;
}
/**
* Transfers `amountInBaseUnits` ERC20 tokens from `fromAddress` to `toAddress`.
* @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
* @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, txOpts: TransactionOpts = {}): Promise<string> {
assert.isETHAddressHex('tokenAddress', tokenAddress);
await assert.isSenderAddressAsync('fromAddress', fromAddress, this._web3Wrapper);
assert.isETHAddressHex('toAddress', toAddress);
assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
const tokenContract = await this._getTokenContractAsync(tokenAddress);
const fromAddressBalance = await this.getBalanceAsync(tokenAddress, fromAddress);
if (fromAddressBalance.lessThan(amountInBaseUnits)) {
throw new Error(ZeroExError.InsufficientBalanceForTransfer);
}
const txHash = await tokenContract.transfer.sendTransactionAsync(toAddress, amountInBaseUnits, {
from: fromAddress,
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
});
return txHash;
}
/**
* Transfers `amountInBaseUnits` ERC20 tokens from `fromAddress` to `toAddress`.
* Requires the fromAddress to have sufficient funds and to have approved an allowance of
* `amountInBaseUnits` to `senderAddress`.
* @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed.
* @param fromAddress The hex encoded user Ethereum address whose funds are being sent.
* @param toAddress The hex encoded user Ethereum address that will receive the funds.
* @param senderAddress The hex encoded user Ethereum address whose initiates the fund transfer. The
* `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, txOpts: TransactionOpts = {}):
Promise<string> {
assert.isETHAddressHex('tokenAddress', tokenAddress);
assert.isETHAddressHex('fromAddress', fromAddress);
assert.isETHAddressHex('toAddress', toAddress);
await assert.isSenderAddressAsync('senderAddress', senderAddress, this._web3Wrapper);
assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
const tokenContract = await this._getTokenContractAsync(tokenAddress);
const fromAddressAllowance = await this.getAllowanceAsync(tokenAddress, fromAddress, senderAddress);
if (fromAddressAllowance.lessThan(amountInBaseUnits)) {
throw new Error(ZeroExError.InsufficientAllowanceForTransfer);
}
const fromAddressBalance = await this.getBalanceAsync(tokenAddress, fromAddress);
if (fromAddressBalance.lessThan(amountInBaseUnits)) {
throw new Error(ZeroExError.InsufficientBalanceForTransfer);
}
const txHash = await tokenContract.transferFrom.sendTransactionAsync(
fromAddress, toAddress, amountInBaseUnits,
{
from: senderAddress,
gas: txOpts.gasLimit,
gasPrice: txOpts.gasPrice,
},
);
return txHash;
}
/**
* Subscribe to an event type emitted by the Token contract.
* @param tokenAddress The hex encoded address where the ERC20 token is deployed.
* @param eventName The token contract event you would like to subscribe to.
* @param indexFilterValues An object where the keys are indexed args returned by the event and
* the value is the value you are interested in. E.g `{maker: aUserAddressHex}`
* @param callback Callback that gets called when a log is added/removed
* @return Subscription token used later to unsubscribe
*/
public subscribe<ArgsType extends TokenContractEventArgs>(
tokenAddress: string, eventName: TokenEvents, indexFilterValues: IndexedFilterValues,
callback: EventCallback<ArgsType>): string {
assert.isETHAddressHex('tokenAddress', tokenAddress);
assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
assert.isFunction('callback', callback);
const subscriptionToken = this._subscribe<ArgsType>(
tokenAddress, eventName, indexFilterValues, artifacts.TokenArtifact.abi, callback,
);
return subscriptionToken;
}
/**
* Cancel a subscription
* @param subscriptionToken Subscription token returned by `subscribe()`
*/
public unsubscribe(subscriptionToken: string): void {
this._unsubscribe(subscriptionToken);
}
/**
* Cancels all existing subscriptions
*/
public unsubscribeAll(): void {
super.unsubscribeAll();
}
/**
* Gets historical logs without creating a subscription
* @param tokenAddress An address of the token that emmited the logs.
* @param eventName The token contract event you would like to subscribe to.
* @param blockRange Block range to get logs from.
* @param indexFilterValues An object where the keys are indexed args returned by the event and
* the value is the value you are interested in. E.g `{_from: aUserAddressHex}`
* @return Array of logs that match the parameters
*/
public async getLogsAsync<ArgsType extends TokenContractEventArgs>(
tokenAddress: string, eventName: TokenEvents, blockRange: BlockRange,
indexFilterValues: IndexedFilterValues): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
assert.isETHAddressHex('tokenAddress', tokenAddress);
assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
const logs = await this._getLogsAsync<ArgsType>(
tokenAddress, eventName, blockRange, indexFilterValues, artifacts.TokenArtifact.abi,
);
return logs;
}
private _invalidateContractInstances(): void {
this.unsubscribeAll();
this._tokenContractsByAddress = {};
}
private async _getTokenContractAsync(tokenAddress: string): Promise<TokenContract> {
let tokenContract = this._tokenContractsByAddress[tokenAddress];
if (!_.isUndefined(tokenContract)) {
return tokenContract;
}
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
artifacts.TokenArtifact, tokenAddress,
);
const contractInstance = new TokenContract(
web3ContractInstance, this._web3Wrapper.getContractDefaults(),
);
tokenContract = contractInstance;
this._tokenContractsByAddress[tokenAddress] = tokenContract;
return tokenContract;
}
}

View File

@@ -1,27 +1,17 @@
/// <reference types='chai-typescript-typings' />
/// <reference types='chai-as-promised-typescript-typings' />
declare module 'web3_beta';
declare module 'chai-bignumber';
declare module 'dirty-chai';
declare module 'bn.js';
declare module 'request-promise-native';
declare module 'web3-provider-engine';
declare module 'web3-provider-engine/subproviders/rpc';
declare interface Schema {
id: string;
}
// HACK: In order to merge the bignumber declaration added by chai-bignumber to the chai Assertion
// interface we must use `namespace` as the Chai definitelyTyped definition does. Since we otherwise
// disallow `namespace`, we disable tslint for the following.
/* tslint:disable */
declare namespace Chai {
interface NumberComparer {
(value: number|BigNumber.BigNumber, message?: string): Assertion;
}
interface NumericComparison {
greaterThan: NumberComparer;
}
interface Assertion {
bignumber: Assertion;
// HACK: In order to comply with chai-as-promised we make eventually a `PromisedAssertion` not an `Assertion`
@@ -37,34 +27,6 @@ declare module '*.json' {
/* tslint:enable */
}
declare module 'ethereumjs-util' {
const toBuffer: (dataHex: string) => Buffer;
const hashPersonalMessage: (msg: Buffer) => Buffer;
const bufferToHex: (buff: Buffer) => string;
const ecrecover: (msgHashBuff: Buffer, v: number, r: Buffer, s: Buffer) => string;
const pubToAddress: (pubKey: string) => Buffer;
const isValidAddress: (address: string) => boolean;
const bufferToInt: (buffer: Buffer) => number;
const fromRpcSig: (signature: string) => {v: number, r: Buffer, s: Buffer};
}
// truffle-contract declarations
declare interface ContractInstance {
address: string;
}
declare interface ContractFactory {
setProvider: (providerObj: any) => void;
deployed: () => ContractInstance;
at: (address: string) => ContractInstance;
}
declare interface Artifact {
networks: {[networkId: number]: any};
}
declare function contract(artifacts: Artifact): ContractFactory;
declare module 'truffle-contract' {
export = contract;
}
// find-version declarations
declare function findVersions(version: string): string[];
declare module 'find-versions' {
@@ -77,12 +39,36 @@ 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;
}
// truffle-hdwallet-provider declarations
declare module 'truffle-hdwallet-provider' {
import * as Web3 from 'web3';
class HDWalletProvider implements Web3.Provider {
constructor(mnemonic: string, rpcUrl: string);
public sendAsync(
payload: Web3.JSONRPCRequestPayload,
callback: (err: Error, result: Web3.JSONRPCResponsePayload) => void,
): void;
}
export = HDWalletProvider;
}
// abi-decoder declarations
interface DecodedLogArg {
}
interface DecodedLog {
name: string;
events: DecodedLogArg[];
}
declare module 'abi-decoder' {
import * as Web3 from 'web3';
const addABI: (abi: Web3.AbiDefinition) => void;
const decodeLogs: (logs: Web3.LogEntry[]) => DecodedLog[];
}
declare module 'web3/lib/solidity/coder' {
const decodeParams: (types: string[], data: string) => any[];
}

23
packages/0x.js/src/globalsAugment.d.ts vendored Normal file
View File

@@ -0,0 +1,23 @@
import BigNumber from 'bignumber.js';
// HACK: This module overrides the Chai namespace so that we can use BigNumber types inside.
// Source: https://github.com/Microsoft/TypeScript/issues/7352#issuecomment-191547232
declare global {
// HACK: In order to merge the bignumber declaration added by chai-bignumber to the chai Assertion
// interface we must use `namespace` as the Chai definitelyTyped definition does. Since we otherwise
// disallow `namespace`, we disable tslint for the following.
/* tslint:disable */
namespace Chai {
interface NumberComparer {
(value: number|BigNumber, message?: string): Assertion;
}
interface NumericComparison {
greaterThan: NumberComparer;
}
}
/* tslint:enable */
interface DecodedLogArg {
name: string;
value: string|BigNumber;
}
}

View File

@@ -0,0 +1,52 @@
export {ZeroEx} from './0x';
export {
Order,
BlockParamLiteral,
SignedOrder,
ECSignature,
ZeroExError,
EventCallback,
ExchangeContractErrs,
ContractEvent,
Token,
ExchangeEvents,
TokenEvents,
IndexedFilterValues,
BlockRange,
BlockParam,
OrderCancellationRequest,
OrderFillRequest,
LogErrorContractEventArgs,
LogCancelContractEventArgs,
LogFillContractEventArgs,
ExchangeContractEventArgs,
TransferContractEventArgs,
ApprovalContractEventArgs,
TokenContractEventArgs,
EtherTokenContractEventArgs,
WithdrawalContractEventArgs,
DepositContractEventArgs,
ContractEventArgs,
ContractEventArg,
Web3Provider,
ZeroExConfig,
EtherTokenEvents,
TransactionReceiptWithDecodedLogs,
LogWithDecodedArgs,
MethodOpts,
OrderTransactionOpts,
TransactionOpts,
FilterObject,
LogEvent,
DecodedLogEvent,
EventWatcherCallback,
OnOrderStateChangeCallback,
OrderStateValid,
OrderStateInvalid,
OrderState,
} from './types';
export {
TransactionReceipt,
} from '@0xproject/types';

View File

@@ -0,0 +1,86 @@
import {intervalUtils} from '@0xproject/utils';
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import * as _ from 'lodash';
import * as Web3 from 'web3';
import {
BlockParamLiteral,
EventWatcherCallback,
ZeroExError,
} from '../types';
import {assert} from '../utils/assert';
const DEFAULT_EVENT_POLLING_INTERVAL_MS = 200;
enum LogEventState {
Removed,
Added,
}
/*
* The EventWatcher watches for blockchain events at the specified block confirmation
* depth.
*/
export class EventWatcher {
private _web3Wrapper: Web3Wrapper;
private _pollingIntervalMs: number;
private _intervalIdIfExists?: NodeJS.Timer;
private _lastEvents: Web3.LogEntry[] = [];
constructor(web3Wrapper: Web3Wrapper, pollingIntervalIfExistsMs: undefined|number) {
this._web3Wrapper = web3Wrapper;
this._pollingIntervalMs = _.isUndefined(pollingIntervalIfExistsMs) ?
DEFAULT_EVENT_POLLING_INTERVAL_MS :
pollingIntervalIfExistsMs;
}
public subscribe(callback: EventWatcherCallback): void {
assert.isFunction('callback', callback);
if (!_.isUndefined(this._intervalIdIfExists)) {
throw new Error(ZeroExError.SubscriptionAlreadyPresent);
}
this._intervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
this._pollForBlockchainEventsAsync.bind(this, callback), this._pollingIntervalMs,
);
}
public unsubscribe(): void {
this._lastEvents = [];
if (!_.isUndefined(this._intervalIdIfExists)) {
intervalUtils.clearAsyncExcludingInterval(this._intervalIdIfExists);
delete this._intervalIdIfExists;
}
}
private async _pollForBlockchainEventsAsync(callback: EventWatcherCallback): Promise<void> {
const pendingEvents = await this._getEventsAsync();
if (pendingEvents.length === 0) {
// HACK: Sometimes when node rebuilds the pending block we get back the empty result.
// We don't want to emit a lot of removal events and bring them back after a couple of miliseconds,
// that's why we just ignore those cases.
return;
}
const removedEvents = _.differenceBy(this._lastEvents, pendingEvents, JSON.stringify);
const newEvents = _.differenceBy(pendingEvents, this._lastEvents, JSON.stringify);
await this._emitDifferencesAsync(removedEvents, LogEventState.Removed, callback);
await this._emitDifferencesAsync(newEvents, LogEventState.Added, callback);
this._lastEvents = pendingEvents;
}
private async _getEventsAsync(): Promise<Web3.LogEntry[]> {
const eventFilter = {
fromBlock: BlockParamLiteral.Pending,
toBlock: BlockParamLiteral.Pending,
};
const events = await this._web3Wrapper.getLogsAsync(eventFilter);
return events;
}
private async _emitDifferencesAsync(
logs: Web3.LogEntry[], logEventState: LogEventState, callback: EventWatcherCallback,
): Promise<void> {
for (const log of logs) {
const logEvent = {
removed: logEventState === LogEventState.Removed,
...log,
};
if (!_.isUndefined(this._intervalIdIfExists)) {
callback(logEvent);
}
}
}
}

View File

@@ -0,0 +1,76 @@
import {intervalUtils} from '@0xproject/utils';
import {BigNumber} from 'bignumber.js';
import {RBTree} from 'bintrees';
import * as _ from 'lodash';
import {ZeroExError} from '../types';
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

@@ -0,0 +1,358 @@
import {schemas} from '@0xproject/json-schemas';
import {intervalUtils} from '@0xproject/utils';
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import * as _ from 'lodash';
import {ZeroEx} from '../0x';
import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper';
import {TokenWrapper} from '../contract_wrappers/token_wrapper';
import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store';
import {OrderFilledCancelledLazyStore} from '../stores/order_filled_cancelled_lazy_store';
import {
ApprovalContractEventArgs,
BlockParamLiteral,
ContractEventArgs,
DepositContractEventArgs,
EtherTokenEvents,
ExchangeContractErrs,
ExchangeEvents,
LogCancelContractEventArgs,
LogEvent,
LogFillContractEventArgs,
LogWithDecodedArgs,
OnOrderStateChangeCallback,
OrderState,
OrderStateWatcherConfig,
SignedOrder,
TokenEvents,
TransferContractEventArgs,
WithdrawalContractEventArgs,
ZeroExError,
} from '../types';
import {AbiDecoder} from '../utils/abi_decoder';
import {assert} from '../utils/assert';
import {OrderStateUtils} from '../utils/order_state_utils';
import {utils} from '../utils/utils';
import {EventWatcher} from './event_watcher';
import {ExpirationWatcher} from './expiration_watcher';
interface DependentOrderHashes {
[makerAddress: string]: {
[makerToken: string]: Set<string>;
};
}
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
* the subscriber of these changes so that a final decison can be made on whether
* the order should be deemed invalid.
*/
export class OrderStateWatcher {
private _orderStateByOrderHashCache: OrderStateByOrderHash = {};
private _orderByOrderHash: OrderByOrderHash = {};
private _dependentOrderHashes: DependentOrderHashes = {};
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 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
* signature is verified.
* @param signedOrder The order you wish to start watching.
*/
public addOrder(signedOrder: SignedOrder): void {
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
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
* @param orderHash The orderHash of the order you wish to stop watching.
*/
public removeOrder(orderHash: string): void {
assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
const signedOrder = this._orderByOrderHash[orderHash];
if (_.isUndefined(signedOrder)) {
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
* backing blockchain state has changed. This is a call-to-action for the caller to re-validate the order.
* @param callback Receives the orderHash of the order that should be re-validated, together
* with all the order-relevant blockchain state needed to re-validate the order.
*/
public subscribe(callback: OnOrderStateChangeCallback): void {
assert.isFunction('callback', callback);
if (!_.isUndefined(this._callbackIfExists)) {
throw new Error(ZeroExError.SubscriptionAlreadyPresent);
}
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._callbackIfExists) || _.isUndefined(this._cleanupJobIntervalIdIfExists)) {
throw new Error(ZeroExError.SubscriptionNotFound);
}
this._balanceAndProxyAllowanceLazyStore.deleteAll();
this._orderFilledCancelledLazyStore.deleteAll();
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);
const isLogDecoded = !_.isUndefined((maybeDecodedLog as LogWithDecodedArgs<any>).event);
if (!isLogDecoded) {
return; // noop
}
const decodedLog = maybeDecodedLog as LogWithDecodedArgs<ContractEventArgs>;
let makerToken: string;
let makerAddress: string;
switch (decodedLog.event) {
case TokenEvents.Approval:
{
// Invalidate cache
const args = decodedLog.args as ApprovalContractEventArgs;
this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(decodedLog.address, args._owner);
// Revalidate orders
makerToken = decodedLog.address;
makerAddress = args._owner;
if (!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])) {
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
await this._emitRevalidateOrdersAsync(orderHashes);
}
break;
}
case TokenEvents.Transfer:
{
// Invalidate cache
const args = decodedLog.args as TransferContractEventArgs;
this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._from);
this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._to);
// Revalidate orders
makerToken = decodedLog.address;
makerAddress = args._from;
if (!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])) {
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
await this._emitRevalidateOrdersAsync(orderHashes);
}
break;
}
case EtherTokenEvents.Deposit:
{
// Invalidate cache
const args = decodedLog.args as DepositContractEventArgs;
this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._owner);
// Revalidate orders
makerToken = decodedLog.address;
makerAddress = args._owner;
if (!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])) {
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
await this._emitRevalidateOrdersAsync(orderHashes);
}
break;
}
case EtherTokenEvents.Withdrawal:
{
// Invalidate cache
const args = decodedLog.args as WithdrawalContractEventArgs;
this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._owner);
// Revalidate orders
makerToken = decodedLog.address;
makerAddress = args._owner;
if (!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])) {
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
await this._emitRevalidateOrdersAsync(orderHashes);
}
break;
}
case ExchangeEvents.LogFill:
{
// Invalidate cache
const args = decodedLog.args as LogFillContractEventArgs;
this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(args.orderHash);
// Revalidate orders
const orderHash = args.orderHash;
const isOrderWatched = !_.isUndefined(this._orderByOrderHash[orderHash]);
if (isOrderWatched) {
await this._emitRevalidateOrdersAsync([orderHash]);
}
break;
}
case ExchangeEvents.LogCancel:
{
// Invalidate cache
const args = decodedLog.args as LogCancelContractEventArgs;
this._orderFilledCancelledLazyStore.deleteCancelledTakerAmount(args.orderHash);
// Revalidate orders
const orderHash = args.orderHash;
const isOrderWatched = !_.isUndefined(this._orderByOrderHash[orderHash]);
if (isOrderWatched) {
await this._emitRevalidateOrdersAsync([orderHash]);
}
break;
}
case ExchangeEvents.LogError:
return; // noop
default:
throw utils.spawnSwitchErr('decodedLog.event', decodedLog.event);
}
}
private async _emitRevalidateOrdersAsync(orderHashes: string[]): Promise<void> {
for (const orderHash of orderHashes) {
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._callbackIfExists)) {
break; // Unsubscribe was called
}
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): void {
if (_.isUndefined(this._dependentOrderHashes[signedOrder.maker])) {
this._dependentOrderHashes[signedOrder.maker] = {};
}
if (_.isUndefined(this._dependentOrderHashes[signedOrder.maker][signedOrder.makerTokenAddress])) {
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, 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

@@ -0,0 +1,27 @@
export const zeroExConfigSchema = {
id: '/ZeroExConfig',
properties: {
networkId: {
type: 'number',
minimum: 0,
},
gasPrice: {$ref: '/Number'},
exchangeContractAddress: {$ref: '/Address'},
tokenRegistryContractAddress: {$ref: '/Address'},
orderWatcherConfig: {
type: 'object',
properties: {
pollingIntervalMs: {
type: 'number',
minimum: 0,
},
numConfirmations: {
type: 'number',
minimum: 0,
},
},
},
},
type: 'object',
required: ['networkId'],
};

View File

@@ -0,0 +1,84 @@
import {BigNumber} from 'bignumber.js';
import * as _ from 'lodash';
import {TokenWrapper} from '../contract_wrappers/token_wrapper';
import {BlockParamLiteral} from '../types';
/**
* Copy on read store for balances/proxyAllowances of tokens/accounts
*/
export class BalanceAndProxyAllowanceLazyStore {
private _token: TokenWrapper;
private _defaultBlock: BlockParamLiteral;
private _balance: {
[tokenAddress: string]: {
[userAddress: string]: BigNumber;
};
};
private _proxyAllowance: {
[tokenAddress: string]: {
[userAddress: string]: BigNumber;
};
};
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: this._defaultBlock,
};
const balance = await this._token.getBalanceAsync(tokenAddress, userAddress, methodOpts);
this.setBalance(tokenAddress, userAddress, balance);
}
const cachedBalance = this._balance[tokenAddress][userAddress];
return cachedBalance;
}
public setBalance(tokenAddress: string, userAddress: string, balance: BigNumber): void {
if (_.isUndefined(this._balance[tokenAddress])) {
this._balance[tokenAddress] = {};
}
this._balance[tokenAddress][userAddress] = balance;
}
public deleteBalance(tokenAddress: string, userAddress: string): void {
if (!_.isUndefined(this._balance[tokenAddress])) {
delete this._balance[tokenAddress][userAddress];
if (_.isEmpty(this._balance[tokenAddress])) {
delete this._balance[tokenAddress];
}
}
}
public async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> {
if (_.isUndefined(this._proxyAllowance[tokenAddress]) ||
_.isUndefined(this._proxyAllowance[tokenAddress][userAddress])) {
const methodOpts = {
defaultBlock: this._defaultBlock,
};
const proxyAllowance = await this._token.getProxyAllowanceAsync(tokenAddress, userAddress, methodOpts);
this.setProxyAllowance(tokenAddress, userAddress, proxyAllowance);
}
const cachedProxyAllowance = this._proxyAllowance[tokenAddress][userAddress];
return cachedProxyAllowance;
}
public setProxyAllowance(tokenAddress: string, userAddress: string, proxyAllowance: BigNumber): void {
if (_.isUndefined(this._proxyAllowance[tokenAddress])) {
this._proxyAllowance[tokenAddress] = {};
}
this._proxyAllowance[tokenAddress][userAddress] = proxyAllowance;
}
public deleteProxyAllowance(tokenAddress: string, userAddress: string): void {
if (!_.isUndefined(this._proxyAllowance[tokenAddress])) {
delete this._proxyAllowance[tokenAddress][userAddress];
if (_.isEmpty(this._proxyAllowance[tokenAddress])) {
delete this._proxyAllowance[tokenAddress];
}
}
}
public deleteAll(): void {
this._balance = {};
this._proxyAllowance = {};
}
}

View File

@@ -0,0 +1,61 @@
import {BigNumber} from 'bignumber.js';
import * as _ from 'lodash';
import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper';
import {BlockParamLiteral} from '../types';
/**
* Copy on read store for filled/cancelled taker amounts
*/
export class OrderFilledCancelledLazyStore {
private _exchange: ExchangeWrapper;
private _filledTakerAmount: {
[orderHash: string]: BigNumber;
};
private _cancelledTakerAmount: {
[orderHash: string]: BigNumber;
};
constructor(exchange: ExchangeWrapper) {
this._exchange = exchange;
this._filledTakerAmount = {};
this._cancelledTakerAmount = {};
}
public async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber> {
if (_.isUndefined(this._filledTakerAmount[orderHash])) {
const methodOpts = {
defaultBlock: BlockParamLiteral.Pending,
};
const filledTakerAmount = await this._exchange.getFilledTakerAmountAsync(orderHash, methodOpts);
this.setFilledTakerAmount(orderHash, filledTakerAmount);
}
const cachedFilled = this._filledTakerAmount[orderHash];
return cachedFilled;
}
public setFilledTakerAmount(orderHash: string, filledTakerAmount: BigNumber): void {
this._filledTakerAmount[orderHash] = filledTakerAmount;
}
public deleteFilledTakerAmount(orderHash: string): void {
delete this._filledTakerAmount[orderHash];
}
public async getCancelledTakerAmountAsync(orderHash: string): Promise<BigNumber> {
if (_.isUndefined(this._cancelledTakerAmount[orderHash])) {
const methodOpts = {
defaultBlock: BlockParamLiteral.Pending,
};
const cancelledTakerAmount = await this._exchange.getCancelledTakerAmountAsync(orderHash, methodOpts);
this.setCancelledTakerAmount(orderHash, cancelledTakerAmount);
}
const cachedCancelled = this._cancelledTakerAmount[orderHash];
return cachedCancelled;
}
public setCancelledTakerAmount(orderHash: string, cancelledTakerAmount: BigNumber): void {
this._cancelledTakerAmount[orderHash] = cancelledTakerAmount;
}
public deleteCancelledTakerAmount(orderHash: string): void {
delete this._cancelledTakerAmount[orderHash];
}
public deleteAll(): void {
this._filledTakerAmount = {};
this._cancelledTakerAmount = {};
}
}

405
packages/0x.js/src/types.ts Normal file
View File

@@ -0,0 +1,405 @@
import {TransactionReceipt} from '@0xproject/types';
import BigNumber from 'bignumber.js';
import * as Web3 from 'web3';
export enum ZeroExError {
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',
ContractNotDeployedOnNetwork = 'CONTRACT_NOT_DEPLOYED_ON_NETWORK',
InsufficientAllowanceForTransfer = 'INSUFFICIENT_ALLOWANCE_FOR_TRANSFER',
InsufficientBalanceForTransfer = 'INSUFFICIENT_BALANCE_FOR_TRANSFER',
InsufficientEthBalanceForDeposit = 'INSUFFICIENT_ETH_BALANCE_FOR_DEPOSIT',
InsufficientWEthBalanceForWithdrawal = 'INSUFFICIENT_WETH_BALANCE_FOR_WITHDRAWAL',
InvalidJump = 'INVALID_JUMP',
OutOfGas = 'OUT_OF_GAS',
NoNetworkId = 'NO_NETWORK_ID',
SubscriptionNotFound = 'SUBSCRIPTION_NOT_FOUND',
SubscriptionAlreadyPresent = 'SUBSCRIPTION_ALREADY_PRESENT',
TransactionMiningTimeout = 'TRANSACTION_MINING_TIMEOUT',
}
export enum InternalZeroExError {
NoAbiDecoder = 'NO_ABI_DECODER',
ZrxNotInTokenRegistry = 'ZRX_NOT_IN_TOKEN_REGISTRY',
WethNotInTokenRegistry = 'WETH_NOT_IN_TOKEN_REGISTRY',
}
/**
* Elliptic Curve signature
*/
export interface ECSignature {
v: number;
r: string;
s: string;
}
export type OrderAddresses = [string, string, string, string, string];
export type OrderValues = [BigNumber, BigNumber, BigNumber,
BigNumber, BigNumber, BigNumber];
export type LogEvent = Web3.LogEntryEvent;
export interface DecodedLogEvent<ArgsType> {
isRemoved: boolean;
log: LogWithDecodedArgs<ArgsType>;
}
export type EventCallback<ArgsType> = (err: null|Error, log?: DecodedLogEvent<ArgsType>) => void;
export type EventWatcherCallback = (log: LogEvent) => void;
export enum SolidityTypes {
Address = 'address',
Uint256 = 'uint256',
Uint8 = 'uint8',
Uint = 'uint',
}
export enum ExchangeContractErrCodes {
ERROR_FILL_EXPIRED, // Order has already expired
ERROR_FILL_NO_VALUE, // Order has already been fully filled or cancelled
ERROR_FILL_TRUNCATION, // Rounding error too large
ERROR_FILL_BALANCE_ALLOWANCE, // Insufficient balance or allowance for token transfer
ERROR_CANCEL_EXPIRED, // Order has already expired
ERROR_CANCEL_NO_VALUE, // Order has already been fully filled or cancelled
}
export enum ExchangeContractErrs {
OrderFillExpired = 'ORDER_FILL_EXPIRED',
OrderCancelExpired = 'ORDER_CANCEL_EXPIRED',
OrderCancelAmountZero = 'ORDER_CANCEL_AMOUNT_ZERO',
OrderAlreadyCancelledOrFilled = 'ORDER_ALREADY_CANCELLED_OR_FILLED',
OrderFillAmountZero = 'ORDER_FILL_AMOUNT_ZERO',
OrderRemainingFillAmountZero = 'ORDER_REMAINING_FILL_AMOUNT_ZERO',
OrderFillRoundingError = 'ORDER_FILL_ROUNDING_ERROR',
FillBalanceAllowanceError = 'FILL_BALANCE_ALLOWANCE_ERROR',
InsufficientTakerBalance = 'INSUFFICIENT_TAKER_BALANCE',
InsufficientTakerAllowance = 'INSUFFICIENT_TAKER_ALLOWANCE',
InsufficientMakerBalance = 'INSUFFICIENT_MAKER_BALANCE',
InsufficientMakerAllowance = 'INSUFFICIENT_MAKER_ALLOWANCE',
InsufficientTakerFeeBalance = 'INSUFFICIENT_TAKER_FEE_BALANCE',
InsufficientTakerFeeAllowance = 'INSUFFICIENT_TAKER_FEE_ALLOWANCE',
InsufficientMakerFeeBalance = 'INSUFFICIENT_MAKER_FEE_BALANCE',
InsufficientMakerFeeAllowance = 'INSUFFICIENT_MAKER_FEE_ALLOWANCE',
TransactionSenderIsNotFillOrderTaker = 'TRANSACTION_SENDER_IS_NOT_FILL_ORDER_TAKER',
MultipleMakersInSingleCancelBatchDisallowed = 'MULTIPLE_MAKERS_IN_SINGLE_CANCEL_BATCH_DISALLOWED',
InsufficientRemainingFillAmount = 'INSUFFICIENT_REMAINING_FILL_AMOUNT',
MultipleTakerTokensInFillUpToDisallowed = 'MULTIPLE_TAKER_TOKENS_IN_FILL_UP_TO_DISALLOWED',
BatchOrdersMustHaveSameExchangeAddress = 'BATCH_ORDERS_MUST_HAVE_SAME_EXCHANGE_ADDRESS',
BatchOrdersMustHaveAtLeastOneItem = 'BATCH_ORDERS_MUST_HAVE_AT_LEAST_ONE_ITEM',
}
export type RawLog = Web3.LogEntry;
export interface ContractEvent {
logIndex: number;
transactionIndex: number;
transactionHash: string;
blockHash: string;
blockNumber: number;
address: string;
type: string;
event: string;
args: ContractEventArgs;
}
export interface LogFillContractEventArgs {
maker: string;
taker: string;
feeRecipient: string;
makerToken: string;
takerToken: string;
filledMakerTokenAmount: BigNumber;
filledTakerTokenAmount: BigNumber;
paidMakerFee: BigNumber;
paidTakerFee: BigNumber;
tokens: string;
orderHash: string;
}
export interface LogCancelContractEventArgs {
maker: string;
feeRecipient: string;
makerToken: string;
takerToken: string;
cancelledMakerTokenAmount: BigNumber;
cancelledTakerTokenAmount: BigNumber;
tokens: string;
orderHash: string;
}
export interface LogErrorContractEventArgs {
errorId: BigNumber;
orderHash: string;
}
export type ExchangeContractEventArgs = LogFillContractEventArgs|LogCancelContractEventArgs|LogErrorContractEventArgs;
export interface TransferContractEventArgs {
_from: string;
_to: string;
_value: BigNumber;
}
export interface ApprovalContractEventArgs {
_owner: string;
_spender: string;
_value: BigNumber;
}
export interface DepositContractEventArgs {
_owner: string;
_value: BigNumber;
}
export interface WithdrawalContractEventArgs {
_owner: string;
_value: BigNumber;
}
export type TokenContractEventArgs = TransferContractEventArgs|ApprovalContractEventArgs;
export type EtherTokenContractEventArgs = TokenContractEventArgs|DepositContractEventArgs|WithdrawalContractEventArgs;
export type ContractEventArgs = ExchangeContractEventArgs|TokenContractEventArgs|EtherTokenContractEventArgs;
export type ContractEventArg = string|BigNumber;
export interface Order {
maker: string;
taker: string;
makerFee: BigNumber;
takerFee: BigNumber;
makerTokenAmount: BigNumber;
takerTokenAmount: BigNumber;
makerTokenAddress: string;
takerTokenAddress: string;
salt: BigNumber;
exchangeContractAddress: string;
feeRecipient: string;
expirationUnixTimestampSec: BigNumber;
}
export interface SignedOrder extends Order {
ecSignature: ECSignature;
}
// [address, name, symbol, decimals, ipfsHash, swarmHash]
export type TokenMetadata = [string, string, string, BigNumber, string, string];
export interface Token {
name: string;
address: string;
symbol: string;
decimals: number;
}
export interface TxOpts {
from: string;
gas?: number;
value?: BigNumber;
gasPrice?: BigNumber;
}
export interface TokenAddressBySymbol {
[symbol: string]: string;
}
export enum ExchangeEvents {
LogFill = 'LogFill',
LogCancel = 'LogCancel',
LogError = 'LogError',
}
export enum TokenEvents {
Transfer = 'Transfer',
Approval = 'Approval',
}
export enum EtherTokenEvents {
Transfer = 'Transfer',
Approval = 'Approval',
Deposit = 'Deposit',
Withdrawal = 'Withdrawal',
}
export type ContractEvents = TokenEvents|ExchangeEvents|EtherTokenEvents;
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',
Pending = 'pending',
}
export type BlockParam = BlockParamLiteral|number;
export interface BlockRange {
fromBlock: BlockParam;
toBlock: BlockParam;
}
export type DoneCallback = (err?: Error) => void;
export interface OrderCancellationRequest {
order: Order|SignedOrder;
takerTokenCancelAmount: BigNumber;
}
export interface OrderFillRequest {
signedOrder: SignedOrder;
takerTokenFillAmount: BigNumber;
}
export type AsyncMethod = (...args: any[]) => Promise<any>;
export type SyncMethod = (...args: any[]) => any;
/**
* We re-export the `Web3.Provider` type specified in the Web3 Typescript typings
* 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. To learn more
* about providers, visit https://0xproject.com/wiki#Web3-Provider-Explained
*/
export type Web3Provider = Web3.Provider;
export interface JSONRPCPayload {
params: any[];
method: string;
}
/*
* orderExpirationCheckingIntervalMs: How often to check for expired orders. Default: 50
* eventPollingIntervalMs: How often to poll the Ethereum node for new events. Defaults: 200
* 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
* tokenTransferProxyContractAddress: The address of the token transfer proxy contract to use
* orderWatcherConfig: All the configs related to the orderWatcher
*/
export interface ZeroExConfig {
networkId: number;
gasPrice?: BigNumber;
exchangeContractAddress?: string;
tokenRegistryContractAddress?: string;
tokenTransferProxyContractAddress?: string;
orderWatcherConfig?: OrderStateWatcherConfig;
}
export enum AbiType {
Function = 'function',
Constructor = 'constructor',
Event = 'event',
Fallback = 'fallback',
}
export interface DecodedLogArgs {
[argName: string]: ContractEventArg;
}
export interface LogWithDecodedArgs<ArgsType> extends Web3.DecodedLogEntry<ArgsType> {}
export interface TransactionReceiptWithDecodedLogs extends TransactionReceipt {
logs: Array<LogWithDecodedArgs<DecodedLogArgs>|Web3.LogEntry>;
}
export type ArtifactContractName = 'ZRX'|'TokenTransferProxy'|'TokenRegistry'|'Token'|'Exchange'|'EtherToken';
export interface Artifact {
contract_name: ArtifactContractName;
abi: Web3.ContractAbi;
networks: {
[networkId: number]: {
address: string;
};
};
}
/*
* expectedFillTakerTokenAmount: If specified, the validation method will ensure that the
* supplied order maker has a sufficient allowance/balance to fill this amount of the order's
* takerTokenAmount. If not specified, the validation method ensures that the maker has a sufficient
* allowance/balance to fill the entire remaining order amount.
*/
export interface ValidateOrderFillableOpts {
expectedFillTakerTokenAmount?: BigNumber;
}
/*
* defaultBlock: The block up to which to query the blockchain state. Setting this to a historical block number
* let's the user query the blockchain's state at an arbitrary point in time. In order for this to work, the
* backing Ethereum node must keep the entire historical state of the chain (e.g setting `--pruning=archive`
* flag when running Parity).
*/
export interface MethodOpts {
defaultBlock?: Web3.BlockParam;
}
/*
* gasPrice: Gas price in Wei to use for a transaction
* gasLimit: The amount of gas to send with a transaction
*/
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;
export enum TradeSide {
Maker = 'maker',
Taker = 'taker',
}
export enum TransferType {
Trade = 'trade',
Fee = 'fee',
}
export interface OrderRelevantState {
makerBalance: BigNumber;
makerProxyAllowance: BigNumber;
makerFeeBalance: BigNumber;
makerFeeProxyAllowance: BigNumber;
filledTakerTokenAmount: BigNumber;
cancelledTakerTokenAmount: BigNumber;
remainingFillableMakerTokenAmount: BigNumber;
remainingFillableTakerTokenAmount: BigNumber;
}
export interface OrderStateValid {
isValid: true;
orderHash: string;
orderRelevantState: OrderRelevantState;
}
export interface OrderStateInvalid {
isValid: false;
orderHash: string;
error: ExchangeContractErrs;
}
export type OrderState = OrderStateValid|OrderStateInvalid;
export type OnOrderStateChangeCallback = (orderState: OrderState) => void;
// tslint:disable:max-file-line-count

View File

@@ -0,0 +1,69 @@
import BigNumber from 'bignumber.js';
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));
}
// This method can only decode logs from the 0x & ERC20 smart contracts
public tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>(
log: Web3.LogEntry): LogWithDecodedArgs<ArgsType>|RawLog {
const methodId = log.topics[0];
const event = this._methodIds[methodId];
if (_.isUndefined(event)) {
return log;
}
const logData = log.data;
const decodedParams: DecodedLogArgs = {};
let dataIndex = 0;
let topicsIndex = 1;
const nonIndexedInputs = _.filter(event.inputs, input => !input.indexed);
const dataTypes = _.map(nonIndexedInputs, input => input.type);
const decodedData = SolidityCoder.decodeParams(dataTypes, logData.slice('0x'.length));
_.map(event.inputs, (param: Web3.EventParameter) => {
// Indexed parameters are stored in topics. Non-indexed ones in decodedData
let value = param.indexed ? log.topics[topicsIndex++] : decodedData[dataIndex++];
if (param.type === SolidityTypes.Address) {
value = AbiDecoder._padZeros(new BigNumber(value).toString(16));
} else if (param.type === SolidityTypes.Uint256 ||
param.type === SolidityTypes.Uint8 ||
param.type === SolidityTypes.Uint) {
value = new BigNumber(value);
}
decodedParams[param.name] = value;
});
return {
...log,
event: event.name,
args: decodedParams,
};
}
private _addABI(abiArray: Web3.AbiDefinition[]): void {
_.map(abiArray, (abi: Web3.AbiDefinition) => {
if (abi.type === AbiType.Event) {
const signature = `${abi.name}(${_.map(abi.inputs, input => input.type).join(',')})`;
const signatureHash = new Web3().sha3(signature);
this._methodIds[signatureHash] = abi;
}
});
this._savedABIs = this._savedABIs.concat(abiArray);
}
}

View File

@@ -0,0 +1,31 @@
import {assert as sharedAssert} from '@0xproject/assert';
// We need those two unused imports because they're actually used by sharedAssert which gets injected here
// tslint:disable-next-line:no-unused-variable
import {Schema} from '@0xproject/json-schemas';
import {Web3Wrapper} from '@0xproject/web3-wrapper';
// tslint:disable-next-line:no-unused-variable
import * as BigNumber from 'bignumber.js';
import * as _ from 'lodash';
import {ECSignature} from '../types';
import {signatureUtils} from '../utils/signature_utils';
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`);
},
async isSenderAddressAsync(variableName: string, senderAddressHex: string,
web3Wrapper: Web3Wrapper): Promise<void> {
sharedAssert.isETHAddressHex(variableName, senderAddressHex);
const isSenderAddressAvailable = await web3Wrapper.isSenderAddressAvailableAsync(senderAddressHex);
sharedAssert.assert(isSenderAddressAvailable,
`Specified ${variableName} ${senderAddressHex} isn't available through the supplied web3 provider`,
);
},
async isUserAddressAvailableAsync(web3Wrapper: Web3Wrapper): Promise<void> {
const availableAddresses = await web3Wrapper.getAvailableAddressesAsync();
this.assert(!_.isEmpty(availableAddresses), 'No addresses were available on the provided web3 provider');
},
};

View File

@@ -1,7 +1,12 @@
import BigNumber from 'bignumber.js';
export const constants = {
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
TESTRPC_NETWORK_ID: 50,
MAX_DIGITS_IN_UNSIGNED_256_INT: 78,
INVALID_JUMP_PATTERN: 'invalid JUMP at',
OUT_OF_GAS_PATTERN: 'out of gas',
INVALID_TAKER_FORMAT: 'instance.taker is not of a type(s) string',
UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1),
DEFAULT_BLOCK_POLLING_INTERVAL: 1000,
};

View File

@@ -0,0 +1,87 @@
import * as _ from 'lodash';
import {AsyncMethod, SyncMethod, ZeroExError} from '../types';
import {constants} from './constants';
type ErrorTransformer = (err: Error) => Error;
const contractCallErrorTransformer = (error: Error) => {
if (_.includes(error.message, constants.INVALID_JUMP_PATTERN)) {
return new Error(ZeroExError.InvalidJump);
}
if (_.includes(error.message, constants.OUT_OF_GAS_PATTERN)) {
return new Error(ZeroExError.OutOfGas);
}
return error;
};
const schemaErrorTransformer = (error: Error) => {
if (_.includes(error.message, constants.INVALID_TAKER_FORMAT)) {
// tslint:disable-next-line:max-line-length
const errMsg = 'Order taker must be of type string. If you want anyone to be able to fill an order - pass ZeroEx.NULL_ADDRESS';
return new Error(errMsg);
}
return error;
};
/**
* Source: https://stackoverflow.com/a/29837695/3546986
*/
const asyncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
const asyncErrorHandlingDecorator = (
target: object, key: string|symbol, descriptor: TypedPropertyDescriptor<AsyncMethod>,
) => {
const originalMethod = (descriptor.value as AsyncMethod);
// Do not use arrow syntax here. Use a function expression in
// order to use the correct value of `this` in this method
// tslint:disable-next-line:only-arrow-functions
descriptor.value = async function(...args: any[]) {
try {
const result = await originalMethod.apply(this, args);
return result;
} catch (error) {
const transformedError = errorTransformer(error);
throw transformedError;
}
};
return descriptor;
};
return asyncErrorHandlingDecorator;
};
const syncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
const syncErrorHandlingDecorator = (
target: object, key: string|symbol, descriptor: TypedPropertyDescriptor<SyncMethod>,
) => {
const originalMethod = (descriptor.value as SyncMethod);
// Do not use arrow syntax here. Use a function expression in
// order to use the correct value of `this` in this method
// tslint:disable-next-line:only-arrow-functions
descriptor.value = function(...args: any[]) {
try {
const result = originalMethod.apply(this, args);
return result;
} catch (error) {
const transformedError = errorTransformer(error);
throw transformedError;
}
};
return descriptor;
};
return syncErrorHandlingDecorator;
};
// _.flow(f, g) = f ∘ g
const zeroExErrorTransformer = _.flow(schemaErrorTransformer, contractCallErrorTransformer);
export const decorators = {
asyncZeroExErrorHandler: asyncErrorHandlerFactory(zeroExErrorTransformer),
syncZeroExErrorHandler: syncErrorHandlerFactory(zeroExErrorTransformer),
};

View File

@@ -0,0 +1,89 @@
import BigNumber from 'bignumber.js';
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',
ProxyAllowance = 'proxyAllowance',
}
const ERR_MSG_MAPPING = {
[FailureReason.Balance]: {
[TradeSide.Maker]: {
[TransferType.Trade]: ExchangeContractErrs.InsufficientMakerBalance,
[TransferType.Fee]: ExchangeContractErrs.InsufficientMakerFeeBalance,
},
[TradeSide.Taker]: {
[TransferType.Trade]: ExchangeContractErrs.InsufficientTakerBalance,
[TransferType.Fee]: ExchangeContractErrs.InsufficientTakerFeeBalance,
},
},
[FailureReason.ProxyAllowance]: {
[TradeSide.Maker]: {
[TransferType.Trade]: ExchangeContractErrs.InsufficientMakerAllowance,
[TransferType.Fee]: ExchangeContractErrs.InsufficientMakerFeeAllowance,
},
[TradeSide.Taker]: {
[TransferType.Trade]: ExchangeContractErrs.InsufficientTakerAllowance,
[TransferType.Fee]: ExchangeContractErrs.InsufficientTakerFeeAllowance,
},
},
};
export class ExchangeTransferSimulator {
private _store: BalanceAndProxyAllowanceLazyStore;
private _UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber;
private static _throwValidationError(failureReason: FailureReason, tradeSide: TradeSide,
transferType: TransferType): never {
const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType];
throw new Error(errMsg);
}
constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) {
this._store = new BalanceAndProxyAllowanceLazyStore(token, defaultBlock);
this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS = token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
}
/**
* Simulates transferFrom call performed by a proxy
* @param tokenAddress Address of the token to be transferred
* @param from Owner of the transferred tokens
* @param to Recipient of the transferred tokens
* @param amountInBaseUnits The amount of tokens being transferred
* @param tradeSide Is Maker/Taker transferring
* @param transferType Is it a fee payment or a value transfer
*/
public async transferFromAsync(tokenAddress: string, from: string, to: string,
amountInBaseUnits: BigNumber, tradeSide: TradeSide,
transferType: TransferType): Promise<void> {
const balance = await this._store.getBalanceAsync(tokenAddress, from);
const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, from);
if (proxyAllowance.lessThan(amountInBaseUnits)) {
ExchangeTransferSimulator._throwValidationError(FailureReason.ProxyAllowance, tradeSide, transferType);
}
if (balance.lessThan(amountInBaseUnits)) {
ExchangeTransferSimulator._throwValidationError(FailureReason.Balance, tradeSide, transferType);
}
await this._decreaseProxyAllowanceAsync(tokenAddress, from, amountInBaseUnits);
await this._decreaseBalanceAsync(tokenAddress, from, amountInBaseUnits);
await this._increaseBalanceAsync(tokenAddress, to, amountInBaseUnits);
}
private async _decreaseProxyAllowanceAsync(tokenAddress: string, userAddress: string,
amountInBaseUnits: BigNumber): Promise<void> {
const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, userAddress);
if (!proxyAllowance.eq(this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
this._store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits));
}
}
private async _increaseBalanceAsync(tokenAddress: string, userAddress: string,
amountInBaseUnits: BigNumber): Promise<void> {
const balance = await this._store.getBalanceAsync(tokenAddress, userAddress);
this._store.setBalance(tokenAddress, userAddress, balance.plus(amountInBaseUnits));
}
private async _decreaseBalanceAsync(tokenAddress: string, userAddress: string,
amountInBaseUnits: BigNumber): Promise<void> {
const balance = await this._store.getBalanceAsync(tokenAddress, userAddress);
this._store.setBalance(tokenAddress, userAddress, balance.minus(amountInBaseUnits));
}
}

View File

@@ -0,0 +1,83 @@
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 {BlockRange, ContractEvents, IndexedFilterValues} from '../types';
const TOPIC_LENGTH = 32;
export const filterUtils = {
generateUUID(): string {
return uuid();
},
getFilter(address: string, eventName: ContractEvents,
indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi,
blockRange?: BlockRange): Web3.FilterObject {
const eventAbi = _.find(abi, {name: eventName}) as Web3.EventAbi;
const eventSignature = filterUtils.getEventSignatureFromAbiByName(eventAbi, eventName);
const topicForEventSignature = ethUtil.addHexPrefix(jsSHA3.keccak256(eventSignature));
const topicsForIndexedArgs = filterUtils.getTopicsForIndexedArgs(eventAbi, indexFilterValues);
const topics = [topicForEventSignature, ...topicsForIndexedArgs];
let filter: Web3.FilterObject = {
address,
topics,
};
if (!_.isUndefined(blockRange)) {
filter = {
...blockRange,
...filter,
};
}
return filter;
},
getEventSignatureFromAbiByName(eventAbi: Web3.EventAbi, eventName: ContractEvents): string {
const types = _.map(eventAbi.inputs, 'type');
const signature = `${eventAbi.name}(${types.join(',')})`;
return signature;
},
getTopicsForIndexedArgs(abi: Web3.EventAbi, indexFilterValues: IndexedFilterValues): Array<string|null> {
const topics: Array<string|null> = [];
for (const eventInput of abi.inputs) {
if (!eventInput.indexed) {
continue;
}
if (_.isUndefined(indexFilterValues[eventInput.name])) {
// Null is a wildcard topic in a JSON-RPC call
topics.push(null);
} else {
const value = indexFilterValues[eventInput.name] as string;
const buffer = ethUtil.toBuffer(value);
const paddedBuffer = ethUtil.setLengthLeft(buffer, TOPIC_LENGTH);
const topic = ethUtil.bufferToHex(paddedBuffer);
topics.push(topic);
}
}
return topics;
},
matchesFilter(log: Web3.LogEntry, filter: Web3.FilterObject): boolean {
if (!_.isUndefined(filter.address) && log.address !== filter.address) {
return false;
}
if (!_.isUndefined(filter.topics)) {
return filterUtils.matchesTopics(log.topics, filter.topics);
}
return true;
},
matchesTopics(logTopics: string[], filterTopics: Array<string[]|string|null>): boolean {
const matchesTopic = _.zipWith(logTopics, filterTopics, filterUtils.matchesTopic.bind(filterUtils));
const matchesTopics = _.every(matchesTopic);
return matchesTopics;
},
matchesTopic(logTopic: string, filterTopic: string[]|string|null): boolean {
if (_.isArray(filterTopic)) {
return _.includes(filterTopic, logTopic);
}
if (_.isString(filterTopic)) {
return filterTopic === logTopic;
}
// null topic is a wildcard
return true;
},
};

View File

@@ -0,0 +1,132 @@
import BigNumber from 'bignumber.js';
import * as _ from 'lodash';
import {ZeroEx} from '../0x';
import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper';
import {RemainingFillableCalculator} from '../order_watcher/remaining_fillable_calculator';
import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store';
import {OrderFilledCancelledLazyStore} from '../stores/order_filled_cancelled_lazy_store';
import {
ExchangeContractErrs,
OrderRelevantState,
OrderState,
OrderStateInvalid,
OrderStateValid,
SignedOrder,
} from '../types';
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;
this._orderFilledCancelledLazyStore = orderFilledCancelledLazyStore;
}
public async getOrderStateAsync(signedOrder: SignedOrder): Promise<OrderState> {
const orderRelevantState = await this.getOrderRelevantStateAsync(signedOrder);
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
try {
OrderStateUtils._validateIfOrderIsValid(signedOrder, orderRelevantState);
const orderState: OrderStateValid = {
isValid: true,
orderHash,
orderRelevantState,
};
return orderState;
} catch (err) {
const orderState: OrderStateInvalid = {
isValid: false,
orderHash,
error: err.message,
};
return orderState;
}
}
public async getOrderRelevantStateAsync(signedOrder: SignedOrder): Promise<OrderRelevantState> {
// HACK: We access the private property here but otherwise the interface will be less nice.
// If we pass it from the instantiator - there is no opportunity to get it there
// because JS doesn't support async constructors.
// Moreover - it's cached under the hood so it's equivalent to an async constructor.
const exchange = (this._orderFilledCancelledLazyStore as any)._exchange as ExchangeWrapper;
const zrxTokenAddress = exchange.getZRXTokenAddress();
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
const makerBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync(
signedOrder.makerTokenAddress, signedOrder.maker,
);
const makerProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
signedOrder.makerTokenAddress, signedOrder.maker,
);
const makerFeeBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync(
zrxTokenAddress, signedOrder.maker,
);
const makerFeeProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
zrxTokenAddress, signedOrder.maker,
);
const filledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getFilledTakerAmountAsync(orderHash);
const cancelledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getCancelledTakerAmountAsync(
orderHash,
);
const unavailableTakerTokenAmount = await exchange.getUnavailableTakerAmountAsync(orderHash);
const totalMakerTokenAmount = signedOrder.makerTokenAmount;
const totalTakerTokenAmount = signedOrder.takerTokenAmount;
const remainingTakerTokenAmount = totalTakerTokenAmount.minus(unavailableTakerTokenAmount);
const remainingMakerTokenAmount = remainingTakerTokenAmount.times(totalMakerTokenAmount)
.dividedToIntegerBy(totalTakerTokenAmount);
const 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,
makerFeeBalance,
makerFeeProxyAllowance,
filledTakerTokenAmount,
cancelledTakerTokenAmount,
remainingFillableMakerTokenAmount,
remainingFillableTakerTokenAmount,
};
return orderRelevantState;
}
}

View File

@@ -0,0 +1,165 @@
import BigNumber from 'bignumber.js';
import * as _ from 'lodash';
import {ZeroEx} from '../0x';
import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper';
import {ExchangeContractErrs, Order, SignedOrder, TradeSide, TransferType, ZeroExError} from '../types';
import {constants} from '../utils/constants';
import {utils} from '../utils/utils';
import {ExchangeTransferSimulator} from './exchange_transfer_simulator';
export class OrderValidationUtils {
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(exchangeWrapper: ExchangeWrapper) {
this._exchangeWrapper = exchangeWrapper;
}
public async validateOrderFillableOrThrowAsync(
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder, zrxTokenAddress: string,
expectedFillTakerTokenAmount?: BigNumber): Promise<void> {
const orderHash = utils.getOrderHashHex(signedOrder);
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
signedOrder.takerTokenAmount, unavailableTakerTokenAmount,
);
OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
let fillTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
if (!_.isUndefined(expectedFillTakerTokenAmount)) {
fillTakerTokenAmount = expectedFillTakerTokenAmount;
}
const fillMakerTokenAmount = OrderValidationUtils._getPartialAmount(
fillTakerTokenAmount,
signedOrder.takerTokenAmount,
signedOrder.makerTokenAmount,
);
await exchangeTradeEmulator.transferFromAsync(
signedOrder.makerTokenAddress, signedOrder.maker, signedOrder.taker, fillMakerTokenAmount,
TradeSide.Maker, TransferType.Trade,
);
const makerFeeAmount = OrderValidationUtils._getPartialAmount(
fillTakerTokenAmount,
signedOrder.takerTokenAmount,
signedOrder.makerFee,
);
await exchangeTradeEmulator.transferFromAsync(
zrxTokenAddress, signedOrder.maker, signedOrder.feeRecipient, makerFeeAmount,
TradeSide.Maker, TransferType.Fee,
);
}
public async validateFillOrderThrowIfInvalidAsync(
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder,
fillTakerTokenAmount: BigNumber, takerAddress: string,
zrxTokenAddress: string): Promise<BigNumber> {
if (fillTakerTokenAmount.eq(0)) {
throw new Error(ExchangeContractErrs.OrderFillAmountZero);
}
const orderHash = utils.getOrderHashHex(signedOrder);
if (!ZeroEx.isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker)) {
throw new Error(ZeroExError.InvalidSignature);
}
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
signedOrder.takerTokenAmount, unavailableTakerTokenAmount,
);
if (signedOrder.taker !== constants.NULL_ADDRESS && signedOrder.taker !== takerAddress) {
throw new Error(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker);
}
OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
const remainingTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
const filledTakerTokenAmount = remainingTakerTokenAmount.lessThan(fillTakerTokenAmount) ?
remainingTakerTokenAmount :
fillTakerTokenAmount;
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
exchangeTradeEmulator, signedOrder, filledTakerTokenAmount, takerAddress, zrxTokenAddress,
);
const wouldRoundingErrorOccur = await this._exchangeWrapper.isRoundingErrorAsync(
filledTakerTokenAmount, signedOrder.takerTokenAmount, signedOrder.makerTokenAmount,
);
if (wouldRoundingErrorOccur) {
throw new Error(ExchangeContractErrs.OrderFillRoundingError);
}
return filledTakerTokenAmount;
}
public async validateFillOrKillOrderThrowIfInvalidAsync(
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder,
fillTakerTokenAmount: BigNumber, takerAddress: string, zrxTokenAddress: string): Promise<void> {
const filledTakerTokenAmount = await this.validateFillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress,
);
if (filledTakerTokenAmount !== fillTakerTokenAmount) {
throw new Error(ExchangeContractErrs.InsufficientRemainingFillAmount);
}
}
}

View File

@@ -0,0 +1,45 @@
import * as ethUtil from 'ethereumjs-util';
import {ECSignature} from '../types';
export const signatureUtils = {
isValidSignature(data: string, signature: ECSignature, signerAddress: string): boolean {
const dataBuff = ethUtil.toBuffer(data);
const msgHashBuff = ethUtil.hashPersonalMessage(dataBuff);
try {
const pubKey = ethUtil.ecrecover(
msgHashBuff,
signature.v,
ethUtil.toBuffer(signature.r),
ethUtil.toBuffer(signature.s));
const retrievedAddress = ethUtil.bufferToHex(ethUtil.pubToAddress(pubKey));
return retrievedAddress === signerAddress;
} catch (err) {
return false;
}
},
parseSignatureHexAsVRS(signatureHex: string): ECSignature {
const signatureBuffer = ethUtil.toBuffer(signatureHex);
let v = signatureBuffer[0];
if (v < 27) {
v += 27;
}
const r = signatureBuffer.slice(1, 33);
const s = signatureBuffer.slice(33, 65);
const ecSignature: ECSignature = {
v,
r: ethUtil.bufferToHex(r),
s: ethUtil.bufferToHex(s),
};
return ecSignature;
},
parseSignatureHexAsRSV(signatureHex: string): ECSignature {
const {v, r, s} = ethUtil.fromRpcSig(signatureHex);
const ecSignature: ECSignature = {
v,
r: ethUtil.bufferToHex(r),
s: ethUtil.bufferToHex(s),
};
return ecSignature;
},
};

View File

@@ -1,9 +1,10 @@
import * as _ from 'lodash';
import * as BN from 'bn.js';
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';
import * as BigNumber from 'bignumber.js';
export const utils = {
/**
@@ -12,7 +13,7 @@ export const utils = {
* expects values of Solidity type `uint` to be passed as type `BN`.
* We do not use BN anywhere else in the codebase.
*/
bigNumberToBN(value: BigNumber.BigNumber) {
bigNumberToBN(value: BigNumber) {
return new BN(value.toString(), 10);
},
consoleLog(message: string): void {
@@ -22,27 +23,26 @@ export const utils = {
isParityNode(nodeVersion: string): boolean {
return _.includes(nodeVersion, 'Parity');
},
isValidOrderHash(orderHashHex: string): boolean {
const isValid = /^0x[0-9A-F]{64}$/i.test(orderHashHex);
return isValid;
isTestRpc(nodeVersion: string): boolean {
return _.includes(nodeVersion, 'TestRPC');
},
spawnSwitchErr(name: string, value: any): Error {
return new Error(`Unexpected switch value: ${value} encountered for ${name}`);
},
getOrderHashHex(order: Order|SignedOrder, exchangeContractAddr: string): string {
getOrderHashHex(order: Order|SignedOrder): string {
const orderParts = [
{value: exchangeContractAddr, type: SolidityTypes.address},
{value: order.maker, type: SolidityTypes.address},
{value: order.taker, type: SolidityTypes.address},
{value: order.makerTokenAddress, type: SolidityTypes.address},
{value: order.takerTokenAddress, type: SolidityTypes.address},
{value: order.feeRecipient, type: SolidityTypes.address},
{value: utils.bigNumberToBN(order.makerTokenAmount), type: SolidityTypes.uint256},
{value: utils.bigNumberToBN(order.takerTokenAmount), type: SolidityTypes.uint256},
{value: utils.bigNumberToBN(order.makerFee), type: SolidityTypes.uint256},
{value: utils.bigNumberToBN(order.takerFee), type: SolidityTypes.uint256},
{value: utils.bigNumberToBN(order.expirationUnixTimestampSec), type: SolidityTypes.uint256},
{value: utils.bigNumberToBN(order.salt), type: SolidityTypes.uint256},
{value: order.exchangeContractAddress, type: SolidityTypes.Address},
{value: order.maker, type: SolidityTypes.Address},
{value: order.taker, type: SolidityTypes.Address},
{value: order.makerTokenAddress, type: SolidityTypes.Address},
{value: order.takerTokenAddress, type: SolidityTypes.Address},
{value: order.feeRecipient, type: SolidityTypes.Address},
{value: utils.bigNumberToBN(order.makerTokenAmount), type: SolidityTypes.Uint256},
{value: utils.bigNumberToBN(order.takerTokenAmount), type: SolidityTypes.Uint256},
{value: utils.bigNumberToBN(order.makerFee), type: SolidityTypes.Uint256},
{value: utils.bigNumberToBN(order.takerFee), type: SolidityTypes.Uint256},
{value: utils.bigNumberToBN(order.expirationUnixTimestampSec), type: SolidityTypes.Uint256},
{value: utils.bigNumberToBN(order.salt), type: SolidityTypes.Uint256},
];
const types = _.map(orderParts, o => o.type);
const values = _.map(orderParts, o => o.value);
@@ -50,7 +50,10 @@ export const utils = {
const hashHex = ethUtil.bufferToHex(hashBuff);
return hashHex;
},
getCurrentUnixTimestamp(): BigNumber.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,21 +1,29 @@
import * as _ from 'lodash';
import {BlockchainLifecycle} from '@0xproject/dev-utils';
import BigNumber from 'bignumber.js';
import * as chai from 'chai';
import {chaiSetup} from './utils/chai_setup';
import * as _ from 'lodash';
import 'mocha';
import * as BigNumber from 'bignumber.js';
import * as Sinon from 'sinon';
import {ZeroEx, Order} from '../src';
import {ApprovalContractEventArgs, LogWithDecodedArgs, Order, TokenEvents, ZeroEx} from '../src';
import {chaiSetup} from './utils/chai_setup';
import {constants} from './utils/constants';
import {TokenUtils} from './utils/token_utils';
import {web3Factory} from './utils/web3_factory';
const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL);
chaiSetup.configure();
const expect = chai.expect;
describe('ZeroEx library', () => {
const web3 = web3Factory.create();
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 () => {
const web3 = web3Factory.create();
const zeroEx = new ZeroEx(web3.currentProvider);
// Instantiate the contract instances with the current provider
await (zeroEx.exchange as any)._getExchangeContractAsync();
await (zeroEx.tokenRegistry as any)._getTokenRegistryContractAsync();
@@ -25,19 +33,19 @@ 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();
expect((zeroEx.tokenRegistry as any)._tokenRegistryContractIfExists).to.be.undefined();
// Check that all nested web3 instances return the updated provider
// 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', () => {
@@ -50,8 +58,6 @@ describe('ZeroEx library', () => {
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
};
const address = '0x5409ed021d9299bf6814279a6a1411a7e866a631';
const web3 = web3Factory.create();
const zeroEx = new ZeroEx(web3.currentProvider);
it('should return false if the data doesn\'t pertain to the signature & address', async () => {
expect(ZeroEx.isValidSignature('0x0', signature, address)).to.be.false();
return expect(
@@ -59,7 +65,7 @@ describe('ZeroEx library', () => {
).to.become(false);
});
it('should return false if the address doesn\'t pertain to the signature & data', async () => {
const validUnrelatedAddress = '0x8b0292B11a196601eD2ce54B665CaFEca0347D42';
const validUnrelatedAddress = '0x8b0292b11a196601ed2ce54b665cafeca0347d42';
expect(ZeroEx.isValidSignature(dataHex, signature, validUnrelatedAddress)).to.be.false();
return expect(
(zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync(dataHex, signature,
@@ -76,9 +82,9 @@ describe('ZeroEx library', () => {
it('should return true if the signature does pertain to the dataHex & address', async () => {
const isValidSignatureLocal = ZeroEx.isValidSignature(dataHex, signature, address);
expect(isValidSignatureLocal).to.be.true();
const isValidSignatureOnContract = await (zeroEx.exchange as any)
._isValidSignatureUsingContractCallAsync(dataHex, signature, address);
return expect(isValidSignatureOnContract).to.be.true();
return expect(
(zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync(dataHex, signature, address),
).to.become(true);
});
});
describe('#generateSalt', () => {
@@ -108,6 +114,12 @@ describe('ZeroEx library', () => {
});
});
describe('#toUnitAmount', () => {
it('should throw if invalid baseUnit amount supplied as argument', () => {
const invalidBaseUnitAmount = new BigNumber(1000000000.4);
const decimals = 6;
expect(() => ZeroEx.toUnitAmount(invalidBaseUnitAmount, decimals))
.to.throw('amount should be in baseUnits (no decimals), found value: 1000000000.4');
});
it('Should return the expected unit amount for the decimals passed in', () => {
const baseUnitAmount = new BigNumber(1000000000);
const decimals = 6;
@@ -124,16 +136,23 @@ describe('ZeroEx library', () => {
const expectedUnitAmount = new BigNumber(1000000000);
expect(baseUnitAmount).to.be.bignumber.equal(expectedUnitAmount);
});
it('should throw if unitAmount has more decimals then specified as the max decimal precision', () => {
const unitAmount = new BigNumber(0.823091);
const decimals = 5;
expect(() => ZeroEx.toBaseUnitAmount(unitAmount, decimals))
.to.throw('Invalid unit amount: 0.823091 - Too many decimal places');
});
});
describe('#getOrderHashHexAsync', () => {
const exchangeContractAddress = constants.NULL_ADDRESS;
const expectedOrderHash = '0x103a5e97dab5dbeb8f385636f86a7d1e458a7ccbe1bd194727f0b2f85ab116c7';
describe('#getOrderHashHex', () => {
const expectedOrderHash = '0x39da987067a3c9e5f1617694f1301326ba8c8b0498ebef5df4863bed394e3c83';
const fakeExchangeContractAddress = '0xb69e673309512a9d726f87304c6984054f87a93b';
const order: Order = {
maker: constants.NULL_ADDRESS,
taker: constants.NULL_ADDRESS,
feeRecipient: constants.NULL_ADDRESS,
makerTokenAddress: constants.NULL_ADDRESS,
takerTokenAddress: constants.NULL_ADDRESS,
exchangeContractAddress: fakeExchangeContractAddress,
salt: new BigNumber(0),
makerFee: new BigNumber(0),
takerFee: new BigNumber(0),
@@ -141,30 +160,23 @@ describe('ZeroEx library', () => {
takerTokenAmount: new BigNumber(0),
expirationUnixTimestampSec: new BigNumber(0),
};
let stubs: Sinon.SinonStub[] = [];
afterEach(() => {
// clean up any stubs after the test has completed
_.each(stubs, s => s.restore());
stubs = [];
});
it('calculates the order hash', async () => {
const web3 = web3Factory.create();
const zeroEx = new ZeroEx(web3.currentProvider);
stubs = [
Sinon.stub((zeroEx as any), '_getExchangeAddressAsync')
.returns(Promise.resolve(exchangeContractAddress)),
];
const orderHash = await zeroEx.getOrderHashHexAsync(order);
const orderHash = ZeroEx.getOrderHashHex(order);
expect(orderHash).to.be.equal(expectedOrderHash);
});
it('throws a readable error message if taker format is invalid', async () => {
const orderWithInvalidtakerFormat = {
...order,
taker: null as any as string,
};
// tslint:disable-next-line:max-line-length
const expectedErrorMessage = 'Order taker must be of type string. If you want anyone to be able to fill an order - pass ZeroEx.NULL_ADDRESS';
expect(() => ZeroEx.getOrderHashHex(orderWithInvalidtakerFormat)).to.throw(expectedErrorMessage);
});
});
describe('#signOrderHashAsync', () => {
let stubs: Sinon.SinonStub[] = [];
let makerAddress: string;
const web3 = web3Factory.create();
const zeroEx = new ZeroEx(web3.currentProvider);
before(async () => {
const availableAddreses = await zeroEx.getAvailableAddressesAsync();
makerAddress = availableAddreses[0];
@@ -174,7 +186,7 @@ describe('ZeroEx library', () => {
_.each(stubs, s => s.restore());
stubs = [];
});
it ('Should return the correct ECSignature on TestPRC nodeVersion', async () => {
it('Should return the correct ECSignature', async () => {
const orderHash = '0x6927e990021d23b1eb7b8789f6a6feaf98fe104bb0cf8259421b79f9a34222b0';
const expectedECSignature = {
v: 27,
@@ -184,8 +196,7 @@ describe('ZeroEx library', () => {
const ecSignature = await zeroEx.signOrderHashAsync(orderHash, makerAddress);
expect(ecSignature).to.deep.equal(expectedECSignature);
});
it ('should return the correct ECSignature on Parity > V1.6.6', async () => {
const newParityNodeVersion = 'Parity//v1.6.7-beta-e128418-20170518/x86_64-macos/rustc1.17.0';
it('should return the correct ECSignature for signatureHex concatenated as R + S + V', async () => {
const orderHash = '0x34decbedc118904df65f379a175bb39ca18209d6ce41d5ed549d54e6e0a95004';
// tslint:disable-next-line: max-line-length
const signature = '0x22109d11d79cb8bf96ed88625e1cd9558800c4073332a9a02857499883ee5ce3050aa3cc1f2c435e67e114cdce54b9527b4f50548342401bc5d2b77adbdacb021b';
@@ -195,8 +206,6 @@ describe('ZeroEx library', () => {
s: '0x050aa3cc1f2c435e67e114cdce54b9527b4f50548342401bc5d2b77adbdacb02',
};
stubs = [
Sinon.stub((zeroEx as any)._web3Wrapper, 'getNodeVersionAsync')
.returns(Promise.resolve(newParityNodeVersion)),
Sinon.stub((zeroEx as any)._web3Wrapper, 'signTransactionAsync')
.returns(Promise.resolve(signature)),
Sinon.stub(ZeroEx, 'isValidSignature').returns(true),
@@ -205,8 +214,7 @@ describe('ZeroEx library', () => {
const ecSignature = await zeroEx.signOrderHashAsync(orderHash, makerAddress);
expect(ecSignature).to.deep.equal(expectedECSignature);
});
it ('should return the correct ECSignature on Parity < V1.6.6', async () => {
const newParityNodeVersion = 'Parity//v1.6.6-beta-8c6e3f3-20170411/x86_64-macos/rustc1.16.0';
it('should return the correct ECSignature for signatureHex concatenated as V + R + S', async () => {
const orderHash = '0xc793e33ffded933b76f2f48d9aa3339fc090399d5e7f5dec8d3660f5480793f7';
// tslint:disable-next-line: max-line-length
const signature = '0x1bc80bedc6756722672753413efdd749b5adbd4fd552595f59c13427407ee9aee02dea66f25a608bbae457e020fb6decb763deb8b7192abab624997242da248960';
@@ -216,8 +224,6 @@ describe('ZeroEx library', () => {
s: '0x2dea66f25a608bbae457e020fb6decb763deb8b7192abab624997242da248960',
};
stubs = [
Sinon.stub((zeroEx as any)._web3Wrapper, 'getNodeVersionAsync')
.returns(Promise.resolve(newParityNodeVersion)),
Sinon.stub((zeroEx as any)._web3Wrapper, 'signTransactionAsync')
.returns(Promise.resolve(signature)),
Sinon.stub(ZeroEx, 'isValidSignature').returns(true),
@@ -227,4 +233,46 @@ describe('ZeroEx library', () => {
expect(ecSignature).to.deep.equal(expectedECSignature);
});
});
describe('#awaitTransactionMinedAsync', () => {
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
it('returns transaction receipt with decoded logs', async () => {
const availableAddresses = await zeroEx.getAvailableAddressesAsync();
const coinbase = availableAddresses[0];
const tokens = await zeroEx.tokenRegistry.getTokensAsync();
const tokenUtils = new TokenUtils(tokens);
const zrxTokenAddress = tokenUtils.getProtocolTokenOrThrow().address;
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>;
expect(log.event).to.be.equal(TokenEvents.Approval);
expect(log.args._owner).to.be.equal(coinbase);
expect(log.args._spender).to.be.equal(proxyAddress);
expect(log.args._value).to.be.bignumber.equal(zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
});
});
describe('#config', () => {
it('allows to specify exchange contract address', async () => {
const zeroExConfig = {
exchangeContractAddress: ZeroEx.NULL_ADDRESS,
networkId: constants.TESTRPC_NETWORK_ID,
};
const zeroExWithWrongExchangeAddress = new ZeroEx(web3.currentProvider, zeroExConfig);
expect(zeroExWithWrongExchangeAddress.exchange.getContractAddress()).to.be.equal(ZeroEx.NULL_ADDRESS);
});
it('allows to specify token registry token contract address', async () => {
const zeroExConfig = {
tokenRegistryContractAddress: ZeroEx.NULL_ADDRESS,
networkId: constants.TESTRPC_NETWORK_ID,
};
const zeroExWithWrongTokenRegistryAddress = new ZeroEx(web3.currentProvider, zeroExConfig);
expect(zeroExWithWrongTokenRegistryAddress.tokenRegistry.getContractAddress())
.to.be.equal(ZeroEx.NULL_ADDRESS);
});
});
});

View File

@@ -0,0 +1,55 @@
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();
// Those tests are slower cause they're talking to a remote node
const TIMEOUT = 10000;
describe('Artifacts', () => {
describe('contracts are deployed on kovan', () => {
const kovanRpcUrl = constants.KOVAN_RPC_URL;
const packageJSONContent = fs.readFileSync('package.json', 'utf-8');
const packageJSON = JSON.parse(packageJSONContent);
const mnemonic = packageJSON.config.mnemonic;
const web3Provider = new HDWalletProvider(mnemonic, kovanRpcUrl);
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.proxy as any)._getTokenTransferProxyContractAsync();
}).timeout(TIMEOUT);
it('exchange contract is deployed', async () => {
await (zeroEx.exchange as any)._getExchangeContractAsync();
}).timeout(TIMEOUT);
});
describe('contracts are deployed on ropsten', () => {
const ropstenRpcUrl = constants.ROPSTEN_RPC_URL;
const packageJSONContent = fs.readFileSync('package.json', 'utf-8');
const packageJSON = JSON.parse(packageJSONContent);
const mnemonic = packageJSON.config.mnemonic;
const web3Provider = new HDWalletProvider(mnemonic, ropstenRpcUrl);
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.proxy as any)._getTokenTransferProxyContractAsync();
}).timeout(TIMEOUT);
it('exchange contract is deployed', async () => {
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';
@@ -21,7 +27,7 @@ describe('Assertion library', () => {
const varName = 'address';
return expect(assert.isSenderAddressAsync(varName, validUnrelatedAddress, (zeroEx as any)._web3Wrapper))
.to.be.rejectedWith(
`Specified ${varName} ${validUnrelatedAddress} isn't available through the supplied web3 instance`,
`Specified ${varName} ${validUnrelatedAddress} isn't available through the supplied web3 provider`,
);
});
it('doesn\'t throw if address is available', async () => {

View File

@@ -0,0 +1,343 @@
import {BlockchainLifecycle} from '@0xproject/dev-utils';
import BigNumber from 'bignumber.js';
import * as chai from 'chai';
import 'mocha';
import * as Web3 from 'web3';
import {
ApprovalContractEventArgs,
BlockParamLiteral,
BlockRange,
DecodedLogEvent,
DepositContractEventArgs,
EtherTokenEvents,
Token,
TransferContractEventArgs,
WithdrawalContractEventArgs,
ZeroEx,
ZeroExError,
} from '../src';
import {artifacts} from '../src/artifacts';
import {DoneCallback} from '../src/types';
import {chaiSetup} from './utils/chai_setup';
import {constants} from './utils/constants';
import {TokenUtils} from './utils/token_utils';
import {web3Factory} from './utils/web3_factory';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL);
// Since the address depositing/withdrawing ETH/WETH also needs to pay gas costs for the transaction,
// a small amount of ETH will be used to pay this gas cost. We therefore check that the difference between
// 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 = 62517;
describe('EtherTokenWrapper', () => {
let web3: Web3;
let zeroEx: ZeroEx;
let tokens: Token[];
let userAddresses: string[];
let addressWithETH: string;
let wethContractAddress: string;
let depositWeiAmount: BigNumber;
let decimalPlaces: number;
let addressWithoutFunds: string;
const gasPrice = new BigNumber(1);
const zeroExConfig = {
gasPrice,
networkId: constants.TESTRPC_NETWORK_ID,
};
const transferAmount = new BigNumber(42);
const allowanceAmount = new BigNumber(42);
const depositAmount = new BigNumber(42);
const withdrawalAmount = new BigNumber(42);
before(async () => {
web3 = web3Factory.create();
zeroEx = new ZeroEx(web3.currentProvider, zeroExConfig);
tokens = await zeroEx.tokenRegistry.getTokensAsync();
userAddresses = await zeroEx.getAvailableAddressesAsync();
addressWithETH = userAddresses[0];
wethContractAddress = (zeroEx.etherToken as any)._getContractAddress(artifacts.EtherTokenArtifact);
depositWeiAmount = (zeroEx as any)._web3Wrapper.toWei(new BigNumber(5));
decimalPlaces = 7;
addressWithoutFunds = userAddresses[1];
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('#depositAsync', () => {
it('should successfully deposit ETH and issue Wrapped ETH tokens', async () => {
const preETHBalance = await (zeroEx as any)._web3Wrapper.getBalanceInWeiAsync(addressWithETH);
const preWETHBalance = await zeroEx.token.getBalanceAsync(wethContractAddress, addressWithETH);
expect(preETHBalance).to.be.bignumber.gt(0);
expect(preWETHBalance).to.be.bignumber.equal(0);
const txHash = await zeroEx.etherToken.depositAsync(wethContractAddress, depositWeiAmount, addressWithETH);
await zeroEx.awaitTransactionMinedAsync(txHash);
const postETHBalanceInWei = await (zeroEx as any)._web3Wrapper.getBalanceInWeiAsync(addressWithETH);
const postWETHBalanceInBaseUnits = await zeroEx.token.getBalanceAsync(wethContractAddress, addressWithETH);
expect(postWETHBalanceInBaseUnits).to.be.bignumber.equal(depositWeiAmount);
const remainingETHInWei = preETHBalance.minus(depositWeiAmount);
const gasCost = remainingETHInWei.minus(postETHBalanceInWei);
expect(gasCost).to.be.bignumber.lte(MAX_REASONABLE_GAS_COST_IN_WEI);
});
it('should throw if user has insufficient ETH balance for deposit', async () => {
const preETHBalance = await (zeroEx as any)._web3Wrapper.getBalanceInWeiAsync(addressWithETH);
const extraETHBalance = (zeroEx as any)._web3Wrapper.toWei(5, 'ether');
const overETHBalanceinWei = preETHBalance.add(extraETHBalance);
return expect(
zeroEx.etherToken.depositAsync(wethContractAddress, overETHBalanceinWei, addressWithETH),
).to.be.rejectedWith(ZeroExError.InsufficientEthBalanceForDeposit);
});
});
describe('#withdrawAsync', () => {
it('should successfully withdraw ETH in return for Wrapped ETH tokens', async () => {
const ETHBalanceInWei = await (zeroEx as any)._web3Wrapper.getBalanceInWeiAsync(addressWithETH);
await zeroEx.etherToken.depositAsync(wethContractAddress, depositWeiAmount, addressWithETH);
const expectedPreETHBalance = ETHBalanceInWei.minus(depositWeiAmount);
const preETHBalance = await (zeroEx as any)._web3Wrapper.getBalanceInWeiAsync(addressWithETH);
const preWETHBalance = await zeroEx.token.getBalanceAsync(wethContractAddress, addressWithETH);
let gasCost = expectedPreETHBalance.minus(preETHBalance);
expect(gasCost).to.be.bignumber.lte(MAX_REASONABLE_GAS_COST_IN_WEI);
expect(preWETHBalance).to.be.bignumber.equal(depositWeiAmount);
const txHash = await zeroEx.etherToken.withdrawAsync(wethContractAddress, depositWeiAmount, addressWithETH);
await zeroEx.awaitTransactionMinedAsync(txHash);
const postETHBalance = await (zeroEx as any)._web3Wrapper.getBalanceInWeiAsync(addressWithETH);
const postWETHBalanceInBaseUnits = await zeroEx.token.getBalanceAsync(wethContractAddress, addressWithETH);
expect(postWETHBalanceInBaseUnits).to.be.bignumber.equal(0);
const expectedETHBalance = preETHBalance.add(depositWeiAmount).round(decimalPlaces);
gasCost = expectedETHBalance.minus(postETHBalance);
expect(gasCost).to.be.bignumber.lte(MAX_REASONABLE_GAS_COST_IN_WEI);
});
it('should throw if user has insufficient WETH balance for withdrawl', async () => {
const preWETHBalance = await zeroEx.token.getBalanceAsync(wethContractAddress, addressWithETH);
expect(preWETHBalance).to.be.bignumber.equal(0);
const overWETHBalance = preWETHBalance.add(999999999);
return expect(
zeroEx.etherToken.withdrawAsync(wethContractAddress, overWETHBalance, addressWithETH),
).to.be.rejectedWith(ZeroExError.InsufficientWEthBalanceForWithdrawal);
});
});
describe('#subscribe', () => {
const indexFilterValues = {};
let etherTokenAddress: string;
before(() => {
const tokenUtils = new TokenUtils(tokens);
const etherToken = tokenUtils.getWethTokenOrThrow();
etherTokenAddress = etherToken.address;
});
afterEach(() => {
zeroEx.etherToken.unsubscribeAll();
});
// Hack: Mocha does not allow a test to be both async and have a `done` callback
// Since we need to await the receipt of the event in the `subscribe` callback,
// we do need both. A hack is to make the top-level async fn w/ a done callback and then
// wrap the rest of the test in an async block
// Source: https://github.com/mochajs/mocha/issues/2407
it('Should receive the Transfer event when tokens are transfered', (done: DoneCallback) => {
(async () => {
const callback = (err: Error, logEvent: DecodedLogEvent<TransferContractEventArgs>) => {
expect(err).to.be.null();
expect(logEvent).to.not.be.undefined();
expect(logEvent.isRemoved).to.be.false();
expect(logEvent.log.logIndex).to.be.equal(0);
expect(logEvent.log.transactionIndex).to.be.equal(0);
expect(logEvent.log.blockNumber).to.be.a('number');
const args = logEvent.log.args;
expect(args._from).to.be.equal(addressWithETH);
expect(args._to).to.be.equal(addressWithoutFunds);
expect(args._value).to.be.bignumber.equal(transferAmount);
done();
};
await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
zeroEx.etherToken.subscribe(
etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callback);
await zeroEx.token.transferAsync(
etherTokenAddress, addressWithETH, addressWithoutFunds, transferAmount,
);
})().catch(done);
});
it('Should receive the Approval event when allowance is being set', (done: DoneCallback) => {
(async () => {
const callback = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
expect(err).to.be.null();
expect(logEvent).to.not.be.undefined();
expect(logEvent.isRemoved).to.be.false();
const args = logEvent.log.args;
expect(args._owner).to.be.equal(addressWithETH);
expect(args._spender).to.be.equal(addressWithoutFunds);
expect(args._value).to.be.bignumber.equal(allowanceAmount);
done();
};
zeroEx.etherToken.subscribe(
etherTokenAddress, EtherTokenEvents.Approval, indexFilterValues, callback);
await zeroEx.token.setAllowanceAsync(
etherTokenAddress, addressWithETH, addressWithoutFunds, allowanceAmount,
);
})().catch(done);
});
it('Should receive the Deposit event when ether is being deposited', (done: DoneCallback) => {
(async () => {
const callback = (err: Error, logEvent: DecodedLogEvent<DepositContractEventArgs>) => {
expect(err).to.be.null();
expect(logEvent).to.not.be.undefined();
expect(logEvent.isRemoved).to.be.false();
const args = logEvent.log.args;
expect(args._owner).to.be.equal(addressWithETH);
expect(args._value).to.be.bignumber.equal(depositAmount);
done();
};
zeroEx.etherToken.subscribe(
etherTokenAddress, EtherTokenEvents.Deposit, indexFilterValues, callback);
await zeroEx.etherToken.depositAsync(
etherTokenAddress, depositAmount, addressWithETH,
);
})().catch(done);
});
it('Should receive the Withdrawal event when ether is being withdrawn', (done: DoneCallback) => {
(async () => {
const callback = (err: Error, logEvent: DecodedLogEvent<WithdrawalContractEventArgs>) => {
expect(err).to.be.null();
expect(logEvent).to.not.be.undefined();
expect(logEvent.isRemoved).to.be.false();
const args = logEvent.log.args;
expect(args._owner).to.be.equal(addressWithETH);
expect(args._value).to.be.bignumber.equal(depositAmount);
done();
};
await zeroEx.etherToken.depositAsync(
etherTokenAddress, depositAmount, addressWithETH,
);
zeroEx.etherToken.subscribe(
etherTokenAddress, EtherTokenEvents.Withdrawal, indexFilterValues, callback);
await zeroEx.etherToken.withdrawAsync(
etherTokenAddress, withdrawalAmount, addressWithETH,
);
})().catch(done);
});
it('should cancel outstanding subscriptions when ZeroEx.setProvider is called', (done: DoneCallback) => {
(async () => {
const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
done(new Error('Expected this subscription to have been cancelled'));
};
zeroEx.etherToken.subscribe(
etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled,
);
const callbackToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
done();
};
const newProvider = web3Factory.getRpcProvider();
zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID);
await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
zeroEx.etherToken.subscribe(
etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callbackToBeCalled,
);
await zeroEx.token.transferAsync(
etherTokenAddress, addressWithETH, addressWithoutFunds, transferAmount,
);
})().catch(done);
});
it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => {
(async () => {
const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
done(new Error('Expected this subscription to have been cancelled'));
};
await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
const subscriptionToken = zeroEx.etherToken.subscribe(
etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled);
zeroEx.etherToken.unsubscribe(subscriptionToken);
await zeroEx.token.transferAsync(
etherTokenAddress, addressWithETH, addressWithoutFunds, transferAmount,
);
done();
})().catch(done);
});
});
describe('#getLogsAsync', () => {
let etherTokenAddress: string;
let tokenTransferProxyAddress: string;
const blockRange: BlockRange = {
fromBlock: 0,
toBlock: BlockParamLiteral.Latest,
};
let txHash: string;
before(() => {
addressWithETH = userAddresses[0];
const tokenUtils = new TokenUtils(tokens);
const etherToken = tokenUtils.getWethTokenOrThrow();
etherTokenAddress = etherToken.address;
tokenTransferProxyAddress = zeroEx.proxy.getContractAddress();
});
it('should get logs with decoded args emitted by Approval', async () => {
txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(etherTokenAddress, addressWithETH);
await zeroEx.awaitTransactionMinedAsync(txHash);
const eventName = EtherTokenEvents.Approval;
const indexFilterValues = {};
const logs = await zeroEx.etherToken.getLogsAsync<ApprovalContractEventArgs>(
etherTokenAddress, eventName, blockRange, indexFilterValues,
);
expect(logs).to.have.length(1);
const args = logs[0].args;
expect(logs[0].event).to.be.equal(eventName);
expect(args._owner).to.be.equal(addressWithETH);
expect(args._spender).to.be.equal(tokenTransferProxyAddress);
expect(args._value).to.be.bignumber.equal(zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
});
it('should get logs with decoded args emitted by Deposit', async () => {
await zeroEx.etherToken.depositAsync(etherTokenAddress, depositAmount, addressWithETH);
const eventName = EtherTokenEvents.Deposit;
const indexFilterValues = {};
const logs = await zeroEx.etherToken.getLogsAsync<DepositContractEventArgs>(
etherTokenAddress, eventName, blockRange, indexFilterValues,
);
expect(logs).to.have.length(1);
const args = logs[0].args;
expect(logs[0].event).to.be.equal(eventName);
expect(args._owner).to.be.equal(addressWithETH);
expect(args._value).to.be.bignumber.equal(depositAmount);
});
it('should only get the logs with the correct event name', async () => {
txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(etherTokenAddress, addressWithETH);
await zeroEx.awaitTransactionMinedAsync(txHash);
const differentEventName = EtherTokenEvents.Transfer;
const indexFilterValues = {};
const logs = await zeroEx.etherToken.getLogsAsync(
etherTokenAddress, differentEventName, blockRange, indexFilterValues,
);
expect(logs).to.have.length(0);
});
it('should only get the logs with the correct indexed fields', async () => {
txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(etherTokenAddress, addressWithETH);
await zeroEx.awaitTransactionMinedAsync(txHash);
txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(etherTokenAddress, addressWithoutFunds);
await zeroEx.awaitTransactionMinedAsync(txHash);
const eventName = EtherTokenEvents.Approval;
const indexFilterValues = {
_owner: addressWithETH,
};
const logs = await zeroEx.etherToken.getLogsAsync<ApprovalContractEventArgs>(
etherTokenAddress, eventName, blockRange, indexFilterValues,
);
expect(logs).to.have.length(1);
const args = logs[0].args;
expect(args._owner).to.be.equal(addressWithETH);
});
});
});

View File

@@ -0,0 +1,125 @@
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import * as chai from 'chai';
import * as _ from 'lodash';
import 'mocha';
import * as Sinon from 'sinon';
import * as Web3 from 'web3';
import {
LogEvent,
} from '../src';
import {EventWatcher} from '../src/order_watcher/event_watcher';
import {DoneCallback} from '../src/types';
import {chaiSetup} from './utils/chai_setup';
import {web3Factory} from './utils/web3_factory';
chaiSetup.configure();
const expect = chai.expect;
describe('EventWatcher', () => {
let web3: Web3;
let stubs: Sinon.SinonStub[] = [];
let eventWatcher: EventWatcher;
let web3Wrapper: Web3Wrapper;
const logA: Web3.LogEntry = {
address: '0x71d271f8b14adef568f8f28f1587ce7271ac4ca5',
blockHash: null,
blockNumber: null,
data: '',
logIndex: null,
topics: [],
transactionHash: '0x004881d38cd4a8f72f1a0d68c8b9b8124504706041ff37019c1d1ed6bfda8e17',
transactionIndex: 0,
};
const logB: Web3.LogEntry = {
address: '0x8d12a197cb00d4747a1fe03395095ce2a5cc6819',
blockHash: null,
blockNumber: null,
data: '',
logIndex: null,
topics: [ '0xf341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb567' ],
transactionHash: '0x01ef3c048b18d9b09ea195b4ed94cf8dd5f3d857a1905ff886b152cfb1166f25',
transactionIndex: 0,
};
const logC: Web3.LogEntry = {
address: '0x1d271f8b174adef58f1587ce68f8f27271ac4ca5',
blockHash: null,
blockNumber: null,
data: '',
logIndex: null,
topics: [ '0xf341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb567' ],
transactionHash: '0x01ef3c048b18d9b09ea195b4ed94cf8dd5f3d857a1905ff886b152cfb1166f25',
transactionIndex: 0,
};
before(async () => {
web3 = web3Factory.create();
const pollingIntervalMs = 10;
web3Wrapper = new Web3Wrapper(web3.currentProvider);
eventWatcher = new EventWatcher(web3Wrapper, pollingIntervalMs);
});
afterEach(() => {
// clean up any stubs after the test has completed
_.each(stubs, s => s.restore());
stubs = [];
eventWatcher.unsubscribe();
});
it('correctly emits initial log events', (done: DoneCallback) => {
const logs: Web3.LogEntry[] = [logA, logB];
const expectedLogEvents = [
{
removed: false,
...logA,
},
{
removed: false,
...logB,
},
];
const getLogsStub = Sinon.stub(web3Wrapper, 'getLogsAsync');
getLogsStub.onCall(0).returns(logs);
stubs.push(getLogsStub);
const callback = (event: LogEvent) => {
const expectedLogEvent = expectedLogEvents.shift();
expect(event).to.be.deep.equal(expectedLogEvent);
if (_.isEmpty(expectedLogEvents)) {
done();
}
};
eventWatcher.subscribe(callback);
});
it('correctly computes the difference and emits only changes', (done: DoneCallback) => {
const initialLogs: Web3.LogEntry[] = [logA, logB];
const changedLogs: Web3.LogEntry[] = [logA, logC];
const expectedLogEvents = [
{
removed: false,
...logA,
},
{
removed: false,
...logB,
},
{
removed: true,
...logB,
},
{
removed: false,
...logC,
},
];
const getLogsStub = Sinon.stub(web3Wrapper, 'getLogsAsync');
getLogsStub.onCall(0).returns(initialLogs);
getLogsStub.onCall(1).returns(changedLogs);
stubs.push(getLogsStub);
const callback = (event: LogEvent) => {
const expectedLogEvent = expectedLogEvents.shift();
expect(event).to.be.deep.equal(expectedLogEvent);
if (_.isEmpty(expectedLogEvents)) {
done();
}
};
eventWatcher.subscribe(callback);
});
});

View File

@@ -0,0 +1,93 @@
import {BlockchainLifecycle} from '@0xproject/dev-utils';
import BigNumber from 'bignumber.js';
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 {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(constants.RPC_URL);
describe('ExchangeTransferSimulator', () => {
const web3 = web3Factory.create();
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[];
let coinbase: string;
let sender: string;
let recipient: string;
let exampleTokenAddress: string;
let exchangeTransferSimulator: ExchangeTransferSimulator;
let txHash: string;
before(async () => {
userAddresses = await zeroEx.getAvailableAddressesAsync();
[coinbase, sender, recipient] = userAddresses;
tokens = await zeroEx.tokenRegistry.getTokensAsync();
exampleTokenAddress = tokens[0].address;
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('#transferFromAsync', () => {
beforeEach(() => {
exchangeTransferSimulator = new ExchangeTransferSimulator(zeroEx.token, BlockParamLiteral.Latest);
});
it('throws if the user doesn\'t have enough allowance', async () => {
return expect(exchangeTransferSimulator.transferFromAsync(
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade,
)).to.be.rejectedWith(ExchangeContractErrs.InsufficientTakerAllowance);
});
it('throws if the user doesn\'t have enough balance', async () => {
txHash = await zeroEx.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount);
await zeroEx.awaitTransactionMinedAsync(txHash);
return expect(exchangeTransferSimulator.transferFromAsync(
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Maker, TransferType.Trade,
)).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance);
});
it('updates balances and proxyAllowance after transfer', async () => {
txHash = await zeroEx.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount);
await zeroEx.awaitTransactionMinedAsync(txHash);
txHash = await zeroEx.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount);
await zeroEx.awaitTransactionMinedAsync(txHash);
await exchangeTransferSimulator.transferFromAsync(
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade,
);
const store = (exchangeTransferSimulator as any)._store;
const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender);
const recipientBalance = await store.getBalanceAsync(exampleTokenAddress, recipient);
const senderProxyAllowance = await store.getProxyAllowanceAsync(exampleTokenAddress, sender);
expect(senderBalance).to.be.bignumber.equal(0);
expect(recipientBalance).to.be.bignumber.equal(transferAmount);
expect(senderProxyAllowance).to.be.bignumber.equal(0);
});
it('doesn\'t update proxyAllowance after transfer if unlimited', async () => {
txHash = await zeroEx.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount);
await zeroEx.awaitTransactionMinedAsync(txHash);
txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(exampleTokenAddress, sender);
await zeroEx.awaitTransactionMinedAsync(txHash);
await exchangeTransferSimulator.transferFromAsync(
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade,
);
const store = (exchangeTransferSimulator as any)._store;
const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender);
const recipientBalance = await store.getBalanceAsync(exampleTokenAddress, recipient);
const senderProxyAllowance = await store.getProxyAllowanceAsync(exampleTokenAddress, sender);
expect(senderBalance).to.be.bignumber.equal(0);
expect(recipientBalance).to.be.bignumber.equal(transferAmount);
expect(senderProxyAllowance).to.be.bignumber.equal(zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
});
});
});

View File

@@ -0,0 +1,831 @@
import {BlockchainLifecycle} from '@0xproject/dev-utils';
import BigNumber from 'bignumber.js';
import * as chai from 'chai';
import 'mocha';
import * as Web3 from 'web3';
import {
BlockRange,
DecodedLogEvent,
ExchangeContractErrs,
ExchangeEvents,
LogCancelContractEventArgs,
LogFillContractEventArgs,
OrderCancellationRequest,
OrderFillRequest,
SignedOrder,
Token,
ZeroEx,
} from '../src';
import {BlockParamLiteral, DoneCallback} from '../src/types';
import {chaiSetup} from './utils/chai_setup';
import {constants} from './utils/constants';
import {FillScenarios} from './utils/fill_scenarios';
import {TokenUtils} from './utils/token_utils';
import {web3Factory} from './utils/web3_factory';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL);
const NON_EXISTENT_ORDER_HASH = '0x79370342234e7acd6bbeac335bd3bb1d368383294b64b8160a00f4060e4d3777';
describe('ExchangeWrapper', () => {
let web3: Web3;
let zeroEx: ZeroEx;
let tokenUtils: TokenUtils;
let tokens: Token[];
let userAddresses: string[];
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, 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);
await fillScenarios.initTokenBalancesAsync();
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('fillOrKill order(s)', () => {
let makerTokenAddress: string;
let takerTokenAddress: string;
let coinbase: string;
let makerAddress: string;
let takerAddress: string;
let feeRecipient: string;
const takerTokenFillAmount = new BigNumber(5);
before(async () => {
[coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses;
tokens = await zeroEx.tokenRegistry.getTokensAsync();
const [makerToken, takerToken] = tokenUtils.getDummyTokens();
makerTokenAddress = makerToken.address;
takerTokenAddress = takerToken.address;
});
describe('#batchFillOrKillAsync', () => {
it('successfully batch fillOrKill', async () => {
const fillableAmount = new BigNumber(5);
const partialFillTakerAmount = new BigNumber(2);
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
const anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
const orderFillRequests = [
{
signedOrder,
takerTokenFillAmount: partialFillTakerAmount,
},
{
signedOrder: anotherSignedOrder,
takerTokenFillAmount: partialFillTakerAmount,
},
];
await zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress);
});
describe('order transaction options', () => {
let signedOrder: SignedOrder;
let orderFillRequests: OrderFillRequest[];
const fillableAmount = new BigNumber(5);
beforeEach(async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
orderFillRequests = [
{
signedOrder,
takerTokenFillAmount: new BigNumber(0),
},
];
});
it('should validate when orderTransactionOptions are not present', async () => {
return expect(zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress))
.to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
});
it('should validate when orderTransactionOptions specify to validate', async () => {
return expect(zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress, {
shouldValidate: true,
})).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
});
it('should not validate when orderTransactionOptions specify not to validate', async () => {
return expect(zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress, {
shouldValidate: false,
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
});
});
});
describe('#fillOrKillOrderAsync', () => {
let signedOrder: SignedOrder;
const fillableAmount = new BigNumber(5);
beforeEach(async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
});
describe('successful fills', () => {
it('should fill a valid order', async () => {
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress))
.to.be.bignumber.equal(fillableAmount);
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress))
.to.be.bignumber.equal(0);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress))
.to.be.bignumber.equal(0);
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress))
.to.be.bignumber.equal(fillableAmount);
await zeroEx.exchange.fillOrKillOrderAsync(signedOrder, takerTokenFillAmount, takerAddress);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress))
.to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount));
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress))
.to.be.bignumber.equal(takerTokenFillAmount);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress))
.to.be.bignumber.equal(takerTokenFillAmount);
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress))
.to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount));
});
it('should partially fill a valid order', async () => {
const partialFillAmount = new BigNumber(3);
await zeroEx.exchange.fillOrKillOrderAsync(signedOrder, partialFillAmount, takerAddress);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress))
.to.be.bignumber.equal(fillableAmount.minus(partialFillAmount));
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress))
.to.be.bignumber.equal(partialFillAmount);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress))
.to.be.bignumber.equal(partialFillAmount);
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress))
.to.be.bignumber.equal(fillableAmount.minus(partialFillAmount));
});
});
describe('order transaction options', () => {
const emptyFillableAmount = new BigNumber(0);
it('should validate when orderTransactionOptions are not present', async () => {
return expect(zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress))
.to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
});
it('should validate when orderTransactionOptions specify to validate', async () => {
return expect(zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress, {
shouldValidate: true,
})).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
});
it('should not validate when orderTransactionOptions specify not to validate', async () => {
return expect(zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress, {
shouldValidate: false,
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
});
});
});
});
describe('fill order(s)', () => {
let makerTokenAddress: string;
let takerTokenAddress: string;
let coinbase: string;
let makerAddress: string;
let takerAddress: string;
let feeRecipient: string;
const fillableAmount = new BigNumber(5);
const takerTokenFillAmount = new BigNumber(5);
const shouldThrowOnInsufficientBalanceOrAllowance = true;
before(async () => {
[coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses;
tokens = await zeroEx.tokenRegistry.getTokensAsync();
const [makerToken, takerToken] = tokenUtils.getDummyTokens();
makerTokenAddress = makerToken.address;
takerTokenAddress = takerToken.address;
});
describe('#fillOrderAsync', () => {
describe('successful fills', () => {
it('should fill a valid order', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress))
.to.be.bignumber.equal(fillableAmount);
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress))
.to.be.bignumber.equal(0);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress))
.to.be.bignumber.equal(0);
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress))
.to.be.bignumber.equal(fillableAmount);
const txHash = await zeroEx.exchange.fillOrderAsync(
signedOrder, takerTokenFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress);
await zeroEx.awaitTransactionMinedAsync(txHash);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress))
.to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount));
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress))
.to.be.bignumber.equal(takerTokenFillAmount);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress))
.to.be.bignumber.equal(takerTokenFillAmount);
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress))
.to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount));
});
it('should partially fill the valid order', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
const partialFillAmount = new BigNumber(3);
const txHash = await zeroEx.exchange.fillOrderAsync(
signedOrder, partialFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress);
await zeroEx.awaitTransactionMinedAsync(txHash);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress))
.to.be.bignumber.equal(fillableAmount.minus(partialFillAmount));
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress))
.to.be.bignumber.equal(partialFillAmount);
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress))
.to.be.bignumber.equal(partialFillAmount);
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress))
.to.be.bignumber.equal(fillableAmount.minus(partialFillAmount));
});
it('should fill the valid orders with fees', async () => {
const makerFee = new BigNumber(1);
const takerFee = new BigNumber(2);
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
makerTokenAddress, takerTokenAddress, makerFee, takerFee,
makerAddress, takerAddress, fillableAmount, feeRecipient,
);
const txHash = await zeroEx.exchange.fillOrderAsync(
signedOrder, takerTokenFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress);
await zeroEx.awaitTransactionMinedAsync(txHash);
expect(await zeroEx.token.getBalanceAsync(zrxTokenAddress, feeRecipient))
.to.be.bignumber.equal(makerFee.plus(takerFee));
});
});
describe('order transaction options', () => {
let signedOrder: SignedOrder;
const emptyFillTakerAmount = new BigNumber(0);
beforeEach(async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
});
it('should validate when orderTransactionOptions are not present', async () => {
return expect(zeroEx.exchange.fillOrderAsync(
signedOrder, emptyFillTakerAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
});
it('should validate when orderTransactionOptions specify to validate', async () => {
return expect(zeroEx.exchange.fillOrderAsync(
signedOrder, emptyFillTakerAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, {
shouldValidate: true,
})).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
});
it('should not validate when orderTransactionOptions specify not to validate', async () => {
return expect(zeroEx.exchange.fillOrderAsync(
signedOrder, emptyFillTakerAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, {
shouldValidate: false,
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
});
});
});
describe('#batchFillOrdersAsync', () => {
let signedOrder: SignedOrder;
let signedOrderHashHex: string;
let anotherSignedOrder: SignedOrder;
let anotherOrderHashHex: string;
let orderFillBatch: OrderFillRequest[];
beforeEach(async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
signedOrderHashHex = ZeroEx.getOrderHashHex(signedOrder);
anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder);
});
describe('successful batch fills', () => {
beforeEach(() => {
orderFillBatch = [
{
signedOrder,
takerTokenFillAmount,
},
{
signedOrder: anotherSignedOrder,
takerTokenFillAmount,
},
];
});
it('should throw if a batch is empty', async () => {
return expect(zeroEx.exchange.batchFillOrdersAsync(
[], shouldThrowOnInsufficientBalanceOrAllowance, takerAddress),
).to.be.rejectedWith(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
});
it('should successfully fill multiple orders', async () => {
const txHash = await zeroEx.exchange.batchFillOrdersAsync(
orderFillBatch, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress);
await zeroEx.awaitTransactionMinedAsync(txHash);
const filledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
const anotherFilledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(anotherOrderHashHex);
expect(filledAmount).to.be.bignumber.equal(takerTokenFillAmount);
expect(anotherFilledAmount).to.be.bignumber.equal(takerTokenFillAmount);
});
});
describe('order transaction options', () => {
beforeEach(async () => {
const emptyFillTakerAmount = new BigNumber(0);
orderFillBatch = [
{
signedOrder,
takerTokenFillAmount: emptyFillTakerAmount,
},
{
signedOrder: anotherSignedOrder,
takerTokenFillAmount: emptyFillTakerAmount,
},
];
});
it('should validate when orderTransactionOptions are not present', async () => {
return expect(zeroEx.exchange.batchFillOrdersAsync(
orderFillBatch, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress),
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
});
it('should validate when orderTransactionOptions specify to validate', async () => {
return expect(zeroEx.exchange.batchFillOrdersAsync(
orderFillBatch, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, {
shouldValidate: true,
})).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
});
it('should not validate when orderTransactionOptions specify not to validate', async () => {
return expect(zeroEx.exchange.batchFillOrdersAsync(
orderFillBatch, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, {
shouldValidate: false,
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
});
});
});
describe('#fillOrdersUpTo', () => {
let signedOrder: SignedOrder;
let signedOrderHashHex: string;
let anotherSignedOrder: SignedOrder;
let anotherOrderHashHex: string;
let signedOrders: SignedOrder[];
const fillUpToAmount = fillableAmount.plus(fillableAmount).minus(1);
beforeEach(async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
signedOrderHashHex = ZeroEx.getOrderHashHex(signedOrder);
anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder);
signedOrders = [signedOrder, anotherSignedOrder];
});
describe('successful batch fills', () => {
it('should throw if a batch is empty', async () => {
return expect(zeroEx.exchange.fillOrdersUpToAsync(
[], fillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress),
).to.be.rejectedWith(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
});
it('should successfully fill up to specified amount', async () => {
const txHash = await zeroEx.exchange.fillOrdersUpToAsync(
signedOrders, fillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
);
await zeroEx.awaitTransactionMinedAsync(txHash);
const filledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
const anotherFilledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(anotherOrderHashHex);
expect(filledAmount).to.be.bignumber.equal(fillableAmount);
const remainingFillAmount = fillableAmount.minus(1);
expect(anotherFilledAmount).to.be.bignumber.equal(remainingFillAmount);
});
});
describe('order transaction options', () => {
const emptyFillUpToAmount = new BigNumber(0);
it('should validate when orderTransactionOptions are not present', async () => {
return expect(zeroEx.exchange.fillOrdersUpToAsync(
signedOrders, emptyFillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
});
it('should validate when orderTransactionOptions specify to validate', async () => {
return expect(zeroEx.exchange.fillOrdersUpToAsync(
signedOrders, emptyFillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, {
shouldValidate: true,
})).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
});
it('should not validate when orderTransactionOptions specify not to validate', async () => {
return expect(zeroEx.exchange.fillOrdersUpToAsync(
signedOrders, emptyFillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, {
shouldValidate: false,
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
});
});
});
});
describe('cancel order(s)', () => {
let makerTokenAddress: string;
let takerTokenAddress: string;
let coinbase: string;
let makerAddress: string;
let takerAddress: string;
const fillableAmount = new BigNumber(5);
let signedOrder: SignedOrder;
let orderHashHex: string;
const cancelAmount = new BigNumber(3);
beforeEach(async () => {
[coinbase, makerAddress, takerAddress] = userAddresses;
const [makerToken, takerToken] = tokenUtils.getDummyTokens();
makerTokenAddress = makerToken.address;
takerTokenAddress = takerToken.address;
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
orderHashHex = ZeroEx.getOrderHashHex(signedOrder);
});
describe('#cancelOrderAsync', () => {
describe('successful cancels', () => {
it('should cancel an order', async () => {
const txHash = await zeroEx.exchange.cancelOrderAsync(signedOrder, cancelAmount);
await zeroEx.awaitTransactionMinedAsync(txHash);
const cancelledAmount = await zeroEx.exchange.getCancelledTakerAmountAsync(orderHashHex);
expect(cancelledAmount).to.be.bignumber.equal(cancelAmount);
});
});
describe('order transaction options', () => {
const emptyCancelTakerTokenAmount = new BigNumber(0);
it('should validate when orderTransactionOptions are not present', async () => {
return expect(zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount))
.to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
});
it('should validate when orderTransactionOptions specify to validate', async () => {
return expect(zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount, {
shouldValidate: true,
})).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
});
it('should not validate when orderTransactionOptions specify not to validate', async () => {
return expect(zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount, {
shouldValidate: false,
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
});
});
});
describe('#batchCancelOrdersAsync', () => {
let anotherSignedOrder: SignedOrder;
let anotherOrderHashHex: string;
let cancelBatch: OrderCancellationRequest[];
beforeEach(async () => {
anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder);
cancelBatch = [
{
order: signedOrder,
takerTokenCancelAmount: cancelAmount,
},
{
order: anotherSignedOrder,
takerTokenCancelAmount: cancelAmount,
},
];
});
describe('failed batch cancels', () => {
it('should throw when orders have different makers', async () => {
const signedOrderWithDifferentMaker = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, takerAddress, takerAddress, fillableAmount,
);
return expect(zeroEx.exchange.batchCancelOrdersAsync([
cancelBatch[0],
{
order: signedOrderWithDifferentMaker,
takerTokenCancelAmount: cancelAmount,
},
])).to.be.rejectedWith(ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed);
});
});
describe('successful batch cancels', () => {
it('should cancel a batch of orders', async () => {
await zeroEx.exchange.batchCancelOrdersAsync(cancelBatch);
const cancelledAmount = await zeroEx.exchange.getCancelledTakerAmountAsync(orderHashHex);
const anotherCancelledAmount = await zeroEx.exchange.getCancelledTakerAmountAsync(
anotherOrderHashHex,
);
expect(cancelledAmount).to.be.bignumber.equal(cancelAmount);
expect(anotherCancelledAmount).to.be.bignumber.equal(cancelAmount);
});
});
describe('order transaction options', () => {
beforeEach(async () => {
const emptyTakerTokenCancelAmount = new BigNumber(0);
cancelBatch = [
{
order: signedOrder,
takerTokenCancelAmount: emptyTakerTokenCancelAmount,
},
{
order: anotherSignedOrder,
takerTokenCancelAmount: emptyTakerTokenCancelAmount,
},
];
});
it('should validate when orderTransactionOptions are not present', async () => {
return expect(zeroEx.exchange.batchCancelOrdersAsync(cancelBatch))
.to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
});
it('should validate when orderTransactionOptions specify to validate', async () => {
return expect(zeroEx.exchange.batchCancelOrdersAsync(cancelBatch, {
shouldValidate: true,
})).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
});
it('should not validate when orderTransactionOptions specify not to validate', async () => {
return expect(zeroEx.exchange.batchCancelOrdersAsync(cancelBatch, {
shouldValidate: false,
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
});
});
});
});
describe('tests that require partially filled order', () => {
let makerTokenAddress: string;
let takerTokenAddress: string;
let takerAddress: string;
let fillableAmount: BigNumber;
let partialFillAmount: BigNumber;
let signedOrder: SignedOrder;
let orderHash: string;
before(() => {
takerAddress = userAddresses[1];
tokenUtils = new TokenUtils(tokens);
const [makerToken, takerToken] = tokenUtils.getDummyTokens();
makerTokenAddress = makerToken.address;
takerTokenAddress = takerToken.address;
});
beforeEach(async () => {
fillableAmount = new BigNumber(5);
partialFillAmount = new BigNumber(2);
signedOrder = await fillScenarios.createPartiallyFilledSignedOrderAsync(
makerTokenAddress, takerTokenAddress, takerAddress, fillableAmount, partialFillAmount,
);
orderHash = ZeroEx.getOrderHashHex(signedOrder);
});
describe('#getUnavailableTakerAmountAsync', () => {
it('should throw if passed an invalid orderHash', async () => {
const invalidOrderHashHex = '0x123';
return expect(zeroEx.exchange.getUnavailableTakerAmountAsync(invalidOrderHashHex)).to.be.rejected();
});
it('should return zero if passed a valid but non-existent orderHash', async () => {
const unavailableValueT = await zeroEx.exchange.getUnavailableTakerAmountAsync(NON_EXISTENT_ORDER_HASH);
expect(unavailableValueT).to.be.bignumber.equal(0);
});
it('should return the unavailableValueT for a valid and partially filled orderHash', async () => {
const unavailableValueT = await zeroEx.exchange.getUnavailableTakerAmountAsync(orderHash);
expect(unavailableValueT).to.be.bignumber.equal(partialFillAmount);
});
});
describe('#getFilledTakerAmountAsync', () => {
it('should throw if passed an invalid orderHash', async () => {
const invalidOrderHashHex = '0x123';
return expect(zeroEx.exchange.getFilledTakerAmountAsync(invalidOrderHashHex)).to.be.rejected();
});
it('should return zero if passed a valid but non-existent orderHash', async () => {
const filledValueT = await zeroEx.exchange.getFilledTakerAmountAsync(NON_EXISTENT_ORDER_HASH,
);
expect(filledValueT).to.be.bignumber.equal(0);
});
it('should return the filledValueT for a valid and partially filled orderHash', async () => {
const filledValueT = await zeroEx.exchange.getFilledTakerAmountAsync(orderHash);
expect(filledValueT).to.be.bignumber.equal(partialFillAmount);
});
});
describe('#getCancelledTakerAmountAsync', () => {
it('should throw if passed an invalid orderHash', async () => {
const invalidOrderHashHex = '0x123';
return expect(zeroEx.exchange.getCancelledTakerAmountAsync(invalidOrderHashHex)).to.be.rejected();
});
it('should return zero if passed a valid but non-existent orderHash', async () => {
const cancelledValueT = await zeroEx.exchange.getCancelledTakerAmountAsync(NON_EXISTENT_ORDER_HASH);
expect(cancelledValueT).to.be.bignumber.equal(0);
});
it('should return the cancelledValueT for a valid and partially filled orderHash', async () => {
const cancelledValueT = await zeroEx.exchange.getCancelledTakerAmountAsync(orderHash);
expect(cancelledValueT).to.be.bignumber.equal(0);
});
it('should return the cancelledValueT for a valid and cancelled orderHash', async () => {
const cancelAmount = fillableAmount.minus(partialFillAmount);
await zeroEx.exchange.cancelOrderAsync(signedOrder, cancelAmount);
const cancelledValueT = await zeroEx.exchange.getCancelledTakerAmountAsync(orderHash);
expect(cancelledValueT).to.be.bignumber.equal(cancelAmount);
});
});
});
describe('#subscribe', () => {
const indexFilterValues = {};
const shouldThrowOnInsufficientBalanceOrAllowance = true;
let makerTokenAddress: string;
let takerTokenAddress: string;
let coinbase: string;
let takerAddress: string;
let makerAddress: string;
let fillableAmount: BigNumber;
let signedOrder: SignedOrder;
const takerTokenFillAmountInBaseUnits = new BigNumber(1);
const cancelTakerAmountInBaseUnits = new BigNumber(1);
before(() => {
[coinbase, makerAddress, takerAddress] = userAddresses;
const [makerToken, takerToken] = tokenUtils.getDummyTokens();
makerTokenAddress = makerToken.address;
takerTokenAddress = takerToken.address;
});
beforeEach(async () => {
fillableAmount = new BigNumber(5);
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
});
afterEach(async () => {
zeroEx.exchange.unsubscribeAll();
});
// Hack: Mocha does not allow a test to be both async and have a `done` callback
// Since we need to await the receipt of the event in the `subscribe` callback,
// we do need both. A hack is to make the top-level a sync fn w/ a done callback and then
// wrap the rest of the test in an async block
// Source: https://github.com/mochajs/mocha/issues/2407
it('Should receive the LogFill event when an order is filled', (done: DoneCallback) => {
(async () => {
const callback = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogFill);
done();
};
zeroEx.exchange.subscribe(
ExchangeEvents.LogFill, indexFilterValues, callback,
);
await zeroEx.exchange.fillOrderAsync(
signedOrder, takerTokenFillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
);
})().catch(done);
});
it('Should receive the LogCancel event when an order is cancelled', (done: DoneCallback) => {
(async () => {
const callback = (err: Error, logEvent: DecodedLogEvent<LogCancelContractEventArgs>) => {
expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogCancel);
done();
};
zeroEx.exchange.subscribe(
ExchangeEvents.LogCancel, indexFilterValues, callback,
);
await zeroEx.exchange.cancelOrderAsync(signedOrder, cancelTakerAmountInBaseUnits);
})().catch(done);
});
it('Outstanding subscriptions are cancelled when zeroEx.setProvider called', (done: DoneCallback) => {
(async () => {
const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
done(new Error('Expected this subscription to have been cancelled'));
};
zeroEx.exchange.subscribe(
ExchangeEvents.LogFill, indexFilterValues, callbackNeverToBeCalled,
);
const newProvider = web3Factory.getRpcProvider();
zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID);
const callback = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogFill);
done();
};
zeroEx.exchange.subscribe(
ExchangeEvents.LogFill, indexFilterValues, callback,
);
await zeroEx.exchange.fillOrderAsync(
signedOrder, takerTokenFillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
);
})().catch(done);
});
it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => {
(async () => {
const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
done(new Error('Expected this subscription to have been cancelled'));
};
const subscriptionToken = zeroEx.exchange.subscribe(
ExchangeEvents.LogFill, indexFilterValues, callbackNeverToBeCalled,
);
zeroEx.exchange.unsubscribe(subscriptionToken);
await zeroEx.exchange.fillOrderAsync(
signedOrder, takerTokenFillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
);
done();
})().catch(done);
});
});
describe('#getOrderHashHexUsingContractCallAsync', () => {
let makerTokenAddress: string;
let takerTokenAddress: string;
let makerAddress: string;
let takerAddress: string;
const fillableAmount = new BigNumber(5);
before(async () => {
[, makerAddress, takerAddress] = userAddresses;
const [makerToken, takerToken] = tokenUtils.getDummyTokens();
makerTokenAddress = makerToken.address;
takerTokenAddress = takerToken.address;
});
it('get\'s the same hash as the local function', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
const orderHashFromContract = await (zeroEx.exchange as any)
._getOrderHashHexUsingContractCallAsync(signedOrder);
expect(orderHash).to.equal(orderHashFromContract);
});
});
describe('#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);
});
});
describe('#getLogsAsync', () => {
let makerTokenAddress: string;
let takerTokenAddress: string;
let makerAddress: string;
let takerAddress: string;
const fillableAmount = new BigNumber(5);
const shouldThrowOnInsufficientBalanceOrAllowance = true;
const blockRange: BlockRange = {
fromBlock: 0,
toBlock: BlockParamLiteral.Latest,
};
let txHash: string;
before(async () => {
[, makerAddress, takerAddress] = userAddresses;
const [makerToken, takerToken] = tokenUtils.getDummyTokens();
makerTokenAddress = makerToken.address;
takerTokenAddress = takerToken.address;
});
it('should get logs with decoded args emitted by LogFill', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
txHash = await zeroEx.exchange.fillOrderAsync(
signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
);
await zeroEx.awaitTransactionMinedAsync(txHash);
const eventName = ExchangeEvents.LogFill;
const indexFilterValues = {};
const logs = await zeroEx.exchange.getLogsAsync(eventName, blockRange, indexFilterValues);
expect(logs).to.have.length(1);
expect(logs[0].event).to.be.equal(eventName);
});
it('should only get the logs with the correct event name', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
txHash = await zeroEx.exchange.fillOrderAsync(
signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
);
await zeroEx.awaitTransactionMinedAsync(txHash);
const differentEventName = ExchangeEvents.LogCancel;
const indexFilterValues = {};
const logs = await zeroEx.exchange.getLogsAsync(differentEventName, blockRange, indexFilterValues);
expect(logs).to.have.length(0);
});
it('should only get the logs with the correct indexed fields', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
txHash = await zeroEx.exchange.fillOrderAsync(
signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
);
await zeroEx.awaitTransactionMinedAsync(txHash);
const differentMakerAddress = userAddresses[2];
const anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, differentMakerAddress, takerAddress, fillableAmount,
);
txHash = await zeroEx.exchange.fillOrderAsync(
anotherSignedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
);
await zeroEx.awaitTransactionMinedAsync(txHash);
const eventName = ExchangeEvents.LogFill;
const indexFilterValues = {
maker: differentMakerAddress,
};
const logs = await zeroEx.exchange.getLogsAsync<LogFillContractEventArgs>(
eventName, blockRange, indexFilterValues,
);
expect(logs).to.have.length(1);
const args = logs[0].args;
expect(args.maker).to.be.equal(differentMakerAddress);
});
});
}); // tslint:disable:max-file-line-count

View File

@@ -0,0 +1,144 @@
import {BlockchainLifecycle} from '@0xproject/dev-utils';
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 {chaiSetup} from './utils/chai_setup';
import {constants as testConstants} 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';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(testConstants.RPC_URL);
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.getDummyTokens();
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

@@ -0,0 +1,463 @@
import {BlockchainLifecycle} from '@0xproject/dev-utils';
import BigNumber from 'bignumber.js';
import * as chai from 'chai';
import * as _ from 'lodash';
import 'mocha';
import * as Web3 from 'web3';
import {
ExchangeContractErrs,
OrderState,
OrderStateInvalid,
OrderStateValid,
SignedOrder,
Token,
ZeroEx,
ZeroExError,
} from '../src';
import {DoneCallback} from '../src/types';
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;
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL);
describe('OrderStateWatcher', () => {
let web3: Web3;
let zeroEx: ZeroEx;
let tokens: Token[];
let tokenUtils: TokenUtils;
let fillScenarios: FillScenarios;
let userAddresses: string[];
let zrxTokenAddress: string;
let exchangeContractAddress: string;
let makerToken: Token;
let takerToken: Token;
let maker: string;
let taker: string;
let signedOrder: SignedOrder;
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, config);
exchangeContractAddress = zeroEx.exchange.getContractAddress();
userAddresses = await zeroEx.getAvailableAddressesAsync();
[, maker, taker] = userAddresses;
tokens = await zeroEx.tokenRegistry.getTokensAsync();
tokenUtils = new TokenUtils(tokens);
zrxTokenAddress = tokenUtils.getProtocolTokenOrThrow().address;
fillScenarios = new FillScenarios(zeroEx, userAddresses, tokens, zrxTokenAddress, exchangeContractAddress);
await fillScenarios.initTokenBalancesAsync();
[makerToken, takerToken] = tokenUtils.getDummyTokens();
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('#removeOrder', async () => {
it('should successfully remove existing order', async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerToken.address, takerToken.address, maker, taker, fillableAmount,
);
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
zeroEx.orderStateWatcher.addOrder(signedOrder);
expect((zeroEx.orderStateWatcher as any)._orderByOrderHash).to.include({
[orderHash]: signedOrder,
});
let dependentOrderHashes = (zeroEx.orderStateWatcher as any)._dependentOrderHashes;
expect(dependentOrderHashes[signedOrder.maker][signedOrder.makerTokenAddress]).to.have.keys(orderHash);
zeroEx.orderStateWatcher.removeOrder(orderHash);
expect((zeroEx.orderStateWatcher as any)._orderByOrderHash).to.not.include({
[orderHash]: signedOrder,
});
dependentOrderHashes = (zeroEx.orderStateWatcher as any)._dependentOrderHashes;
expect(dependentOrderHashes[signedOrder.maker]).to.be.undefined();
});
it('should no-op when removing a non-existing order', async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerToken.address, takerToken.address, maker, taker, fillableAmount,
);
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
const nonExistentOrderHash = `0x${orderHash.substr(2).split('').reverse().join('')}`;
zeroEx.orderStateWatcher.removeOrder(nonExistentOrderHash);
});
});
describe('#subscribe', async () => {
afterEach(async () => {
zeroEx.orderStateWatcher.unsubscribe();
});
it('should fail when trying to subscribe twice', async () => {
zeroEx.orderStateWatcher.subscribe(_.noop);
expect(() => zeroEx.orderStateWatcher.subscribe(_.noop))
.to.throw(ZeroExError.SubscriptionAlreadyPresent);
});
});
describe('tests with cleanup', async () => {
afterEach(async () => {
zeroEx.orderStateWatcher.unsubscribe();
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
zeroEx.orderStateWatcher.removeOrder(orderHash);
});
it('should emit orderStateInvalid when maker allowance set to 0 for watched order', (done: DoneCallback) => {
(async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerToken.address, takerToken.address, maker, taker, fillableAmount,
);
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.InsufficientMakerAllowance);
done();
});
zeroEx.orderStateWatcher.subscribe(callback);
await zeroEx.token.setProxyAllowanceAsync(makerToken.address, maker, new BigNumber(0));
})().catch(done);
});
it('should not emit an orderState event when irrelevant Transfer event received', (done: DoneCallback) => {
(async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerToken.address, takerToken.address, maker, taker, fillableAmount,
);
zeroEx.orderStateWatcher.addOrder(signedOrder);
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
throw new Error('OrderState callback fired for irrelevant order');
});
zeroEx.orderStateWatcher.subscribe(callback);
const notTheMaker = userAddresses[0];
const anyRecipient = taker;
const transferAmount = new BigNumber(2);
await zeroEx.token.transferAsync(makerToken.address, notTheMaker, anyRecipient, transferAmount);
setTimeout(() => {
done();
}, TIMEOUT_MS);
})().catch(done);
});
it('should emit orderStateInvalid when maker moves balance backing watched order', (done: DoneCallback) => {
(async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerToken.address, takerToken.address, maker, taker, fillableAmount,
);
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.InsufficientMakerBalance);
done();
});
zeroEx.orderStateWatcher.subscribe(callback);
const anyRecipient = taker;
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
await zeroEx.token.transferAsync(makerToken.address, maker, anyRecipient, makerBalance);
})().catch(done);
});
it('should emit orderStateInvalid when watched order fully filled', (done: DoneCallback) => {
(async () => {
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.OrderRemainingFillAmountZero);
done();
});
zeroEx.orderStateWatcher.subscribe(callback);
const shouldThrowOnInsufficientBalanceOrAllowance = true;
await zeroEx.exchange.fillOrderAsync(
signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, taker,
);
})().catch(done);
});
it('should emit orderStateValid when watched order partially filled', (done: DoneCallback) => {
(async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerToken.address, takerToken.address, maker, taker, fillableAmount,
);
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
const fillAmountInBaseUnits = new BigNumber(2);
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;
const remainingMakerBalance = makerBalance.sub(fillAmountInBaseUnits);
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);
done();
});
zeroEx.orderStateWatcher.subscribe(callback);
const shouldThrowOnInsufficientBalanceOrAllowance = true;
await zeroEx.exchange.fillOrderAsync(
signedOrder, fillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance, taker,
);
})().catch(done);
});
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 callback = reportCallbackErrors(done)((orderState: OrderState) => {
done();
});
zeroEx.orderStateWatcher.addOrder(signedOrder);
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 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 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);
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 remainingAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals);
const transferAmount = makerBalance.sub(remainingAmount);
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(
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 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 remainingFeeAmount = ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals);
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);
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 () => {
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.OrderRemainingFillAmountZero);
done();
});
zeroEx.orderStateWatcher.subscribe(callback);
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(
makerToken.address, takerToken.address, maker, taker, fillableAmount,
);
const cancelAmountInBaseUnits = new BigNumber(2);
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.cancelledTakerTokenAmount).to.be.bignumber.equal(cancelAmountInBaseUnits);
done();
});
zeroEx.orderStateWatcher.subscribe(callback);
await zeroEx.exchange.cancelOrderAsync(signedOrder, cancelAmountInBaseUnits);
})().catch(done);
});
});
}); // tslint:disable:max-file-line-count

View File

@@ -0,0 +1,328 @@
import {BlockchainLifecycle} from '@0xproject/dev-utils';
import BigNumber from 'bignumber.js';
import * as chai from 'chai';
import * as Sinon from 'sinon';
import * as Web3 from 'web3';
import {ExchangeContractErrs, SignedOrder, Token, ZeroEx, ZeroExError} from '../src';
import {BlockParamLiteral, TradeSide, TransferType} from '../src/types';
import {ExchangeTransferSimulator} from '../src/utils/exchange_transfer_simulator';
import {OrderValidationUtils} from '../src/utils/order_validation_utils';
import {chaiSetup} from './utils/chai_setup';
import {constants} from './utils/constants';
import {FillScenarios} from './utils/fill_scenarios';
import {TokenUtils} from './utils/token_utils';
import {web3Factory} from './utils/web3_factory';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL);
describe('OrderValidation', () => {
let web3: Web3;
let zeroEx: ZeroEx;
let userAddresses: string[];
let tokens: Token[];
let tokenUtils: TokenUtils;
let exchangeContractAddress: string;
let zrxTokenAddress: string;
let fillScenarios: FillScenarios;
let makerTokenAddress: string;
let takerTokenAddress: string;
let coinbase: string;
let makerAddress: string;
let takerAddress: string;
let feeRecipient: string;
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, config);
exchangeContractAddress = zeroEx.exchange.getContractAddress();
userAddresses = await zeroEx.getAvailableAddressesAsync();
[coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses;
tokens = await zeroEx.tokenRegistry.getTokensAsync();
tokenUtils = new TokenUtils(tokens);
zrxTokenAddress = tokenUtils.getProtocolTokenOrThrow().address;
fillScenarios = new FillScenarios(zeroEx, userAddresses, tokens, zrxTokenAddress, exchangeContractAddress);
const [makerToken, takerToken] = tokenUtils.getDummyTokens();
makerTokenAddress = makerToken.address;
takerTokenAddress = takerToken.address;
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('validateOrderFillableOrThrowAsync', () => {
it('should succeed if the order is fillable', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
await zeroEx.exchange.validateOrderFillableOrThrowAsync(
signedOrder,
);
});
it('should succeed if the order is asymmetric and fillable', async () => {
const makerFillableAmount = fillableAmount;
const takerFillableAmount = fillableAmount.minus(4);
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
makerFillableAmount, takerFillableAmount,
);
await zeroEx.exchange.validateOrderFillableOrThrowAsync(
signedOrder,
);
});
it('should throw when the order is fully filled or cancelled', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
return expect(zeroEx.exchange.validateOrderFillableOrThrowAsync(
signedOrder,
)).to.be.rejectedWith(ExchangeContractErrs.OrderRemainingFillAmountZero);
});
it('should throw when order is expired', async () => {
const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
fillableAmount, expirationInPast,
);
return expect(zeroEx.exchange.validateOrderFillableOrThrowAsync(
signedOrder,
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillExpired);
});
});
describe('validateFillOrderAndThrowIfInvalidAsync', () => {
it('should throw when the fill amount is zero', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
const zeroFillAmount = new BigNumber(0);
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
signedOrder, zeroFillAmount, takerAddress,
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
});
it('should throw when the signature is invalid', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
// 27 <--> 28
signedOrder.ecSignature.v = (28 - signedOrder.ecSignature.v) + 27;
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
signedOrder, fillableAmount, takerAddress,
)).to.be.rejectedWith(ZeroExError.InvalidSignature);
});
it('should throw when the order is fully filled or cancelled', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
signedOrder, fillableAmount, takerAddress,
)).to.be.rejectedWith(ExchangeContractErrs.OrderRemainingFillAmountZero);
});
it('should throw when sender is not a taker', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
const nonTakerAddress = userAddresses[6];
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
signedOrder, fillTakerAmount, nonTakerAddress,
)).to.be.rejectedWith(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker);
});
it('should throw when order is expired', async () => {
const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
fillableAmount, expirationInPast,
);
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
signedOrder, fillTakerAmount, takerAddress,
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillExpired);
});
it('should throw when there a rounding error would have occurred', async () => {
const makerAmount = new BigNumber(3);
const takerAmount = new BigNumber(5);
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
makerAmount, takerAmount,
);
const fillTakerAmountThatCausesRoundingError = new BigNumber(3);
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
signedOrder, fillTakerAmountThatCausesRoundingError, takerAddress,
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillRoundingError);
});
});
describe('#validateFillOrKillOrderAndThrowIfInvalidAsync', () => {
it('should throw if remaining fillAmount is less then the desired fillAmount', async () => {
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
const tooLargeFillAmount = new BigNumber(7);
const fillAmountDifference = tooLargeFillAmount.minus(fillableAmount);
await zeroEx.token.transferAsync(takerTokenAddress, coinbase, takerAddress, fillAmountDifference);
await zeroEx.token.setProxyAllowanceAsync(takerTokenAddress, takerAddress, tooLargeFillAmount);
await zeroEx.token.transferAsync(makerTokenAddress, coinbase, makerAddress, fillAmountDifference);
await zeroEx.token.setProxyAllowanceAsync(makerTokenAddress, makerAddress, tooLargeFillAmount);
return expect(zeroEx.exchange.validateFillOrKillOrderThrowIfInvalidAsync(
signedOrder, tooLargeFillAmount, takerAddress,
)).to.be.rejectedWith(ExchangeContractErrs.InsufficientRemainingFillAmount);
});
});
describe('validateCancelOrderAndThrowIfInvalidAsync', () => {
let signedOrder: SignedOrder;
const cancelAmount = new BigNumber(3);
beforeEach(async () => {
[coinbase, makerAddress, takerAddress] = userAddresses;
const [makerToken, takerToken] = tokenUtils.getDummyTokens();
makerTokenAddress = makerToken.address;
takerTokenAddress = takerToken.address;
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
);
});
it('should throw when cancel amount is zero', async () => {
const zeroCancelAmount = new BigNumber(0);
return expect(zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, zeroCancelAmount))
.to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
});
it('should throw when order is expired', async () => {
const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
const expiredSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
fillableAmount, expirationInPast,
);
return expect(zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(expiredSignedOrder, cancelAmount))
.to.be.rejectedWith(ExchangeContractErrs.OrderCancelExpired);
});
it('should throw when order is already cancelled or filled', async () => {
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
return expect(zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, fillableAmount))
.to.be.rejectedWith(ExchangeContractErrs.OrderAlreadyCancelledOrFilled);
});
});
describe('#validateFillOrderBalancesAllowancesThrowIfInvalidAsync', () => {
let exchangeTransferSimulator: ExchangeTransferSimulator;
let transferFromAsync: Sinon.SinonSpy;
const bigNumberMatch = (expected: BigNumber) => {
return Sinon.match((value: BigNumber) => value.eq(expected));
};
beforeEach('create exchangeTransferSimulator', async () => {
exchangeTransferSimulator = new ExchangeTransferSimulator(zeroEx.token, BlockParamLiteral.Latest);
transferFromAsync = Sinon.spy();
exchangeTransferSimulator.transferFromAsync = transferFromAsync as any;
});
it('should call exchangeTransferSimulator.transferFrom in a correct order', async () => {
const makerFee = new BigNumber(2);
const takerFee = new BigNumber(2);
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
makerTokenAddress, takerTokenAddress, makerFee, takerFee,
makerAddress, takerAddress, fillableAmount, feeRecipient,
);
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
exchangeTransferSimulator, signedOrder, fillableAmount, takerAddress, zrxTokenAddress,
);
expect(transferFromAsync.callCount).to.be.equal(4);
expect(
transferFromAsync.getCall(0).calledWith(
makerTokenAddress, makerAddress, takerAddress, bigNumberMatch(fillableAmount),
TradeSide.Maker, TransferType.Trade,
),
).to.be.true();
expect(
transferFromAsync.getCall(1).calledWith(
takerTokenAddress, takerAddress, makerAddress, bigNumberMatch(fillableAmount),
TradeSide.Taker, TransferType.Trade,
),
).to.be.true();
expect(
transferFromAsync.getCall(2).calledWith(
zrxTokenAddress, makerAddress, feeRecipient, bigNumberMatch(makerFee),
TradeSide.Maker, TransferType.Fee,
),
).to.be.true();
expect(
transferFromAsync.getCall(3).calledWith(
zrxTokenAddress, takerAddress, feeRecipient, bigNumberMatch(takerFee),
TradeSide.Taker, TransferType.Fee,
),
).to.be.true();
});
it('should call exchangeTransferSimulator.transferFrom with correct values for an open order', async () => {
const makerFee = new BigNumber(2);
const takerFee = new BigNumber(2);
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
makerTokenAddress, takerTokenAddress, makerFee, takerFee,
makerAddress, ZeroEx.NULL_ADDRESS, fillableAmount, feeRecipient,
);
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
exchangeTransferSimulator, signedOrder, fillableAmount, takerAddress, zrxTokenAddress,
);
expect(transferFromAsync.callCount).to.be.equal(4);
expect(
transferFromAsync.getCall(0).calledWith(
makerTokenAddress, makerAddress, takerAddress, bigNumberMatch(fillableAmount),
TradeSide.Maker, TransferType.Trade,
),
).to.be.true();
expect(
transferFromAsync.getCall(1).calledWith(
takerTokenAddress, takerAddress, makerAddress, bigNumberMatch(fillableAmount),
TradeSide.Taker, TransferType.Trade,
),
).to.be.true();
expect(
transferFromAsync.getCall(2).calledWith(
zrxTokenAddress, makerAddress, feeRecipient, bigNumberMatch(makerFee),
TradeSide.Maker, TransferType.Fee,
),
).to.be.true();
expect(
transferFromAsync.getCall(3).calledWith(
zrxTokenAddress, takerAddress, feeRecipient, bigNumberMatch(takerFee),
TradeSide.Taker, TransferType.Fee,
),
).to.be.true();
});
it('should correctly round the fillMakerTokenAmount', async () => {
const makerTokenAmount = new BigNumber(3);
const takerTokenAmount = new BigNumber(1);
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, makerTokenAmount, takerTokenAmount,
);
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
exchangeTransferSimulator, signedOrder, takerTokenAmount, takerAddress, zrxTokenAddress,
);
expect(transferFromAsync.callCount).to.be.equal(4);
const makerFillAmount = transferFromAsync.getCall(0).args[3];
expect(makerFillAmount).to.be.bignumber.equal(makerTokenAmount);
});
it('should correctly round the makerFeeAmount', async () => {
const makerFee = new BigNumber(2);
const takerFee = new BigNumber(4);
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress,
fillableAmount, ZeroEx.NULL_ADDRESS,
);
const fillTakerTokenAmount = fillableAmount.div(2).round(0);
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
exchangeTransferSimulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress,
);
const makerPartialFee = makerFee.div(2);
const takerPartialFee = takerFee.div(2);
expect(transferFromAsync.callCount).to.be.equal(4);
const partialMakerFee = transferFromAsync.getCall(2).args[3];
expect(partialMakerFee).to.be.bignumber.equal(makerPartialFee);
const partialTakerFee = transferFromAsync.getCall(3).args[3];
expect(partialTakerFee).to.be.bignumber.equal(takerPartialFee);
});
});
});

View File

@@ -0,0 +1,177 @@
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';
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

@@ -0,0 +1,117 @@
import {BlockchainLifecycle} from '@0xproject/dev-utils';
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 {
ApprovalContractEventArgs,
DecodedLogEvent,
Token,
TokenEvents,
ZeroEx,
} from '../src';
import {DoneCallback} from '../src/types';
import {chaiSetup} from './utils/chai_setup';
import {constants} from './utils/constants';
import {reportCallbackErrors} from './utils/report_callback_errors';
import {web3Factory} from './utils/web3_factory';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL);
describe('SubscriptionTest', () => {
let web3: Web3;
let zeroEx: ZeroEx;
let userAddresses: string[];
let tokens: Token[];
let coinbase: string;
let addressWithoutFunds: string;
const config = {
networkId: constants.TESTRPC_NETWORK_ID,
};
before(async () => {
web3 = web3Factory.create();
zeroEx = new ZeroEx(web3.currentProvider, config);
userAddresses = await zeroEx.getAvailableAddressesAsync();
tokens = await zeroEx.tokenRegistry.getTokensAsync();
coinbase = userAddresses[0];
addressWithoutFunds = userAddresses[1];
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('#subscribe', () => {
const indexFilterValues = {};
let tokenAddress: string;
const allowanceAmount = new BigNumber(42);
let stubs: Sinon.SinonStub[] = [];
before(() => {
const token = tokens[0];
tokenAddress = token.address;
});
afterEach(() => {
zeroEx.token.unsubscribeAll();
_.each(stubs, s => s.restore());
stubs = [];
});
it('Should receive the Error when an error occurs while fetching the block', (done: DoneCallback) => {
(async () => {
const errMsg = 'Error fetching block';
const callback = reportCallbackErrors(done)(
(err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
expect(err.message).to.be.equal(errMsg);
expect(logEvent).to.be.undefined();
done();
},
);
stubs = [
Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync')
.throws(new Error(errMsg)),
];
zeroEx.token.subscribe(
tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
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;
zeroEx.token.subscribe(
tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
stubs = [
Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync')
.throws(new Error('JSON RPC error')),
];
zeroEx.token.unsubscribeAll();
done();
})().catch(done);
});
});
});

View File

@@ -0,0 +1,129 @@
import {BlockchainLifecycle} from '@0xproject/dev-utils';
import {schemas, SchemaValidator} from '@0xproject/json-schemas';
import * as chai from 'chai';
import * as _ from 'lodash';
import 'mocha';
import {Token, ZeroEx} from '../src';
import {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(constants.RPC_URL);
const TOKEN_REGISTRY_SIZE_AFTER_MIGRATION = 7;
describe('TokenRegistryWrapper', () => {
let zeroEx: ZeroEx;
let tokens: Token[];
const tokenAddressBySymbol: {[symbol: string]: string} = {};
const tokenAddressByName: {[symbol: string]: string} = {};
const tokenBySymbol: {[symbol: string]: Token} = {};
const tokenByName: {[symbol: string]: Token} = {};
const registeredSymbol = 'ZRX';
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, config);
tokens = await zeroEx.tokenRegistry.getTokensAsync();
_.map(tokens, token => {
tokenAddressBySymbol[token.symbol] = token.address;
tokenAddressByName[token.name] = token.address;
tokenBySymbol[token.symbol] = token;
tokenByName[token.name] = token;
});
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('#getTokensAsync', () => {
it('should return all the tokens added to the tokenRegistry during the migration', async () => {
expect(tokens).to.have.lengthOf(TOKEN_REGISTRY_SIZE_AFTER_MIGRATION);
const schemaValidator = new SchemaValidator();
_.each(tokens, token => {
const validationResult = schemaValidator.validate(token, schemas.tokenSchema);
expect(validationResult.errors).to.have.lengthOf(0);
});
});
});
describe('#getTokenAddressesAsync', () => {
it('should return all the token addresses added to the tokenRegistry during the migration', async () => {
const tokenAddresses = await zeroEx.tokenRegistry.getTokenAddressesAsync();
expect(tokenAddresses).to.have.lengthOf(TOKEN_REGISTRY_SIZE_AFTER_MIGRATION);
const schemaValidator = new SchemaValidator();
_.each(tokenAddresses, tokenAddress => {
const validationResult = schemaValidator.validate(tokenAddress, schemas.addressSchema);
expect(validationResult.errors).to.have.lengthOf(0);
expect(tokenAddress).to.not.be.equal(ZeroEx.NULL_ADDRESS);
});
});
});
describe('#getTokenAddressBySymbol', () => {
it('should return correct address for a token in the registry', async () => {
const tokenAddress = await zeroEx.tokenRegistry.getTokenAddressBySymbolIfExistsAsync(registeredSymbol);
expect(tokenAddress).to.be.equal(tokenAddressBySymbol[registeredSymbol]);
});
it('should return undefined for a token out of registry', async () => {
const tokenAddress = await zeroEx.tokenRegistry.getTokenAddressBySymbolIfExistsAsync(unregisteredSymbol);
expect(tokenAddress).to.be.undefined();
});
});
describe('#getTokenAddressByName', () => {
it('should return correct address for a token in the registry', async () => {
const tokenAddress = await zeroEx.tokenRegistry.getTokenAddressByNameIfExistsAsync(registeredName);
expect(tokenAddress).to.be.equal(tokenAddressByName[registeredName]);
});
it('should return undefined for a token out of registry', async () => {
const tokenAddress = await zeroEx.tokenRegistry.getTokenAddressByNameIfExistsAsync(unregisteredName);
expect(tokenAddress).to.be.undefined();
});
});
describe('#getTokenBySymbol', () => {
it('should return correct token for a token in the registry', async () => {
const token = await zeroEx.tokenRegistry.getTokenBySymbolIfExistsAsync(registeredSymbol);
expect(token).to.be.deep.equal(tokenBySymbol[registeredSymbol]);
});
it('should return undefined for a token out of registry', async () => {
const token = await zeroEx.tokenRegistry.getTokenBySymbolIfExistsAsync(unregisteredSymbol);
expect(token).to.be.undefined();
});
});
describe('#getTokenByName', () => {
it('should return correct token for a token in the registry', async () => {
const token = await zeroEx.tokenRegistry.getTokenByNameIfExistsAsync(registeredName);
expect(token).to.be.deep.equal(tokenByName[registeredName]);
});
it('should return undefined for a token out of registry', async () => {
const token = await zeroEx.tokenRegistry.getTokenByNameIfExistsAsync(unregisteredName);
expect(token).to.be.undefined();
});
});
describe('#getTokenIfExistsAsync', () => {
it('should return the token added to the tokenRegistry during the migration', async () => {
const aToken = tokens[0];
const token = await zeroEx.tokenRegistry.getTokenIfExistsAsync(aToken.address);
const schemaValidator = new SchemaValidator();
const validationResult = schemaValidator.validate(token, schemas.tokenSchema);
expect(validationResult.errors).to.have.lengthOf(0);
});
it('should return return undefined when passed a token address not in the tokenRegistry', async () => {
const unregisteredTokenAddress = '0x5409ed021d9299bf6814279a6a1411a7e866a631';
const tokenIfExists = await zeroEx.tokenRegistry.getTokenIfExistsAsync(unregisteredTokenAddress);
expect(tokenIfExists).to.be.undefined();
});
});
});

View File

@@ -0,0 +1,36 @@
import * as chai from 'chai';
import {ZeroEx} from '../src';
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, config);
});
describe('#isAuthorizedAsync', () => {
it('should return false if the address is not authorized', async () => {
const isAuthorized = await zeroEx.proxy.isAuthorizedAsync(ZeroEx.NULL_ADDRESS);
expect(isAuthorized).to.be.false();
});
});
describe('#getAuthorizedAddressesAsync', () => {
it('should return the list of authorized addresses', async () => {
const authorizedAddresses = await zeroEx.proxy.getAuthorizedAddressesAsync();
for (const authorizedAddress of authorizedAddresses) {
const isAuthorized = await zeroEx.proxy.isAuthorizedAsync(authorizedAddress);
expect(isAuthorized).to.be.true();
}
});
});
});

View File

@@ -0,0 +1,489 @@
import {BlockchainLifecycle} from '@0xproject/dev-utils';
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import BigNumber from 'bignumber.js';
import * as chai from 'chai';
import 'mocha';
import * as Web3 from 'web3';
import {
ApprovalContractEventArgs,
BlockParamLiteral,
BlockRange,
DecodedLogEvent,
Token,
TokenEvents,
TransferContractEventArgs,
ZeroEx,
ZeroExError,
} from '../src';
import {DoneCallback} from '../src/types';
import {chaiSetup} from './utils/chai_setup';
import {constants} from './utils/constants';
import {TokenUtils} from './utils/token_utils';
import {web3Factory} from './utils/web3_factory';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL);
describe('TokenWrapper', () => {
let web3: Web3;
let zeroEx: ZeroEx;
let userAddresses: string[];
let tokens: Token[];
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, config);
web3Wrapper = new Web3Wrapper(web3.currentProvider);
userAddresses = await zeroEx.getAvailableAddressesAsync();
tokens = await zeroEx.tokenRegistry.getTokensAsync();
tokenUtils = new TokenUtils(tokens);
coinbase = userAddresses[0];
addressWithoutFunds = userAddresses[1];
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('#transferAsync', () => {
let token: Token;
let transferAmount: BigNumber;
before(() => {
token = tokens[0];
transferAmount = new BigNumber(42);
});
it('should successfully transfer tokens', async () => {
const fromAddress = coinbase;
const toAddress = addressWithoutFunds;
const preBalance = await zeroEx.token.getBalanceAsync(token.address, toAddress);
expect(preBalance).to.be.bignumber.equal(0);
await zeroEx.token.transferAsync(token.address, fromAddress, toAddress, transferAmount);
const postBalance = await zeroEx.token.getBalanceAsync(token.address, toAddress);
return expect(postBalance).to.be.bignumber.equal(transferAmount);
});
it('should fail to transfer tokens if fromAddress has an insufficient balance', async () => {
const fromAddress = addressWithoutFunds;
const toAddress = coinbase;
return expect(zeroEx.token.transferAsync(
token.address, fromAddress, toAddress, transferAmount,
)).to.be.rejectedWith(ZeroExError.InsufficientBalanceForTransfer);
});
it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
const fromAddress = coinbase;
const toAddress = coinbase;
return expect(zeroEx.token.transferAsync(
nonExistentTokenAddress, fromAddress, toAddress, transferAmount,
)).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
});
});
describe('#transferFromAsync', () => {
let token: Token;
let toAddress: string;
let senderAddress: string;
before(async () => {
token = tokens[0];
toAddress = addressWithoutFunds;
senderAddress = userAddresses[2];
});
it('should fail to transfer tokens if fromAddress has insufficient allowance set', async () => {
const fromAddress = coinbase;
const transferAmount = new BigNumber(42);
const fromAddressBalance = await zeroEx.token.getBalanceAsync(token.address, fromAddress);
expect(fromAddressBalance).to.be.bignumber.greaterThan(transferAmount);
const fromAddressAllowance = await zeroEx.token.getAllowanceAsync(token.address, fromAddress,
toAddress);
expect(fromAddressAllowance).to.be.bignumber.equal(0);
return expect(zeroEx.token.transferFromAsync(
token.address, fromAddress, toAddress, senderAddress, transferAmount,
)).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer);
});
it('[regression] should fail to transfer tokens if set allowance for toAddress instead of senderAddress',
async () => {
const fromAddress = coinbase;
const transferAmount = new BigNumber(42);
await zeroEx.token.setAllowanceAsync(token.address, fromAddress, toAddress, transferAmount);
return expect(zeroEx.token.transferFromAsync(
token.address, fromAddress, toAddress, senderAddress, transferAmount,
)).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer);
});
it('should fail to transfer tokens if fromAddress has insufficient balance', async () => {
const fromAddress = addressWithoutFunds;
const transferAmount = new BigNumber(42);
const fromAddressBalance = await zeroEx.token.getBalanceAsync(token.address, fromAddress);
expect(fromAddressBalance).to.be.bignumber.equal(0);
await zeroEx.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount);
const fromAddressAllowance = await zeroEx.token.getAllowanceAsync(token.address, fromAddress,
senderAddress);
expect(fromAddressAllowance).to.be.bignumber.equal(transferAmount);
return expect(zeroEx.token.transferFromAsync(
token.address, fromAddress, toAddress, senderAddress, transferAmount,
)).to.be.rejectedWith(ZeroExError.InsufficientBalanceForTransfer);
});
it('should successfully transfer tokens', async () => {
const fromAddress = coinbase;
const preBalance = await zeroEx.token.getBalanceAsync(token.address, toAddress);
expect(preBalance).to.be.bignumber.equal(0);
const transferAmount = new BigNumber(42);
await zeroEx.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount);
await zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress,
transferAmount);
const postBalance = await zeroEx.token.getBalanceAsync(token.address, toAddress);
return expect(postBalance).to.be.bignumber.equal(transferAmount);
});
it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
const fromAddress = coinbase;
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
return expect(zeroEx.token.transferFromAsync(
nonExistentTokenAddress, fromAddress, toAddress, senderAddress, new BigNumber(42),
)).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
});
});
describe('#getBalanceAsync', () => {
describe('With web3 provider with accounts', () => {
it('should return the balance for an existing ERC20 token', async () => {
const token = tokens[0];
const ownerAddress = coinbase;
const balance = await zeroEx.token.getBalanceAsync(token.address, ownerAddress);
const expectedBalance = new BigNumber('1000000000000000000000000000');
return expect(balance).to.be.bignumber.equal(expectedBalance);
});
it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
const ownerAddress = coinbase;
return expect(zeroEx.token.getBalanceAsync(nonExistentTokenAddress, ownerAddress))
.to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
});
it('should return a balance of 0 for a non-existent owner address', async () => {
const token = tokens[0];
const nonExistentOwner = '0x198c6ad858f213fb31b6fe809e25040e6b964593';
const balance = await zeroEx.token.getBalanceAsync(token.address, nonExistentOwner);
const expectedBalance = new BigNumber(0);
return expect(balance).to.be.bignumber.equal(expectedBalance);
});
});
describe('With web3 provider without accounts', () => {
let zeroExWithoutAccounts: ZeroEx;
before(async () => {
const hasAddresses = false;
const web3WithoutAccounts = web3Factory.create(hasAddresses);
zeroExWithoutAccounts = new ZeroEx(web3WithoutAccounts.currentProvider, config);
});
it('should return balance even when called with Web3 provider instance without addresses', async () => {
const token = tokens[0];
const ownerAddress = coinbase;
const balance = await zeroExWithoutAccounts.token.getBalanceAsync(token.address, ownerAddress);
const expectedBalance = new BigNumber('1000000000000000000000000000');
return expect(balance).to.be.bignumber.equal(expectedBalance);
});
});
});
describe('#setAllowanceAsync', () => {
it('should set the spender\'s allowance', async () => {
const token = tokens[0];
const ownerAddress = coinbase;
const spenderAddress = addressWithoutFunds;
const allowanceBeforeSet = await zeroEx.token.getAllowanceAsync(token.address, ownerAddress,
spenderAddress);
const expectedAllowanceBeforeAllowanceSet = new BigNumber(0);
expect(allowanceBeforeSet).to.be.bignumber.equal(expectedAllowanceBeforeAllowanceSet);
const amountInBaseUnits = new BigNumber(50);
await zeroEx.token.setAllowanceAsync(token.address, ownerAddress, spenderAddress, amountInBaseUnits);
const allowanceAfterSet = await zeroEx.token.getAllowanceAsync(token.address, ownerAddress, spenderAddress);
const expectedAllowanceAfterAllowanceSet = amountInBaseUnits;
return expect(allowanceAfterSet).to.be.bignumber.equal(expectedAllowanceAfterAllowanceSet);
});
});
describe('#setUnlimitedAllowanceAsync', () => {
it('should set the unlimited spender\'s allowance', async () => {
const token = tokens[0];
const ownerAddress = coinbase;
const spenderAddress = addressWithoutFunds;
await zeroEx.token.setUnlimitedAllowanceAsync(token.address, ownerAddress, spenderAddress);
const allowance = await zeroEx.token.getAllowanceAsync(token.address, ownerAddress, spenderAddress);
return expect(allowance).to.be.bignumber.equal(zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
});
it('should reduce the gas cost for transfers including tokens with unlimited allowance support', async () => {
const transferAmount = new BigNumber(5);
const zrx = tokenUtils.getProtocolTokenOrThrow();
const [, userWithNormalAllowance, userWithUnlimitedAllowance] = userAddresses;
await zeroEx.token.setAllowanceAsync(zrx.address, coinbase, userWithNormalAllowance, transferAmount);
await zeroEx.token.setUnlimitedAllowanceAsync(zrx.address, coinbase, userWithUnlimitedAllowance);
const initBalanceWithNormalAllowance = await web3Wrapper.getBalanceInWeiAsync(userWithNormalAllowance);
const initBalanceWithUnlimitedAllowance = await web3Wrapper.getBalanceInWeiAsync(
userWithUnlimitedAllowance,
);
await zeroEx.token.transferFromAsync(
zrx.address, coinbase, userWithNormalAllowance, userWithNormalAllowance, transferAmount,
);
await zeroEx.token.transferFromAsync(
zrx.address, coinbase, userWithUnlimitedAllowance, userWithUnlimitedAllowance, transferAmount,
);
const finalBalanceWithNormalAllowance = await web3Wrapper.getBalanceInWeiAsync(userWithNormalAllowance);
const finalBalanceWithUnlimitedAllowance = await web3Wrapper.getBalanceInWeiAsync(
userWithUnlimitedAllowance,
);
const normalGasCost = initBalanceWithNormalAllowance.minus(finalBalanceWithNormalAllowance);
const unlimitedGasCost = initBalanceWithUnlimitedAllowance.minus(finalBalanceWithUnlimitedAllowance);
// In theory the gas cost with unlimited allowance should be smaller, but with testrpc it's actually bigger.
// This needs to be investigated in ethereumjs-vm. This test is essentially a repro.
// TODO: Make this test pass with inverted assertion.
expect(unlimitedGasCost.toNumber()).to.be.gt(normalGasCost.toNumber());
});
});
describe('#getAllowanceAsync', () => {
describe('With web3 provider with accounts', () => {
it('should get the proxy allowance', async () => {
const token = tokens[0];
const ownerAddress = coinbase;
const spenderAddress = addressWithoutFunds;
const amountInBaseUnits = new BigNumber(50);
await zeroEx.token.setAllowanceAsync(token.address, ownerAddress, spenderAddress, amountInBaseUnits);
const allowance = await zeroEx.token.getAllowanceAsync(token.address, ownerAddress, spenderAddress);
const expectedAllowance = amountInBaseUnits;
return expect(allowance).to.be.bignumber.equal(expectedAllowance);
});
it('should return 0 if no allowance set yet', async () => {
const token = tokens[0];
const ownerAddress = coinbase;
const spenderAddress = addressWithoutFunds;
const allowance = await zeroEx.token.getAllowanceAsync(token.address, ownerAddress, spenderAddress);
const expectedAllowance = new BigNumber(0);
return expect(allowance).to.be.bignumber.equal(expectedAllowance);
});
});
describe('With web3 provider without accounts', () => {
let zeroExWithoutAccounts: ZeroEx;
before(async () => {
const hasAddresses = false;
const web3WithoutAccounts = web3Factory.create(hasAddresses);
zeroExWithoutAccounts = new ZeroEx(web3WithoutAccounts.currentProvider, config);
});
it('should get the proxy allowance', async () => {
const token = tokens[0];
const ownerAddress = coinbase;
const spenderAddress = addressWithoutFunds;
const amountInBaseUnits = new BigNumber(50);
await zeroEx.token.setAllowanceAsync(token.address, ownerAddress, spenderAddress, amountInBaseUnits);
const allowance = await zeroExWithoutAccounts.token.getAllowanceAsync(
token.address, ownerAddress, spenderAddress,
);
const expectedAllowance = amountInBaseUnits;
return expect(allowance).to.be.bignumber.equal(expectedAllowance);
});
});
});
describe('#getProxyAllowanceAsync', () => {
it('should get the proxy allowance', async () => {
const token = tokens[0];
const ownerAddress = coinbase;
const amountInBaseUnits = new BigNumber(50);
await zeroEx.token.setProxyAllowanceAsync(token.address, ownerAddress, amountInBaseUnits);
const allowance = await zeroEx.token.getProxyAllowanceAsync(token.address, ownerAddress);
const expectedAllowance = amountInBaseUnits;
return expect(allowance).to.be.bignumber.equal(expectedAllowance);
});
});
describe('#setProxyAllowanceAsync', () => {
it('should set the proxy allowance', async () => {
const token = tokens[0];
const ownerAddress = coinbase;
const allowanceBeforeSet = await zeroEx.token.getProxyAllowanceAsync(token.address, ownerAddress);
const expectedAllowanceBeforeAllowanceSet = new BigNumber(0);
expect(allowanceBeforeSet).to.be.bignumber.equal(expectedAllowanceBeforeAllowanceSet);
const amountInBaseUnits = new BigNumber(50);
await zeroEx.token.setProxyAllowanceAsync(token.address, ownerAddress, amountInBaseUnits);
const allowanceAfterSet = await zeroEx.token.getProxyAllowanceAsync(token.address, ownerAddress);
const expectedAllowanceAfterAllowanceSet = amountInBaseUnits;
return expect(allowanceAfterSet).to.be.bignumber.equal(expectedAllowanceAfterAllowanceSet);
});
});
describe('#setUnlimitedProxyAllowanceAsync', () => {
it('should set the unlimited proxy allowance', async () => {
const token = tokens[0];
const ownerAddress = coinbase;
await zeroEx.token.setUnlimitedProxyAllowanceAsync(token.address, ownerAddress);
const allowance = await zeroEx.token.getProxyAllowanceAsync(token.address, ownerAddress);
return expect(allowance).to.be.bignumber.equal(zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
});
});
describe('#subscribe', () => {
const indexFilterValues = {};
let tokenAddress: string;
const transferAmount = new BigNumber(42);
const allowanceAmount = new BigNumber(42);
before(() => {
const token = tokens[0];
tokenAddress = token.address;
});
afterEach(() => {
zeroEx.token.unsubscribeAll();
});
// Hack: Mocha does not allow a test to be both async and have a `done` callback
// Since we need to await the receipt of the event in the `subscribe` callback,
// we do need both. A hack is to make the top-level a sync fn w/ a done callback and then
// wrap the rest of the test in an async block
// Source: https://github.com/mochajs/mocha/issues/2407
it('Should receive the Transfer event when tokens are transfered', (done: DoneCallback) => {
(async () => {
const callback = (err: Error, logEvent: DecodedLogEvent<TransferContractEventArgs>) => {
expect(logEvent).to.not.be.undefined();
expect(logEvent.isRemoved).to.be.false();
expect(logEvent.log.logIndex).to.be.equal(0);
expect(logEvent.log.transactionIndex).to.be.equal(0);
expect(logEvent.log.blockNumber).to.be.a('number');
const args = logEvent.log.args;
expect(args._from).to.be.equal(coinbase);
expect(args._to).to.be.equal(addressWithoutFunds);
expect(args._value).to.be.bignumber.equal(transferAmount);
done();
};
zeroEx.token.subscribe(
tokenAddress, TokenEvents.Transfer, indexFilterValues, callback);
await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
})().catch(done);
});
it('Should receive the Approval event when allowance is being set', (done: DoneCallback) => {
(async () => {
const callback = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
expect(logEvent).to.not.be.undefined();
expect(logEvent.isRemoved).to.be.false();
const args = logEvent.log.args;
expect(args._owner).to.be.equal(coinbase);
expect(args._spender).to.be.equal(addressWithoutFunds);
expect(args._value).to.be.bignumber.equal(allowanceAmount);
done();
};
zeroEx.token.subscribe(
tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount);
})().catch(done);
});
it('Outstanding subscriptions are cancelled when zeroEx.setProvider called', (done: DoneCallback) => {
(async () => {
const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
done(new Error('Expected this subscription to have been cancelled'));
};
zeroEx.token.subscribe(
tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled,
);
const callbackToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
done();
};
const newProvider = web3Factory.getRpcProvider();
zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID);
zeroEx.token.subscribe(
tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackToBeCalled,
);
await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
})().catch(done);
});
it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => {
(async () => {
const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
done(new Error('Expected this subscription to have been cancelled'));
};
const subscriptionToken = zeroEx.token.subscribe(
tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled);
zeroEx.token.unsubscribe(subscriptionToken);
await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
done();
})().catch(done);
});
});
describe('#getLogsAsync', () => {
let tokenAddress: string;
let tokenTransferProxyAddress: string;
const blockRange: BlockRange = {
fromBlock: 0,
toBlock: BlockParamLiteral.Latest,
};
let txHash: string;
before(() => {
const token = tokens[0];
tokenAddress = token.address;
tokenTransferProxyAddress = zeroEx.proxy.getContractAddress();
});
it('should get logs with decoded args emitted by Approval', async () => {
txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase);
await zeroEx.awaitTransactionMinedAsync(txHash);
const eventName = TokenEvents.Approval;
const indexFilterValues = {};
const logs = await zeroEx.token.getLogsAsync<ApprovalContractEventArgs>(
tokenAddress, eventName, blockRange, indexFilterValues,
);
expect(logs).to.have.length(1);
const args = logs[0].args;
expect(logs[0].event).to.be.equal(eventName);
expect(args._owner).to.be.equal(coinbase);
expect(args._spender).to.be.equal(tokenTransferProxyAddress);
expect(args._value).to.be.bignumber.equal(zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
});
it('should only get the logs with the correct event name', async () => {
txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase);
await zeroEx.awaitTransactionMinedAsync(txHash);
const differentEventName = TokenEvents.Transfer;
const indexFilterValues = {};
const logs = await zeroEx.token.getLogsAsync(
tokenAddress, differentEventName, blockRange, indexFilterValues,
);
expect(logs).to.have.length(0);
});
it('should only get the logs with the correct indexed fields', async () => {
txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase);
await zeroEx.awaitTransactionMinedAsync(txHash);
txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(tokenAddress, addressWithoutFunds);
await zeroEx.awaitTransactionMinedAsync(txHash);
const eventName = TokenEvents.Approval;
const indexFilterValues = {
_owner: coinbase,
};
const logs = await zeroEx.token.getLogsAsync<ApprovalContractEventArgs>(
tokenAddress, eventName, blockRange, indexFilterValues,
);
expect(logs).to.have.length(1);
const args = logs[0].args;
expect(args._owner).to.be.equal(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

@@ -0,0 +1,11 @@
export const constants = {
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
RPC_URL: 'http://localhost:8545/',
ROPSTEN_NETWORK_ID: 3,
KOVAN_NETWORK_ID: 42,
TESTRPC_NETWORK_ID: 50,
KOVAN_RPC_URL: 'https://kovan.infura.io/',
ROPSTEN_RPC_URL: 'https://ropsten.infura.io/',
ZRX_DECIMALS: 18,
GAS_ESTIMATE: 500000,
};

View File

@@ -0,0 +1,138 @@
import {Web3Wrapper} from '@0xproject/web3-wrapper';
import BigNumber from 'bignumber.js';
import {SignedOrder, Token, ZeroEx} from '../../src';
import {artifacts} from '../../src/artifacts';
import {DummyTokenContract} from '../../src/contract_wrappers/generated/dummy_token';
import {orderFactory} from '../utils/order_factory';
import {constants} from './constants';
const INITIAL_COINBASE_TOKEN_SUPPLY_IN_UNITS = new BigNumber(100);
export class FillScenarios {
private _zeroEx: ZeroEx;
private _userAddresses: string[];
private _tokens: Token[];
private _coinbase: string;
private _zrxTokenAddress: string;
private _exchangeContractAddress: string;
constructor(zeroEx: ZeroEx, userAddresses: string[],
tokens: Token[], zrxTokenAddress: string, exchangeContractAddress: string) {
this._zeroEx = zeroEx;
this._userAddresses = userAddresses;
this._tokens = tokens;
this._coinbase = userAddresses[0];
this._zrxTokenAddress = zrxTokenAddress;
this._exchangeContractAddress = exchangeContractAddress;
}
public async initTokenBalancesAsync() {
const web3Wrapper = (this._zeroEx as any)._web3Wrapper as Web3Wrapper;
for (const token of this._tokens) {
if (token.symbol !== 'ZRX' && token.symbol !== 'WETH') {
const contractInstance = web3Wrapper.getContractInstance(
artifacts.DummyTokenArtifact.abi, token.address,
);
const defaults = {};
const dummyToken = new DummyTokenContract(contractInstance, defaults);
const tokenSupply = ZeroEx.toBaseUnitAmount(INITIAL_COINBASE_TOKEN_SUPPLY_IN_UNITS, token.decimals);
const txHash = await dummyToken.setBalance.sendTransactionAsync(this._coinbase, tokenSupply, {
from: this._coinbase,
});
await this._zeroEx.awaitTransactionMinedAsync(txHash);
}
}
}
public async createFillableSignedOrderAsync(makerTokenAddress: string, takerTokenAddress: string,
makerAddress: string, takerAddress: string,
fillableAmount: BigNumber,
expirationUnixTimestampSec?: BigNumber):
Promise<SignedOrder> {
return this.createAsymmetricFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
fillableAmount, fillableAmount, expirationUnixTimestampSec,
);
}
public async createFillableSignedOrderWithFeesAsync(
makerTokenAddress: string, takerTokenAddress: string,
makerFee: BigNumber, takerFee: BigNumber,
makerAddress: string, takerAddress: string,
fillableAmount: BigNumber,
feeRecepient: string, expirationUnixTimestampSec?: BigNumber,
): Promise<SignedOrder> {
return this._createAsymmetricFillableSignedOrderWithFeesAsync(
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress,
fillableAmount, fillableAmount, feeRecepient, expirationUnixTimestampSec,
);
}
public async createAsymmetricFillableSignedOrderAsync(
makerTokenAddress: string, takerTokenAddress: string, makerAddress: string, takerAddress: string,
makerFillableAmount: BigNumber, takerFillableAmount: BigNumber,
expirationUnixTimestampSec?: BigNumber): Promise<SignedOrder> {
const makerFee = new BigNumber(0);
const takerFee = new BigNumber(0);
const feeRecepient = constants.NULL_ADDRESS;
return this._createAsymmetricFillableSignedOrderWithFeesAsync(
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress,
makerFillableAmount, takerFillableAmount, feeRecepient, expirationUnixTimestampSec,
);
}
public async createPartiallyFilledSignedOrderAsync(makerTokenAddress: string, takerTokenAddress: string,
takerAddress: string, fillableAmount: BigNumber,
partialFillAmount: BigNumber) {
const [makerAddress] = this._userAddresses;
const signedOrder = await this.createAsymmetricFillableSignedOrderAsync(
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
fillableAmount, fillableAmount,
);
const shouldThrowOnInsufficientBalanceOrAllowance = false;
await this._zeroEx.exchange.fillOrderAsync(
signedOrder, partialFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
);
return signedOrder;
}
private async _createAsymmetricFillableSignedOrderWithFeesAsync(
makerTokenAddress: string, takerTokenAddress: string,
makerFee: BigNumber, takerFee: BigNumber,
makerAddress: string, takerAddress: string,
makerFillableAmount: BigNumber, takerFillableAmount: BigNumber,
feeRecepient: string, expirationUnixTimestampSec?: BigNumber): Promise<SignedOrder> {
await Promise.all([
this._increaseBalanceAndAllowanceAsync(makerTokenAddress, makerAddress, makerFillableAmount),
this._increaseBalanceAndAllowanceAsync(takerTokenAddress, takerAddress, takerFillableAmount),
]);
await Promise.all([
this._increaseBalanceAndAllowanceAsync(this._zrxTokenAddress, makerAddress, makerFee),
this._increaseBalanceAndAllowanceAsync(this._zrxTokenAddress, takerAddress, takerFee),
]);
const signedOrder = await orderFactory.createSignedOrderAsync(this._zeroEx,
makerAddress, takerAddress, makerFee, takerFee,
makerFillableAmount, makerTokenAddress, takerFillableAmount, takerTokenAddress,
this._exchangeContractAddress, feeRecepient, expirationUnixTimestampSec);
return signedOrder;
}
private async _increaseBalanceAndAllowanceAsync(
tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
if (amount.isZero() || address === ZeroEx.NULL_ADDRESS) {
return; // noop
}
await Promise.all([
this._increaseBalanceAsync(tokenAddress, address, amount),
this._increaseAllowanceAsync(tokenAddress, address, amount),
]);
}
private async _increaseBalanceAsync(
tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
await this._zeroEx.token.transferAsync(tokenAddress, this._coinbase, address, amount);
}
private async _increaseAllowanceAsync(
tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
const oldMakerAllowance = await this._zeroEx.token.getProxyAllowanceAsync(tokenAddress, address);
const newMakerAllowance = oldMakerAllowance.plus(amount);
await this._zeroEx.token.setProxyAllowanceAsync(
tokenAddress, address, newMakerAllowance,
);
}
}

View File

@@ -1,24 +1,26 @@
import BigNumber from 'bignumber.js';
import * as _ from 'lodash';
import * as BigNumber from 'bignumber.js';
import {ZeroEx, SignedOrder} from '../../src';
import {SignedOrder, ZeroEx} from '../../src';
export const orderFactory = {
async createSignedOrderAsync(
zeroEx: ZeroEx,
maker: string,
taker: string,
makerFee: BigNumber.BigNumber,
takerFee: BigNumber.BigNumber,
makerTokenAmount: BigNumber.BigNumber,
makerFee: BigNumber,
takerFee: BigNumber,
makerTokenAmount: BigNumber,
makerTokenAddress: string,
takerTokenAmount: BigNumber.BigNumber,
takerTokenAmount: BigNumber,
takerTokenAddress: string,
exchangeContractAddress: string,
feeRecipient: string,
expirationUnixTimestampSec?: BigNumber.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,
@@ -29,10 +31,11 @@ export const orderFactory = {
makerTokenAddress,
takerTokenAddress,
salt: ZeroEx.generatePseudoRandomSalt(),
exchangeContractAddress,
feeRecipient,
expirationUnixTimestampSec,
};
const orderHash = await zeroEx.getOrderHashHexAsync(order);
const orderHash = ZeroEx.getOrderHashHex(order);
const ecSignature = await zeroEx.signOrderHashAsync(orderHash, maker);
const signedOrder: SignedOrder = _.assign(order, {ecSignature});
return signedOrder;

View File

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

View File

@@ -0,0 +1,27 @@
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 {
// 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':
end(null, []);
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

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

@@ -0,0 +1,33 @@
import * as _ from 'lodash';
import {InternalZeroExError, Token} from '../../src/types';
const PROTOCOL_TOKEN_SYMBOL = 'ZRX';
const WETH_TOKEN_SYMBOL = 'WETH';
export class TokenUtils {
private _tokens: Token[];
constructor(tokens: Token[]) {
this._tokens = tokens;
}
public getProtocolTokenOrThrow(): Token {
const zrxToken = _.find(this._tokens, {symbol: PROTOCOL_TOKEN_SYMBOL});
if (_.isUndefined(zrxToken)) {
throw new Error(InternalZeroExError.ZrxNotInTokenRegistry);
}
return zrxToken;
}
public getWethTokenOrThrow(): Token {
const wethToken = _.find(this._tokens, {symbol: WETH_TOKEN_SYMBOL});
if (_.isUndefined(wethToken)) {
throw new Error(InternalZeroExError.WethNotInTokenRegistry);
}
return wethToken;
}
public getDummyTokens(): Token[] {
const dummyTokens = _.filter(this._tokens, token => {
return !_.includes([PROTOCOL_TOKEN_SYMBOL, WETH_TOKEN_SYMBOL], token.symbol);
});
return dummyTokens;
}
}

View File

@@ -0,0 +1,40 @@
// HACK: web3 injects XMLHttpRequest into the global scope and ProviderEngine checks XMLHttpRequest
// to know whether it is running in a browser or node environment. We need it to be undefined since
// we are not running in a browser env.
// Filed issue: https://github.com/ethereum/web3.js/issues/844
(global as any).XMLHttpRequest = undefined;
import ProviderEngine = require('web3-provider-engine');
import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
import {EmptyWalletSubprovider} from './subproviders/empty_wallet_subprovider';
import {FakeGasEstimateSubprovider} from './subproviders/fake_gas_estimate_subprovider';
import {constants} from './constants';
// HACK: web3 leaks XMLHttpRequest into the global scope and causes requests to hang
// because they are using the wrong XHR package.
// importing web3 after subproviders fixes this issue
// Filed issue: https://github.com/ethereum/web3.js/issues/844
// tslint:disable-next-line:ordered-imports
import * as Web3 from 'web3';
export const web3Factory = {
create(hasAddresses: boolean = true): Web3 {
const provider = this.getRpcProvider(hasAddresses);
const web3 = new Web3();
web3.setProvider(provider);
return web3;
},
getRpcProvider(hasAddresses: boolean = true): Web3.Provider {
const provider = new ProviderEngine();
if (!hasAddresses) {
provider.addProvider(new EmptyWalletSubprovider());
}
provider.addProvider(new FakeGasEstimateSubprovider(constants.GAS_ESTIMATE));
provider.addProvider(new RpcSubprovider({
rpcUrl: constants.RPC_URL,
}));
provider.start();
return provider;
},
};

View File

@@ -13,8 +13,10 @@
"include": [
"./src/**/*",
"./test/**/*",
"./node_modules/web3-typescript-typings/index.d.ts",
"./node_modules/chai-typescript-typings/index.d.ts",
"./node_modules/chai-as-promised-typescript-typings/index.d.ts"
"../../node_modules/types-bn/index.d.ts",
"../../node_modules/types-ethereumjs-util/index.d.ts",
"../../node_modules/web3-typescript-typings/index.d.ts",
"../../node_modules/chai-typescript-typings/index.d.ts",
"../../node_modules/chai-as-promised-typescript-typings/index.d.ts"
]
}

View File

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

View File

@@ -0,0 +1,4 @@
# CHANGELOG
vx.x.x
------------------------

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/0x.js/contract_templates) are the templates used to generate those files.
## Installation
`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/0x.js/contract_templates) and start adjusting them for your needs.
We use [handlebars](http://handlebarsjs.com/) template engine under the hood.
You need to have a master template called `contract.mustache`. it will be used to generate each contract wrapper. Although - you don't need and probably shouldn't write all your logic in a single template file. You can write [partial templates](http://handlebarsjs.com/partials.html) and as long as they are within a partials folder - they will be registered and available.
## Which data/context do I get in my templates?
For now you don't get much on top of methods abi, some useful helpers and a contract name because it was enough for our use-case, but if you need something else - create a PR.
See the [type definition](https://github.com/0xProject/0x.js/tree/development/packages/abi-gen/src/types.ts) of what we pass to the render method.
## Output files
Output files will be generated within an output folder with names converted to camel case and taken from abi file names. If you already have some files in that folder they will be overwritten.

View File

@@ -0,0 +1,48 @@
{
"name": "@0xproject/abi-gen",
"version": "0.0.4",
"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.4.0",
"@types/glob": "^5.0.33",
"@types/handlebars": "^4.0.36",
"@types/mkdirp": "^0.5.1",
"@types/node": "^8.0.53",
"@types/yargs": "^10.0.0",
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"tslint": "5.8.0",
"typescript": "~2.6.1",
"web3-typescript-typings": "^0.7.2"
}
}

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

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.

54
packages/assert/README.md Normal file
View File

@@ -0,0 +1,54 @@
@0xproject/assert
------
Standard type and schema assertions to be used across all 0x projects and packages
## Installation
```bash
yarn add @0xproject/assert
```
## Usage
```typescript
import {assert} from '@0xproject/assert';
assert.isValidBaseUnitAmount('baseUnitAmount', baseUnitAmount);
```
## Contributing
We strongly encourage that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
### Install Dependencies
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
```bash
yarn config set workspaces-experimental true
```
Then install dependencies
```bash
yarn install
```
### Build
```bash
yarn build
```
### Lint
```bash
yarn lint
```
### Run Tests
```bash
yarn test
```

View File

@@ -0,0 +1,46 @@
{
"name": "@0xproject/assert",
"version": "0.0.9",
"description": "Provides a standard way of performing type and schema validation across 0x projects",
"main": "lib/src/index.js",
"types": "lib/src/index.d.ts",
"scripts": {
"build": "tsc",
"clean": "shx rm -rf _bundles lib test_temp",
"lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'",
"run_mocha": "mocha lib/test/**/*_test.js",
"prepublishOnly": "run-p build",
"test": "run-s clean build run_mocha",
"test:circleci": "yarn test"
},
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/0xProject/0x.js.git"
},
"bugs": {
"url": "https://github.com/0xProject/0x.js/issues"
},
"homepage": "https://github.com/0xProject/0x.js/packages/assert/README.md",
"devDependencies": {
"@0xproject/tslint-config": "^0.4.0",
"@types/lodash": "^4.14.86",
"@types/mocha": "^2.2.42",
"@types/valid-url": "^1.0.2",
"chai": "^4.0.1",
"chai-typescript-typings": "^0.0.1",
"dirty-chai": "^2.0.1",
"mocha": "^4.0.1",
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"tslint": "5.8.0",
"typescript": "~2.6.1"
},
"dependencies": {
"@0xproject/json-schemas": "^0.7.1",
"@0xproject/utils": "^0.1.2",
"bignumber.js": "~4.1.0",
"lodash": "^4.17.4",
"valid-url": "^1.0.9"
}
}

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

1
packages/assert/src/globals.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
declare module 'dirty-chai';

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