Compare commits
211 Commits
@0xproject
...
@0xproject
Author | SHA1 | Date | |
---|---|---|---|
|
547bee38c0 | ||
|
60614ba250 | ||
|
278f68ae77 | ||
|
0e3bd0c6c1 | ||
|
86668eb7b9 | ||
|
771f65c858 | ||
|
89d6326a83 | ||
|
8b81ea162f | ||
|
a53e6db537 | ||
|
62e3feeb94 | ||
|
a950494503 | ||
|
3cb310122e | ||
|
feace988b4 | ||
|
6a56f20928 | ||
|
80a46d14be | ||
|
fbcbf066cd | ||
|
4d30e1115f | ||
|
897cfb491c | ||
|
c2c7512431 | ||
|
568cf4d182 | ||
|
f54330f1c5 | ||
|
97e01d7a42 | ||
|
4be3e000e1 | ||
|
b47baa9ee1 | ||
|
f6c98112df | ||
|
94d29ab22e | ||
|
b0b179550a | ||
|
41c7ab4f9c | ||
|
432c7c63fe | ||
|
2bba1ae292 | ||
|
7830d518e0 | ||
|
571b3c4da8 | ||
|
5b6f8d4c3f | ||
|
ae57b21b98 | ||
|
292c3bbff8 | ||
|
065570ebf5 | ||
|
1f5dfd71d5 | ||
|
31b3ac4b98 | ||
|
7f4a383d75 | ||
|
de943c5f30 | ||
|
e34b0af251 | ||
|
fa7237fde7 | ||
|
ed530cef72 | ||
|
0f8b2703d1 | ||
|
a2176f566b | ||
|
bef056b084 | ||
|
c8c86c44f8 | ||
|
f917a4a34a | ||
|
78fd942faa | ||
|
a3274ac9b1 | ||
|
2e67d69434 | ||
|
c2d6e78b2a | ||
|
7233a11ba0 | ||
|
3a1360ce11 | ||
|
ba761044a6 | ||
|
d8636a2c5d | ||
|
9889c8f9e0 | ||
|
7e2e392ecc | ||
|
6912a67eba | ||
|
6abc83de83 | ||
|
0ca66a1469 | ||
|
a88be1af44 | ||
|
ae47fda257 | ||
|
6eb5411029 | ||
|
73d13d61a7 | ||
|
fdf213ef72 | ||
|
22fe605b1e | ||
|
bcc902a889 | ||
|
24ff2ec30c | ||
|
4e0c67e2a1 | ||
|
0cc21db654 | ||
|
dd5d1c00e5 | ||
|
cad2555c03 | ||
|
005d8184aa | ||
|
c228eddc57 | ||
|
ae37f8d9b6 | ||
|
6a8113af1d | ||
|
0c8cf12650 | ||
|
2e29a51ccf | ||
|
162f1d94dc | ||
|
a76bce1f32 | ||
|
be20e04c7b | ||
|
d9df82f31d | ||
|
6210333628 | ||
|
a552a790d3 | ||
|
9acb745956 | ||
|
875edaf96f | ||
|
a9afc0f3f0 | ||
|
3bbeaabe26 | ||
|
c04cbb480a | ||
|
2c241c294e | ||
|
ce851f3c28 | ||
|
817a6d1828 | ||
|
4d0735e7f6 | ||
|
80291930f0 | ||
|
cf8678b979 | ||
|
67722c0fb8 | ||
|
0b6e246c04 | ||
|
3992295678 | ||
|
da404b9acc | ||
|
da8db153be | ||
|
2c90f7324b | ||
|
2cdb0de1c3 | ||
|
66bd798e80 | ||
|
cf37dfb257 | ||
|
217f84204e | ||
|
fbbe0ec3db | ||
|
1ec34767f9 | ||
|
14e94a5376 | ||
|
08508afdb2 | ||
|
4220f25e01 | ||
|
4ff5afecc8 | ||
|
2eabb439d9 | ||
|
2bc9d5d490 | ||
|
9e1c142f02 | ||
|
1a38893b52 | ||
|
f28d75cf7c | ||
|
a3c9d0ace5 | ||
|
aea1799a64 | ||
|
ef76c4c62b | ||
|
210e7c5579 | ||
|
3fa0046542 | ||
|
d6754685cc | ||
|
bb5721700b | ||
|
5c4a1dcbd5 | ||
|
4f488dee61 | ||
|
0d33758104 | ||
|
15b5fcbaf9 | ||
|
0718b0d5b0 | ||
|
0af2ba1b7d | ||
|
ea2fdecb83 | ||
|
07eb250083 | ||
|
ee04717e1b | ||
|
d7d22c36ed | ||
|
36bf91f920 | ||
|
98e9c3b800 | ||
|
a7f1137db8 | ||
|
f86159e717 | ||
|
6e93223ea3 | ||
|
a6d677043f | ||
|
eb1bf198ac | ||
|
0a2f82a19d | ||
|
27d9fba785 | ||
|
e6a783aff8 | ||
|
a767c353d2 | ||
|
a39d3d7233 | ||
|
40c7ee6355 | ||
|
eb760aa33f | ||
|
262c34abac | ||
|
8019b1b823 | ||
|
7a56e83fa3 | ||
|
a1c38d9cb2 | ||
|
734cf5819a | ||
|
35e0b6143a | ||
|
e019ae4aed | ||
|
c700046b76 | ||
|
326a6b729f | ||
|
e2ef0c5b94 | ||
|
c49f68ef3e | ||
|
d0f66f8624 | ||
|
4dfa720f2d | ||
|
f3b8bac477 | ||
|
ce6abad97f | ||
|
807e908f78 | ||
|
94c75b5262 | ||
|
eb0dd6b6e9 | ||
|
1c542c3e0d | ||
|
d46fcb33c5 | ||
|
d5e0da0eb6 | ||
|
e744e4cd98 | ||
|
9a96e8c704 | ||
|
31a94f468e | ||
|
7422b9b53b | ||
|
161a9d6ad2 | ||
|
f684cc3711 | ||
|
ab0c8c3496 | ||
|
47534b200d | ||
|
f2976af734 | ||
|
ee463058f1 | ||
|
c36a7471a8 | ||
|
6ea8cee551 | ||
|
69806c8839 | ||
|
690036aa30 | ||
|
8fe81c9d09 | ||
|
eda6b8d01b | ||
|
9f3acf8e28 | ||
|
31c9c82f6c | ||
|
cbf06b2165 | ||
|
e884eb9882 | ||
|
f8cbfea4a1 | ||
|
e01c0f054d | ||
|
12dc8c0d15 | ||
|
cb3582289f | ||
|
734d220d60 | ||
|
d725de7286 | ||
|
3e91773cd9 | ||
|
dc1d2a33a5 | ||
|
ac4074911d | ||
|
66cf60f9cb | ||
|
fffe8c355e | ||
|
b94d13b413 | ||
|
85e16c1233 | ||
|
2d53b7d9a4 | ||
|
23052a5c2e | ||
|
42b3a7c9d7 | ||
|
33315046cd | ||
|
2cf647d5ad | ||
|
b1d88ca643 | ||
|
b79b48cfbe | ||
|
a2bf19efc1 | ||
|
cb11aec84d |
@@ -26,3 +26,4 @@ jobs:
|
||||
background: true
|
||||
- run: yarn lerna:run test:circleci
|
||||
- run: yarn lerna:run lint
|
||||
- run: yarn prettier:ci
|
||||
|
4
.prettierignore
Normal file
4
.prettierignore
Normal file
@@ -0,0 +1,4 @@
|
||||
lib
|
||||
generated
|
||||
.nyc_output
|
||||
/packages/contracts/build/contracts
|
6
.prettierrc
Normal file
6
.prettierrc
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"tabWidth": 4,
|
||||
"printWidth": 120,
|
||||
"trailingComma": all,
|
||||
"singleQuote": true
|
||||
}
|
@@ -1,62 +1,46 @@
|
||||
# 0x.js CONTRIBUTING.md
|
||||
## 0x Contribution Guide
|
||||
|
||||
Thank you for your interest in contributing to 0x.js! We welcome contributions from anyone on the internet, and are grateful for even the smallest of fixes!
|
||||
Thank you for your interest in contributing to 0x protocol! We welcome contributions from anyone on the internet, and are grateful for even the smallest of fixes!
|
||||
|
||||
## Developer's guide
|
||||
### How to contribute
|
||||
|
||||
## How to contribute
|
||||
If you'd like to contribute to 0x protocol, please fork the repo, fix, commit and send a pull request against the `development` branch for the maintainers to review and merge into the main code base. If you wish to submit more complex changes though, please check with a core dev first on [our RocketChat #dev channel](http://chat.0xproject.com) to ensure those changes are in-line with the general philosophy of the project and/or to get some early feedback which can make both your efforts easier as well as our review and merge procedures quick and simple.
|
||||
|
||||
If you'd like to contribute to 0x.js, please fork the repo, fix, commit and send a pull request against the `development` branch for the maintainers to review and merge into the main code base. If you wish to submit more complex changes though, please check up with a core dev first on [our gitter channel](https://gitter.im/0xProject/Lobby) or in the `#dev` channel on our [slack](https://slack.0xproject.com/) to ensure those changes are in line with the general philosophy of the project and/or to get some early feedback which can make both your efforts easier as well as our review and merge procedures quick and simple.
|
||||
|
||||
We encourage a “PR early” approach so create the PR as early as possible even without the fix/feature ready, so that devs and other volunteers know you have picked up the issue. These early PRs should indicate an 'in progress' status by adding the '[WIP]' prefix to the PR title. Please make sure your contributions adhere to our coding guidelines:
|
||||
We encourage a “PR early” approach so create the PR as early as possible even without the fix/feature ready, so that devs and other contributors know you have picked up the issue. These early PRs should indicate an 'in progress' status by adding the '[WIP]' prefix to the PR title. Please make sure your contributions adhere to our coding guidelines:
|
||||
|
||||
* Pull requests adding features or refactoring should be opened against the `development` branch
|
||||
* Pull requests fixing bugs in the latest release version should be opened again the `master` branch
|
||||
* Write [good commit messages](https://chris.beams.io/posts/git-commit/)
|
||||
|
||||
## Code quality
|
||||
### Code quality
|
||||
|
||||
Because 0x.js is used by multiple relayers in production and their businesses depend on it, we strive for exceptional code quality. Please follow the existing code standards and conventions. `tslint` and `prettier` (described below) will help you.
|
||||
|
||||
Because 0x.js is used by multiple relayers in production and their businesses depend on it, we strive for excellent code quality. Please follow the existing code standards and conventions. `tslint` (described below) will help you.
|
||||
If you're adding functionality, please also add tests and make sure they pass. We have an automatic coverage reporting tool, so we'll see it if they are missing ;)
|
||||
If you're adding a new public function/member, make sure you document it with Java doc-style comments. We use typedoc to generate [awesome documentation](https://0xproject.com/docs/0xjs) from the comments within our source code.
|
||||
|
||||
## Running and building
|
||||
If the sub-package you are modifying has a `CHANGELOG.md` file, make sure to add an entry in it for the change made to the package. For published packages, only changes that modify the public interface or behavior of the package need a CHANGELOG entry.
|
||||
|
||||
First thing to do with an unknown code base is to run the tests.
|
||||
We assume that you have `npm` and `yarn` installed.
|
||||
### Styleguide
|
||||
|
||||
To do that:
|
||||
|
||||
* Install dependencies: `yarn`
|
||||
* Initialize the testrpc state (migrate the contracts) by doing one of the following:
|
||||
* Manual contracts migration:
|
||||
* Run testrpc: `yarn testrpc`
|
||||
* Clone the `[contracts](https://github.com/0xProject/contracts)` repo and run `yarn migrate`
|
||||
* Use one of the existing testrpc snapshots
|
||||
* Check out `circle.yml` for an example
|
||||
* Run tests: `yarn test`
|
||||
|
||||
To build run: `yarn build`
|
||||
|
||||
We also recommend you read through the tests.
|
||||
|
||||
## Styleguide
|
||||
|
||||
We use [TSLint](https://palantir.github.io/tslint/) with [custom configs](https://github.com/0xProject/tslint-config-0xproject) to keep our code style consistent.
|
||||
We use [TSLint](https://palantir.github.io/tslint/) with [custom configs](https://github.com/0xProject/0x.js/tree/development/packages/tslint-config) to keep our code style consistent.
|
||||
|
||||
To lint your code just run: `yarn lint`
|
||||
|
||||
We also use [Prettier](https://prettier.io/) to auto-format our code. Be sure to either add a [text editor integration](https://prettier.io/docs/en/editors.html) or a [pre-commit hook](https://prettier.io/docs/en/precommit.html) to properly format your code changes.
|
||||
|
||||
If using the Atom text editor, we recommend you install the following packages:
|
||||
|
||||
* [atom-typescript](https://atom.io/packages/atom-typescript)
|
||||
* [linter-tslint](https://atom.io/packages/linter-tslint)
|
||||
* [prettier-atom](https://atom.io/packages/prettier-atom)
|
||||
* [language-ethereum](https://atom.io/packages/language-ethereum)
|
||||
|
||||
Our CI will also run it as a part of the test run when you submit your PR.
|
||||
Our CI will also run TSLint and Prettier as a part of the test run when you submit your PR. Make sure that the CI tests pass for your contribution.
|
||||
|
||||
### Branch structure & versioning
|
||||
|
||||
## Branch structure & versioning
|
||||
|
||||
We use [semantic versioning](http://semver.org/), but before we reach v1.0.0 all breaking changes as well as new features will be minor version bumps.
|
||||
We use [semantic versioning](http://semver.org/), but before a package reaches v1.0.0 all breaking changes as well as new features will be minor version bumps.
|
||||
|
||||
We have two main branches: `master` and `development`.
|
||||
|
||||
|
@@ -1,2 +1,3 @@
|
||||
This PR:
|
||||
*
|
||||
|
||||
\*
|
||||
|
27
README.md
27
README.md
@@ -11,8 +11,7 @@ This repository contains all the 0x developer tools written in TypeScript. Our h
|
||||
|
||||
[](https://circleci.com/gh/0xProject/0x.js)
|
||||
[](https://coveralls.io/github/0xProject/0x.js?branch=master)
|
||||
[](https://chat.0xproject.com)
|
||||
[](https://chat.0xproject.com)
|
||||
[](https://gitter.im/0xProject/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
[](https://greenkeeper.io/)
|
||||
@@ -20,8 +19,11 @@ This repository contains all the 0x developer tools written in TypeScript. Our h
|
||||
### Published Packages
|
||||
|
||||
| Package | Version | Description |
|
||||
|---------|---------|-------------|
|
||||
| -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
|
||||
| [`0x.js`](/packages/0x.js) | [](https://www.npmjs.com/package/0x.js) | A Javascript library for interacting with the 0x protocol |
|
||||
| [`chai-as-promised-typescript-typings`](/packages/chai-as-promised-typescript-typings) | [](https://www.npmjs.com/package/chai-as-promised-typescript-typings) | Chai as promised typescript typings |
|
||||
| [`chai-typescript-typings`](/packages/chai-typescript-typings) | [](https://www.npmjs.com/package/chai-typescript-typings) | Chai typescript typings |
|
||||
| [`web3-typescript-typings`](/packages/web3-typescript-typings) | [](https://www.npmjs.com/package/web3-typescript-typings) | Web3 typescript typings |
|
||||
| [`@0xproject/abi-gen`](/packages/abi-gen) | [](https://www.npmjs.com/package/@0xproject/abi-gen) | Tool to generate TS wrappers from smart contract ABIs |
|
||||
| [`@0xproject/assert`](/packages/assert) | [](https://www.npmjs.com/package/@0xproject/assert) | Type and schema assertions used by our packages |
|
||||
| [`@0xproject/connect`](/packages/connect) | [](https://www.npmjs.com/package/@0xproject/connect) | A Javascript library for interacting with the standard relayer api |
|
||||
@@ -30,12 +32,12 @@ This repository contains all the 0x developer tools written in TypeScript. Our h
|
||||
| [`@0xproject/tslint-config`](/packages/tslint-config) | [](https://www.npmjs.com/package/@0xproject/tslint-config) | Custom 0x development TSLint rules |
|
||||
| [`@0xproject/types`](/packages/types) | [](https://www.npmjs.com/package/@0xproject/types) | Shared type declarations |
|
||||
| [`@0xproject/utils`](/packages/utils) | [](https://www.npmjs.com/package/@0xproject/utils) | Shared utilities |
|
||||
| [`@0xproject/web3-wrapper`](/packages/web3-wrapper) | [](https://www.npmjs.com/package/@0xproject/web3-wrapper) | Web3 wrapper |
|
||||
| [`@0xproject/web3-wrapper`](/packages/web3-wrapper) | [](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 |
|
||||
@@ -44,10 +46,11 @@ This repository contains all the 0x developer tools written in TypeScript. Our h
|
||||
## 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)
|
||||
|
||||
* [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
|
||||
|
||||
@@ -58,11 +61,13 @@ Please read our [contribution guidelines](./CONTRIBUTING.md) before getting star
|
||||
### 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
|
||||
```
|
||||
@@ -78,6 +83,7 @@ yarn lerna:run build
|
||||
### Lint
|
||||
|
||||
Lint all packages
|
||||
|
||||
```bash
|
||||
yarn lerna:run lint
|
||||
```
|
||||
@@ -87,11 +93,13 @@ yarn lerna:run lint
|
||||
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
|
||||
@@ -99,6 +107,7 @@ cd ..
|
||||
```
|
||||
|
||||
And finally from the root project directory run
|
||||
|
||||
```bash
|
||||
yarn lerna:run test
|
||||
```
|
||||
|
@@ -1,8 +1,6 @@
|
||||
{
|
||||
"lerna": "2.5.1",
|
||||
"packages": [
|
||||
"packages/*"
|
||||
],
|
||||
"packages": ["packages/*"],
|
||||
"version": "independent",
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true
|
||||
|
10
package.json
10
package.json
@@ -1,14 +1,15 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "0x.js",
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
],
|
||||
"workspaces": ["packages/*"],
|
||||
"scripts": {
|
||||
"testrpc": "testrpc -p 8545 --networkId 50 -m \"${npm_package_config_mnemonic}\"",
|
||||
"prettier": "prettier --write '**/*.{ts,tsx,json,md}'",
|
||||
"prettier:ci": "prettier --list-different '**/*.{ts,tsx,json,md}'",
|
||||
"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/"
|
||||
"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"
|
||||
@@ -18,6 +19,7 @@
|
||||
"async-child-process": "^1.1.1",
|
||||
"ethereumjs-testrpc": "6.0.3",
|
||||
"lerna": "^2.5.1",
|
||||
"prettier": "1.9.2",
|
||||
"publish-release": "0xproject/publish-release",
|
||||
"semver-sort": "^0.0.4"
|
||||
}
|
||||
|
@@ -1,7 +1,22 @@
|
||||
# CHANGELOG
|
||||
|
||||
v0.28.0 - _December 20, 2017_
|
||||
------------------------
|
||||
## v0.30.0 - _January 17, 2018_
|
||||
|
||||
* Add an error parameter to the order watcher callback (#312)
|
||||
* Fix a bug making it impossible to catch some errors from awaitTransactionMinedAsync (#312)
|
||||
* Fix a bug in fillOrdersUpTo validation making it impossible to fill up to if user doesn't have enough balance to fully fill all the orders (#321)
|
||||
|
||||
## v0.29.1 - _January 11, 2018_
|
||||
|
||||
* Fixed bignumber config issue #301 (#305)
|
||||
|
||||
## v0.29.0 - _December 28, 2017_
|
||||
|
||||
* Assert baseUnit amount supplied to `toUnitAmount` is integer amount. (#287)
|
||||
* `toBaseUnitAmount` throws if amount supplied has too many decimals (#287)
|
||||
|
||||
## v0.28.0 - _December 20, 2017_
|
||||
|
||||
* Add `etherTokenAddress` arg to `depositAsync` and `withdrawAsync` methods on `zeroEx.etherToken` (#267)
|
||||
* Removed accidentally included `unsubscribeAll` method from `zeroEx.proxy`, `zeroEx.etherToken` and `zeroEx.tokenRegistry` (#267)
|
||||
* Removed `etherTokenContractAddress` from `ZeroEx` constructor arg `ZeroExConfig` (#267)
|
||||
@@ -12,12 +27,12 @@ v0.28.0 - _December 20, 2017_
|
||||
* 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_
|
||||
------------------------
|
||||
## v0.27.1 - _November 28, 2017_
|
||||
|
||||
* Export `TransactionOpts` type
|
||||
|
||||
v0.27.0 - _November 28, 2017_
|
||||
------------------------
|
||||
## v0.27.0 - _November 28, 2017_
|
||||
|
||||
* Make `ZeroExConfig` required parameter of `ZeroEx` constructor (#233)
|
||||
* Add a required property `networkId` to `ZeroExConfig` (#233)
|
||||
* Make all `getContractAddress` functions, `zeroEx.exchange.subscribe`, `zeroEx.exchange.getZRXTokenAddress` sync (#233)
|
||||
@@ -28,66 +43,66 @@ v0.27.0 - _November 28, 2017_
|
||||
* All transaction sending methods now call `estimateGas` if no gas amount was supplied (#235)
|
||||
* Modify order validation methods to validate against the `latest` block, not against the `pending` block (#236)
|
||||
|
||||
v0.26.0 - _November 21, 2017_
|
||||
------------------------
|
||||
## v0.26.0 - _November 21, 2017_
|
||||
|
||||
* Add post-formatter for logs converting `blockNumber`, `logIndex`, `transactionIndex` from hexes to numbers (#231)
|
||||
* Remove support for Async callback types when used in Subscribe functions (#222)
|
||||
* In OrderWatcher subscribe to ZRX Token Transfer and Approval events when maker token is different (#225)
|
||||
|
||||
v0.25.1 - _November 13, 2017_
|
||||
------------------------
|
||||
## v0.25.1 - _November 13, 2017_
|
||||
|
||||
* Standardise on Cancelled over Canceled (#217)
|
||||
* Add missing `DecodedLogEvent` type to exported types (#205)
|
||||
* Normalized the transactionReceipt status to be `null|0|1`, 1 meaning transaction execution successful, 0 unsuccessful and `null` if it is a pre-byzantinium transaction. (#200)
|
||||
|
||||
v0.23.0 - _November 12, 2017_
|
||||
------------------------
|
||||
## v0.23.0 - _November 12, 2017_
|
||||
|
||||
* Fixed unhandled promise rejection error in subscribe methods (#209)
|
||||
* Subscribe callbacks now receive an error object as their first argument
|
||||
|
||||
v0.22.6 - _November 10, 2017_
|
||||
------------------------
|
||||
## v0.22.6 - _November 10, 2017_
|
||||
|
||||
* Add a timeout parameter to transaction awaiting (#206)
|
||||
|
||||
v0.22.5 - _November 7, 2017_
|
||||
------------------------
|
||||
## v0.22.5 - _November 7, 2017_
|
||||
|
||||
* Re-publish v0.22.4 to fix publishing issue
|
||||
|
||||
v0.22.4 - _October 25, 2017_
|
||||
------------------------
|
||||
## v0.22.4 - _October 25, 2017_
|
||||
|
||||
* Upgraded bignumber.js to a new version that ships with native typings
|
||||
|
||||
v0.22.3 - _October 25, 2017_
|
||||
------------------------
|
||||
## v0.22.3 - _October 25, 2017_
|
||||
|
||||
* Fixed an issue with new version of testrpc and unlimited proxy allowance (#199)
|
||||
|
||||
v0.22.2 - _October 24, 2017_
|
||||
------------------------
|
||||
## v0.22.2 - _October 24, 2017_
|
||||
|
||||
* Fixed rounding of maker fill amount and incorrect validation of partial fees (#197)
|
||||
|
||||
v0.22.0 - _October 16, 2017_
|
||||
------------------------
|
||||
## v0.22.0 - _October 16, 2017_
|
||||
|
||||
* Started using `OrderFillRequest` interface instead of `OrderFillOrKillRequest` interface for `zeroEx.exchange.batchFillOrKill` (#187)
|
||||
* Removed `OrderFillOrKillRequest` (#187)
|
||||
|
||||
v0.21.4 - _October 13, 2017_
|
||||
------------------------
|
||||
## v0.21.4 - _October 13, 2017_
|
||||
|
||||
* Made 0x.js more type-safe by making `getLogsAsync` and `subscribe/subscribeAsync` generics parametrized with arg type (#194)
|
||||
|
||||
v0.21.3 - _October 12, 2017_
|
||||
------------------------
|
||||
## v0.21.3 - _October 12, 2017_
|
||||
|
||||
* Fixed a bug causing order fills to throw `INSUFFICIENT_TAKER_ALLOWANCE` (#193)
|
||||
|
||||
v0.21.2 - _October 11, 2017_
|
||||
------------------------
|
||||
## v0.21.2 - _October 11, 2017_
|
||||
|
||||
* Exported `ContractEventArg` as a public type (#190)
|
||||
|
||||
v0.21.1 - _October 11, 2017_
|
||||
------------------------
|
||||
## v0.21.1 - _October 11, 2017_
|
||||
|
||||
* Fixed a bug in subscriptions (#189)
|
||||
|
||||
v0.21.0 - _October 10, 2017_
|
||||
------------------------
|
||||
## v0.21.0 - _October 10, 2017_
|
||||
|
||||
* Complete rewrite of subscription logic (#182)
|
||||
* Subscriptions no longer return historical logs. If you want them - use `getLogsAsync`
|
||||
* Subscriptions now use [ethereumjs-blockstream](https://github.com/ethereumjs/ethereumjs-blockstream) under the hood
|
||||
@@ -101,77 +116,77 @@ v0.21.0 - _October 10, 2017_
|
||||
* Renamed `zeroEx.token.stopWatchingAllEventsAsync` to `zeroEx.token.unsubscribeAll`
|
||||
* Fixed the batch fills validation by emulating all balance & proxy allowance changes (#185)
|
||||
|
||||
v0.20.0 - _October 5, 2017_
|
||||
------------------------
|
||||
## v0.20.0 - _October 5, 2017_
|
||||
|
||||
* Add `zeroEx.token.getLogsAsync` (#178)
|
||||
* Add `zeroEx.exchange.getLogsAsync` (#178)
|
||||
* Fixed fees validation when one of the tokens transferred is ZRX (#181)
|
||||
|
||||
v0.19.0 - _September 29, 2017_
|
||||
------------------------
|
||||
## v0.19.0 - _September 29, 2017_
|
||||
|
||||
* Made order validation optional (#172)
|
||||
* Added Ropsten testnet support (#173)
|
||||
* Fixed a bug causing awaitTransactionMinedAsync to DDos backend nodes (#175)
|
||||
|
||||
v0.18.0 - _September 26, 2017_
|
||||
------------------------
|
||||
## v0.18.0 - _September 26, 2017_
|
||||
|
||||
* Added `zeroEx.exchange.validateOrderFillableOrThrowAsync` to simplify orderbook pruning (#170)
|
||||
|
||||
v0.17.0 - _September 26, 2017_
|
||||
------------------------
|
||||
## v0.17.0 - _September 26, 2017_
|
||||
|
||||
* Made `zeroEx.exchange.getZRXTokenAddressAsync` public (#171)
|
||||
|
||||
v0.16.0 - _September 20, 2017_
|
||||
------------------------
|
||||
## v0.16.0 - _September 20, 2017_
|
||||
|
||||
* Added the ability to specify custom contract addresses to be used with 0x.js (#165)
|
||||
* ZeroExConfig.exchangeContractAddress
|
||||
* ZeroExConfig.tokenRegistryContractAddress
|
||||
* ZeroExConfig.etherTokenContractAddress
|
||||
* Added `zeroEx.tokenRegistry.getContractAddressAsync` (#165)
|
||||
|
||||
v0.15.0 - _September 8, 2017_
|
||||
------------------------
|
||||
## v0.15.0 - _September 8, 2017_
|
||||
|
||||
* Added the ability to specify a historical `blockNumber` at which to query the blockchain's state when calling a token or exchange method (#161)
|
||||
|
||||
v0.14.2 - _September 7, 2017_
|
||||
------------------------
|
||||
## v0.14.2 - _September 7, 2017_
|
||||
|
||||
* Fixed an issue with bignumber.js types not found (#160)
|
||||
|
||||
v0.14.1 - _September 7, 2017_
|
||||
------------------------
|
||||
## v0.14.1 - _September 7, 2017_
|
||||
|
||||
* Fixed an issue with Artifact type not found (#159)
|
||||
|
||||
v0.14.0 - _September 6, 2017_
|
||||
------------------------
|
||||
## v0.14.0 - _September 6, 2017_
|
||||
|
||||
* Added `zeroEx.exchange.throwLogErrorsAsErrors` method to public interface (#157)
|
||||
* Fixed an issue with overlapping async intervals in `zeroEx.awaitTransactionMinedAsync` (#157)
|
||||
* Fixed an issue with log decoder returning `BigNumber`s as `strings` (#157)
|
||||
|
||||
v0.13.0 - _September 6, 2017_
|
||||
------------------------
|
||||
## v0.13.0 - _September 6, 2017_
|
||||
|
||||
* Made all the functions submitting transactions to the network to immediately return transaction hash (#151)
|
||||
* Added `zeroEx.awaitTransactionMinedAsync` (#151)
|
||||
* Added `TransactionReceiptWithDecodedLogs`, `LogWithDecodedArgs`, `DecodedLogArgs` to public types (#151)
|
||||
* Added signature validation to `validateFillOrderThrowIfInvalidAsync` (#152)
|
||||
|
||||
v0.12.1 - _September 2, 2017_
|
||||
------------------------
|
||||
## v0.12.1 - _September 2, 2017_
|
||||
|
||||
* Added the support for web3@1.x.x provider (#142)
|
||||
* Added the optional `zeroExConfig` parameter to the constructor of `ZeroEx` (#139)
|
||||
* Added the ability to specify `gasPrice` when instantiating `ZeroEx` (#139)
|
||||
|
||||
v0.11.0 - _August 24, 2017_
|
||||
------------------------
|
||||
## v0.11.0 - _August 24, 2017_
|
||||
|
||||
* Added `zeroEx.token.setUnlimitedProxyAllowanceAsync` (#137)
|
||||
* Added `zeroEx.token.setUnlimitedAllowanceAsync` (#137)
|
||||
* Added `zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS` (#137)
|
||||
|
||||
v0.10.4 - _Aug 24, 2017_
|
||||
------------------------
|
||||
## v0.10.4 - _Aug 24, 2017_
|
||||
|
||||
* Fixed a bug where checksummed addresses were being pulled from artifacts and not lower-cased. (#135)
|
||||
|
||||
v0.10.1 - _Aug 24, 2017_
|
||||
------------------------
|
||||
## v0.10.1 - _Aug 24, 2017_
|
||||
|
||||
* Added `zeroEx.exchange.validateFillOrderThrowIfInvalidAsync` (#128)
|
||||
* Added `zeroEx.exchange.validateFillOrKillOrderThrowIfInvalidAsync` (#128)
|
||||
* Added `zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync` (#128)
|
||||
@@ -185,21 +200,21 @@ v0.10.1 - _Aug 24, 2017_
|
||||
* Added clear error message when checksummed address is passed to a public method (#124)
|
||||
* Fixes the description of `shouldThrowOnInsufficientBalanceOrAllowance` in docs (#127)
|
||||
|
||||
v0.9.3 - _Aug 22, 2017_
|
||||
------------------------
|
||||
## v0.9.3 - _Aug 22, 2017_
|
||||
|
||||
* Update contract artifacts to include latest Kovan and Mainnet deploys (#118)
|
||||
|
||||
v0.9.2 - _Aug 21, 2017_
|
||||
------------------------
|
||||
## v0.9.2 - _Aug 21, 2017_
|
||||
|
||||
* *This version was unpublished because of a publishing issue.*
|
||||
* Update contract artifacts to include latest Kovan and Mainnet deploys (#118)
|
||||
|
||||
v0.9.1 - _Aug. 16, 2017_
|
||||
------------------------
|
||||
## v0.9.1 - _Aug. 16, 2017_
|
||||
|
||||
* Fixed the bug causing `zeroEx.token.getBalanceAsync()` to fail if no addresses available (#120)
|
||||
|
||||
v0.9.0 - _Jul. 26, 2017_
|
||||
------------------------
|
||||
## v0.9.0 - _Jul. 26, 2017_
|
||||
|
||||
* Migrated to the new version of smart contracts (#101)
|
||||
* Removed the ability to call methods on multiple authorized Exchange smart contracts (#106)
|
||||
* Made `zeroEx.getOrderHashHex` a static method (#107)
|
||||
@@ -209,8 +224,8 @@ v0.9.0 - _Jul. 26, 2017_
|
||||
* Updated to typescript v2.4 (#104)
|
||||
* Fixed an issue with incorrect balance/allowance validation when ZRX is one of the tokens traded (#109)
|
||||
|
||||
v0.8.0 - _Jul. 4, 2017_
|
||||
------------------------
|
||||
## v0.8.0 - _Jul. 4, 2017_
|
||||
|
||||
* Added the ability to call methods on different authorized versions of the Exchange smart contract (#82)
|
||||
* Updated contract artifacts to reflect latest changes to the smart contracts (0xproject/contracts#59)
|
||||
* Added `zeroEx.proxy.isAuthorizedAsync` and `zeroEx.proxy.getAuthorizedAddressesAsync` (#89)
|
||||
@@ -222,35 +237,35 @@ v0.8.0 - _Jul. 4, 2017_
|
||||
* `zeroEx.tokenRegistry.invalidateContractInstance`
|
||||
* Fixed the bug where `zeroEx.setProviderAsync` didn't invalidate etherToken contract's instance
|
||||
|
||||
v0.7.1 - _Jun. 26, 2017_
|
||||
------------------------
|
||||
## v0.7.1 - _Jun. 26, 2017_
|
||||
|
||||
* Added the ability to convert Ether to wrapped Ether tokens and back via `zeroEx.etherToken.depostAsync` and `zeroEx.etherToken.withdrawAsync` (#81)
|
||||
|
||||
v0.7.0 - _Jun. 22, 2017_
|
||||
------------------------
|
||||
## v0.7.0 - _Jun. 22, 2017_
|
||||
|
||||
* Added Kovan smart contract artifacts (#78)
|
||||
* Started returning fillAmount from `fillOrderAsync` and `fillUpToAsync` (#72)
|
||||
* Started returning cancelledAmount from `cancelOrderAsync` (#72)
|
||||
* Renamed type `LogCancelArgs` to `LogCancelContractEventArgs` and `LogFillArgs` to `LogFillContractEventArgs`
|
||||
|
||||
v0.6.2 - _Jun. 21, 2017_
|
||||
------------------------
|
||||
## v0.6.2 - _Jun. 21, 2017_
|
||||
|
||||
* Reduced bundle size
|
||||
* Improved documentation
|
||||
|
||||
v0.6.1 - _Jun. 19, 2017_
|
||||
------------------------
|
||||
## v0.6.1 - _Jun. 19, 2017_
|
||||
|
||||
* Improved documentation
|
||||
|
||||
v0.6.0 - _Jun. 19, 2017_
|
||||
------------------------
|
||||
## v0.6.0 - _Jun. 19, 2017_
|
||||
|
||||
* Made `ZeroEx` class accept `Web3Provider` instance instead of `Web3` instance
|
||||
* Added types for contract event arguments
|
||||
|
||||
v0.5.2 - _Jun. 15, 2017_
|
||||
------------------------
|
||||
## v0.5.2 - _Jun. 15, 2017_
|
||||
|
||||
* Fixed the bug in `postpublish` script that caused that only unminified UMD bundle was uploaded to release page
|
||||
|
||||
v0.5.1 - _Jun. 15, 2017_
|
||||
------------------------
|
||||
## v0.5.1 - _Jun. 15, 2017_
|
||||
|
||||
* Added `postpublish` script to publish to Github Releases with assets.
|
||||
|
@@ -1,11 +1,10 @@
|
||||
0x.js
|
||||
-----
|
||||
## 0x.js
|
||||
|
||||
## Installation
|
||||
|
||||
0x.js ships as both a [UMD](https://github.com/umdjs/umd) module and a [CommonJS](https://en.wikipedia.org/wiki/CommonJS) package.
|
||||
|
||||
#### CommonJS *(recommended)*:
|
||||
#### CommonJS _(recommended)_:
|
||||
|
||||
**Install**
|
||||
|
||||
|
@@ -4,8 +4,7 @@
|
||||
*/
|
||||
// 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 { BigNumber, classUtils, promisify } from '@0xproject/utils';
|
||||
import * as Web3 from 'web3';
|
||||
|
||||
import {BaseContract} from './base_contract';
|
||||
|
@@ -1,29 +1,27 @@
|
||||
{
|
||||
"name": "0x.js",
|
||||
"version": "0.27.2",
|
||||
"version": "0.29.2",
|
||||
"description": "A javascript library for interacting with the 0x protocol",
|
||||
"keywords": [
|
||||
"0x.js",
|
||||
"0xproject",
|
||||
"ethereum",
|
||||
"tokens",
|
||||
"exchange"
|
||||
],
|
||||
"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",
|
||||
"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: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;",
|
||||
"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",
|
||||
@@ -45,10 +43,10 @@
|
||||
"node": ">=6.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0xproject/abi-gen": "^0.0.2",
|
||||
"@0xproject/tslint-config": "^0.2.1",
|
||||
"@0xproject/types": "^0.1.0",
|
||||
"@0xproject/dev-utils": "^0.0.1",
|
||||
"@0xproject/abi-gen": "^0.1.1",
|
||||
"@0xproject/dev-utils": "^0.0.4",
|
||||
"@0xproject/tslint-config": "^0.4.1",
|
||||
"@0xproject/types": "^0.1.3",
|
||||
"@types/bintrees": "^1.0.2",
|
||||
"@types/jsonschema": "^1.1.1",
|
||||
"@types/lodash": "^4.14.86",
|
||||
@@ -80,15 +78,14 @@
|
||||
"typedoc": "~0.8.0",
|
||||
"typescript": "~2.6.1",
|
||||
"web3-provider-engine": "^13.0.1",
|
||||
"web3-typescript-typings": "^0.7.2",
|
||||
"web3-typescript-typings": "^0.9.3",
|
||||
"webpack": "^3.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/assert": "^0.0.7",
|
||||
"@0xproject/json-schemas": "^0.6.10",
|
||||
"@0xproject/utils": "^0.1.0",
|
||||
"@0xproject/web3-wrapper": "^0.1.0",
|
||||
"bignumber.js": "~4.1.0",
|
||||
"@0xproject/assert": "^0.0.10",
|
||||
"@0xproject/json-schemas": "^0.7.2",
|
||||
"@0xproject/utils": "^0.1.3",
|
||||
"@0xproject/web3-wrapper": "^0.1.4",
|
||||
"bintrees": "^1.0.2",
|
||||
"bn.js": "^4.11.8",
|
||||
"compare-versions": "^3.0.1",
|
||||
|
@@ -8,26 +8,21 @@ const S3BucketPath = 's3://0xjs-docs-jsons/';
|
||||
|
||||
let tag;
|
||||
let version;
|
||||
postpublish_utils.getLatestTagAndVersionAsync(subPackageName)
|
||||
postpublish_utils
|
||||
.getLatestTagAndVersionAsync(subPackageName)
|
||||
.then(function(result) {
|
||||
tag = result.tag;
|
||||
version = result.version;
|
||||
const releaseName = postpublish_utils.getReleaseName(subPackageName, version);
|
||||
const assets = [
|
||||
__dirname + '/../_bundles/index.js',
|
||||
__dirname + '/../_bundles/index.min.js',
|
||||
];
|
||||
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',
|
||||
{
|
||||
return execAsync('JSON_FILE_PATH=' + jsonFilePath + ' PROJECT_DIR=' + __dirname + '/.. yarn docs:json', {
|
||||
cwd,
|
||||
}
|
||||
);
|
||||
});
|
||||
})
|
||||
.then(function(result) {
|
||||
if (result.stderr !== '') {
|
||||
@@ -39,6 +34,7 @@ postpublish_utils.getLatestTagAndVersionAsync(subPackageName)
|
||||
return execAsync('S3_URL=' + s3Url + ' yarn upload_docs_json', {
|
||||
cwd,
|
||||
});
|
||||
}).catch (function(err) {
|
||||
})
|
||||
.catch(function(err) {
|
||||
throw err;
|
||||
});
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import { schemas, SchemaValidator } from '@0xproject/json-schemas';
|
||||
import {bigNumberConfigs, intervalUtils} from '@0xproject/utils';
|
||||
import { BigNumber, 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';
|
||||
|
||||
@@ -29,9 +28,6 @@ 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.
|
||||
@@ -128,7 +124,7 @@ export class ZeroEx {
|
||||
* @return The amount in units.
|
||||
*/
|
||||
public static toUnitAmount(amount: BigNumber, decimals: number): BigNumber {
|
||||
assert.isBigNumber('amount', amount);
|
||||
assert.isValidBaseUnitAmount('amount', amount);
|
||||
assert.isNumber('decimals', decimals);
|
||||
|
||||
const aUnit = new BigNumber(10).pow(decimals);
|
||||
@@ -149,6 +145,10 @@ export class ZeroEx {
|
||||
|
||||
const unit = new BigNumber(10).pow(decimals);
|
||||
const baseUnitAmount = amount.times(unit);
|
||||
const hasDecimals = baseUnitAmount.decimalPlaces() !== 0;
|
||||
if (hasDecimals) {
|
||||
throw new Error(`Invalid unit amount: ${amount.toString()} - Too many decimal places`);
|
||||
}
|
||||
return baseUnitAmount;
|
||||
}
|
||||
/**
|
||||
@@ -184,12 +184,7 @@ export class ZeroEx {
|
||||
config.networkId,
|
||||
config.tokenTransferProxyContractAddress,
|
||||
);
|
||||
this.token = new TokenWrapper(
|
||||
this._web3Wrapper,
|
||||
config.networkId,
|
||||
this._abiDecoder,
|
||||
this.proxy,
|
||||
);
|
||||
this.token = new TokenWrapper(this._web3Wrapper, config.networkId, this._abiDecoder, this.proxy);
|
||||
this.exchange = new ExchangeWrapper(
|
||||
this._web3Wrapper,
|
||||
config.networkId,
|
||||
@@ -198,13 +193,17 @@ export class ZeroEx {
|
||||
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._web3Wrapper,
|
||||
config.networkId,
|
||||
config.tokenRegistryContractAddress,
|
||||
);
|
||||
this.etherToken = new EtherTokenWrapper(this._web3Wrapper, config.networkId, this._abiDecoder, this.token);
|
||||
this.orderStateWatcher = new OrderStateWatcher(
|
||||
this._web3Wrapper, this._abiDecoder, this.token, this.exchange, config.orderWatcherConfig,
|
||||
this._web3Wrapper,
|
||||
this._abiDecoder,
|
||||
this.token,
|
||||
this.exchange,
|
||||
config.orderWatcherConfig,
|
||||
);
|
||||
}
|
||||
/**
|
||||
@@ -214,12 +213,17 @@ export class ZeroEx {
|
||||
* @param networkId The id of the network your provider is connected to
|
||||
*/
|
||||
public setProvider(provider: Web3Provider, networkId: number): void {
|
||||
this._web3Wrapper.setProvider(provider, networkId);
|
||||
this._web3Wrapper.setProvider(provider);
|
||||
(this.exchange as any)._invalidateContractInstances();
|
||||
(this.exchange as any)._setNetworkId(networkId);
|
||||
(this.tokenRegistry as any)._invalidateContractInstance();
|
||||
(this.tokenRegistry as any)._setNetworkId(networkId);
|
||||
(this.token as any)._invalidateContractInstances();
|
||||
(this.token as any)._setNetworkId(networkId);
|
||||
(this.proxy as any)._invalidateContractInstance();
|
||||
(this.proxy as any)._setNetworkId(networkId);
|
||||
(this.etherToken as any)._invalidateContractInstance();
|
||||
(this.etherToken as any)._setNetworkId(networkId);
|
||||
}
|
||||
/**
|
||||
* Get user Ethereum addresses available through the supplied web3 provider available for sending transactions.
|
||||
@@ -287,15 +291,19 @@ export class ZeroEx {
|
||||
* @return Transaction receipt with decoded log args.
|
||||
*/
|
||||
public async awaitTransactionMinedAsync(
|
||||
txHash: string, pollingIntervalMs = 1000, timeoutMs?: number): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
txHash: string,
|
||||
pollingIntervalMs = 1000,
|
||||
timeoutMs?: number,
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
let timeoutExceeded = false;
|
||||
if (timeoutMs) {
|
||||
setTimeout(() => timeoutExceeded = true, timeoutMs);
|
||||
setTimeout(() => (timeoutExceeded = true), timeoutMs);
|
||||
}
|
||||
|
||||
const txReceiptPromise = new Promise(
|
||||
(resolve: (receipt: TransactionReceiptWithDecodedLogs) => void, reject) => {
|
||||
const intervalId = intervalUtils.setAsyncExcludingInterval(async () => {
|
||||
const intervalId = intervalUtils.setAsyncExcludingInterval(
|
||||
async () => {
|
||||
if (timeoutExceeded) {
|
||||
intervalUtils.clearAsyncExcludingInterval(intervalId);
|
||||
return reject(ZeroExError.TransactionMiningTimeout);
|
||||
@@ -314,8 +322,15 @@ export class ZeroEx {
|
||||
};
|
||||
resolve(transactionReceiptWithDecodedLogArgs);
|
||||
}
|
||||
}, pollingIntervalMs);
|
||||
});
|
||||
},
|
||||
pollingIntervalMs,
|
||||
(err: Error) => {
|
||||
intervalUtils.clearAsyncExcludingInterval(intervalId);
|
||||
reject(err);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
return txReceiptPromise;
|
||||
}
|
||||
|
@@ -8,11 +8,11 @@ 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,
|
||||
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,
|
||||
};
|
||||
|
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"contract_name": "DummyToken",
|
||||
"abi":
|
||||
[
|
||||
"abi": [
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
|
@@ -21,7 +21,9 @@ import {AbiDecoder} from '../utils/abi_decoder';
|
||||
import { constants } from '../utils/constants';
|
||||
import { filterUtils } from '../utils/filter_utils';
|
||||
|
||||
const CONTRACT_NAME_TO_NOT_FOUND_ERROR: {[contractName: string]: ZeroExError} = {
|
||||
const CONTRACT_NAME_TO_NOT_FOUND_ERROR: {
|
||||
[contractName: string]: ZeroExError;
|
||||
} = {
|
||||
ZRX: ZeroExError.ZRXContractDoesNotExist,
|
||||
EtherToken: ZeroExError.EtherTokenContractDoesNotExist,
|
||||
Token: ZeroExError.TokenContractDoesNotExist,
|
||||
@@ -37,7 +39,9 @@ export class ContractWrapper {
|
||||
private _blockAndLogStreamerIfExists: BlockAndLogStreamer | undefined;
|
||||
private _blockAndLogStreamInterval: NodeJS.Timer;
|
||||
private _filters: { [filterToken: string]: Web3.FilterObject };
|
||||
private _filterCallbacks: {[filterToken: string]: EventCallback<ContractEventArgs>};
|
||||
private _filterCallbacks: {
|
||||
[filterToken: string]: EventCallback<ContractEventArgs>;
|
||||
};
|
||||
private _onLogAddedSubscriptionToken: string | undefined;
|
||||
private _onLogRemovedSubscriptionToken: string | undefined;
|
||||
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder?: AbiDecoder) {
|
||||
@@ -71,27 +75,36 @@ export class ContractWrapper {
|
||||
}
|
||||
}
|
||||
protected _subscribe<ArgsType extends ContractEventArgs>(
|
||||
address: string, eventName: ContractEvents, indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi,
|
||||
callback: EventCallback<ArgsType>): string {
|
||||
address: string,
|
||||
eventName: ContractEvents,
|
||||
indexFilterValues: IndexedFilterValues,
|
||||
abi: Web3.ContractAbi,
|
||||
callback: EventCallback<ArgsType>,
|
||||
): string {
|
||||
const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi);
|
||||
if (_.isUndefined(this._blockAndLogStreamerIfExists)) {
|
||||
this._startBlockAndLogStream();
|
||||
}
|
||||
const filterToken = filterUtils.generateUUID();
|
||||
this._filters[filterToken] = filter;
|
||||
this._filterCallbacks[filterToken] = callback;
|
||||
this._filterCallbacks[filterToken] = callback as EventCallback<ContractEventArgs>;
|
||||
return filterToken;
|
||||
}
|
||||
protected async _getLogsAsync<ArgsType extends ContractEventArgs>(
|
||||
address: string, eventName: ContractEvents, blockRange: BlockRange,
|
||||
indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
|
||||
address: string,
|
||||
eventName: ContractEvents,
|
||||
blockRange: BlockRange,
|
||||
indexFilterValues: IndexedFilterValues,
|
||||
abi: Web3.ContractAbi,
|
||||
): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
|
||||
const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi, blockRange);
|
||||
const logs = await this._web3Wrapper.getLogsAsync(filter);
|
||||
const logsWithDecodedArguments = _.map(logs, this._tryToDecodeLogOrNoop.bind(this));
|
||||
return logsWithDecodedArguments;
|
||||
}
|
||||
protected _tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>(
|
||||
log: Web3.LogEntry): LogWithDecodedArgs<ArgsType>|RawLog {
|
||||
log: Web3.LogEntry,
|
||||
): LogWithDecodedArgs<ArgsType> | RawLog {
|
||||
if (_.isUndefined(this._abiDecoder)) {
|
||||
throw new Error(InternalZeroExError.NoAbiDecoder);
|
||||
}
|
||||
@@ -99,7 +112,8 @@ export class ContractWrapper {
|
||||
return logWithDecodedArgs;
|
||||
}
|
||||
protected async _instantiateContractIfExistsAsync(
|
||||
artifact: Artifact, addressIfExists?: string,
|
||||
artifact: Artifact,
|
||||
addressIfExists?: string,
|
||||
): Promise<Web3.ContractInstance> {
|
||||
let contractAddress: string;
|
||||
if (_.isUndefined(addressIfExists)) {
|
||||
@@ -114,9 +128,7 @@ export class ContractWrapper {
|
||||
if (!doesContractExist) {
|
||||
throw new Error(CONTRACT_NAME_TO_NOT_FOUND_ERROR[artifact.contract_name]);
|
||||
}
|
||||
const contractInstance = this._web3Wrapper.getContractInstance(
|
||||
artifact.abi, contractAddress,
|
||||
);
|
||||
const contractInstance = this._web3Wrapper.getContractInstance(artifact.abi, contractAddress);
|
||||
return contractInstance;
|
||||
}
|
||||
protected _getContractAddress(artifact: Artifact, addressIfExists?: string): string {
|
||||
@@ -153,7 +165,9 @@ export class ContractWrapper {
|
||||
const catchAllLogFilter = {};
|
||||
this._blockAndLogStreamerIfExists.addLogFilter(catchAllLogFilter);
|
||||
this._blockAndLogStreamInterval = intervalUtils.setAsyncExcludingInterval(
|
||||
this._reconcileBlockAsync.bind(this), constants.DEFAULT_BLOCK_POLLING_INTERVAL,
|
||||
this._reconcileBlockAsync.bind(this),
|
||||
constants.DEFAULT_BLOCK_POLLING_INTERVAL,
|
||||
this._onReconcileBlockError.bind(this),
|
||||
);
|
||||
let isRemoved = false;
|
||||
this._onLogAddedSubscriptionToken = this._blockAndLogStreamerIfExists.subscribeToOnLogAdded(
|
||||
@@ -164,6 +178,15 @@ export class ContractWrapper {
|
||||
this._onLogStateChanged.bind(this, isRemoved),
|
||||
);
|
||||
}
|
||||
private _onReconcileBlockError(err: Error): void {
|
||||
const filterTokens = _.keys(this._filterCallbacks);
|
||||
_.each(filterTokens, filterToken => {
|
||||
this._unsubscribe(filterToken, err);
|
||||
});
|
||||
}
|
||||
private _setNetworkId(networkId: number): void {
|
||||
this._networkId = networkId;
|
||||
}
|
||||
private _stopBlockAndLogStream(): void {
|
||||
if (_.isUndefined(this._blockAndLogStreamerIfExists)) {
|
||||
throw new Error(ZeroExError.SubscriptionNotFound);
|
||||
@@ -174,18 +197,11 @@ export class ContractWrapper {
|
||||
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);
|
||||
});
|
||||
await this._blockAndLogStreamerIfExists.reconcileNewBlock((latestBlock as any) as Block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { schemas } from '@0xproject/json-schemas';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from '../artifacts';
|
||||
@@ -26,7 +26,9 @@ import {TokenWrapper} from './token_wrapper';
|
||||
* 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 _etherTokenContractsByAddress: {
|
||||
[address: string]: EtherTokenContract;
|
||||
} = {};
|
||||
private _tokenWrapper: TokenWrapper;
|
||||
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder: AbiDecoder, tokenWrapper: TokenWrapper) {
|
||||
super(web3Wrapper, networkId, abiDecoder);
|
||||
@@ -43,7 +45,10 @@ export class EtherTokenWrapper extends ContractWrapper {
|
||||
* @return Transaction hash.
|
||||
*/
|
||||
public async depositAsync(
|
||||
etherTokenAddress: string, amountInWei: BigNumber, depositor: string, txOpts: TransactionOpts = {},
|
||||
etherTokenAddress: string,
|
||||
amountInWei: BigNumber,
|
||||
depositor: string,
|
||||
txOpts: TransactionOpts = {},
|
||||
): Promise<string> {
|
||||
assert.isValidBaseUnitAmount('amountInWei', amountInWei);
|
||||
await assert.isSenderAddressAsync('depositor', depositor, this._web3Wrapper);
|
||||
@@ -70,7 +75,10 @@ export class EtherTokenWrapper extends ContractWrapper {
|
||||
* @return Transaction hash.
|
||||
*/
|
||||
public async withdrawAsync(
|
||||
etherTokenAddress: string, amountInWei: BigNumber, withdrawer: string, txOpts: TransactionOpts = {},
|
||||
etherTokenAddress: string,
|
||||
amountInWei: BigNumber,
|
||||
withdrawer: string,
|
||||
txOpts: TransactionOpts = {},
|
||||
): Promise<string> {
|
||||
assert.isValidBaseUnitAmount('amountInWei', amountInWei);
|
||||
await assert.isSenderAddressAsync('withdrawer', withdrawer, this._web3Wrapper);
|
||||
@@ -96,14 +104,21 @@ export class EtherTokenWrapper extends ContractWrapper {
|
||||
* @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>>> {
|
||||
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,
|
||||
etherTokenAddress,
|
||||
eventName,
|
||||
blockRange,
|
||||
indexFilterValues,
|
||||
artifacts.EtherTokenArtifact.abi,
|
||||
);
|
||||
return logs;
|
||||
}
|
||||
@@ -117,14 +132,21 @@ export class EtherTokenWrapper extends ContractWrapper {
|
||||
* @return Subscription token used later to unsubscribe
|
||||
*/
|
||||
public subscribe<ArgsType extends EtherTokenContractEventArgs>(
|
||||
etherTokenAddress: string, eventName: EtherTokenEvents, indexFilterValues: IndexedFilterValues,
|
||||
callback: EventCallback<ArgsType>): string {
|
||||
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,
|
||||
etherTokenAddress,
|
||||
eventName,
|
||||
indexFilterValues,
|
||||
artifacts.EtherTokenArtifact.abi,
|
||||
callback,
|
||||
);
|
||||
return subscriptionToken;
|
||||
}
|
||||
@@ -151,7 +173,8 @@ export class EtherTokenWrapper extends ContractWrapper {
|
||||
return etherTokenContract;
|
||||
}
|
||||
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
||||
artifacts.EtherTokenArtifact, etherTokenAddress,
|
||||
artifacts.EtherTokenArtifact,
|
||||
etherTokenAddress,
|
||||
);
|
||||
const contractInstance = new EtherTokenContract(web3ContractInstance, this._web3Wrapper.getContractDefaults());
|
||||
etherTokenContract = contractInstance;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { schemas } from '@0xproject/json-schemas';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import * as _ from 'lodash';
|
||||
import * as Web3 from 'web3';
|
||||
|
||||
@@ -81,8 +81,13 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
];
|
||||
return [orderAddresses, orderValues];
|
||||
}
|
||||
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder: AbiDecoder,
|
||||
tokenWrapper: TokenWrapper, contractAddressIfExists?: string) {
|
||||
constructor(
|
||||
web3Wrapper: Web3Wrapper,
|
||||
networkId: number,
|
||||
abiDecoder: AbiDecoder,
|
||||
tokenWrapper: TokenWrapper,
|
||||
contractAddressIfExists?: string,
|
||||
) {
|
||||
super(web3Wrapper, networkId, abiDecoder);
|
||||
this._tokenWrapper = tokenWrapper;
|
||||
this._orderValidationUtils = new OrderValidationUtils(this);
|
||||
@@ -97,14 +102,14 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
* @param methodOpts Optional arguments this method accepts.
|
||||
* @return The amount of the order (in taker tokens) that has either been filled or cancelled.
|
||||
*/
|
||||
public async getUnavailableTakerAmountAsync(orderHash: string,
|
||||
methodOpts?: MethodOpts): Promise<BigNumber> {
|
||||
public async getUnavailableTakerAmountAsync(orderHash: string, methodOpts?: MethodOpts): Promise<BigNumber> {
|
||||
assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
|
||||
|
||||
const exchangeContract = await this._getExchangeContractAsync();
|
||||
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
|
||||
let unavailableTakerTokenAmount = await exchangeContract.getUnavailableTakerTokenAmount.callAsync(
|
||||
orderHash, defaultBlock,
|
||||
orderHash,
|
||||
defaultBlock,
|
||||
);
|
||||
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
|
||||
unavailableTakerTokenAmount = new BigNumber(unavailableTakerTokenAmount);
|
||||
@@ -163,24 +168,32 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
* @return Transaction hash.
|
||||
*/
|
||||
@decorators.asyncZeroExErrorHandler
|
||||
public async fillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber,
|
||||
public async fillOrderAsync(
|
||||
signedOrder: SignedOrder,
|
||||
fillTakerTokenAmount: BigNumber,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
|
||||
takerAddress: string,
|
||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
||||
orderTransactionOpts: OrderTransactionOpts = {},
|
||||
): Promise<string> {
|
||||
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
||||
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
||||
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
|
||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||
|
||||
const exchangeInstance = await this._getExchangeContractAsync();
|
||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
|
||||
SHOULD_VALIDATE_BY_DEFAULT :
|
||||
orderTransactionOpts.shouldValidate;
|
||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
|
||||
? SHOULD_VALIDATE_BY_DEFAULT
|
||||
: orderTransactionOpts.shouldValidate;
|
||||
if (shouldValidate) {
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress);
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount,
|
||||
takerAddress,
|
||||
zrxTokenAddress,
|
||||
);
|
||||
}
|
||||
|
||||
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder);
|
||||
@@ -219,30 +232,44 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
* @return Transaction hash.
|
||||
*/
|
||||
@decorators.asyncZeroExErrorHandler
|
||||
public async fillOrdersUpToAsync(signedOrders: SignedOrder[], fillTakerTokenAmount: BigNumber,
|
||||
public async fillOrdersUpToAsync(
|
||||
signedOrders: SignedOrder[],
|
||||
fillTakerTokenAmount: BigNumber,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
|
||||
takerAddress: string,
|
||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
||||
orderTransactionOpts: OrderTransactionOpts = {},
|
||||
): Promise<string> {
|
||||
assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema);
|
||||
const takerTokenAddresses = _.map(signedOrders, signedOrder => signedOrder.takerTokenAddress);
|
||||
assert.hasAtMostOneUniqueValue(takerTokenAddresses,
|
||||
ExchangeContractErrs.MultipleTakerTokensInFillUpToDisallowed);
|
||||
assert.hasAtMostOneUniqueValue(
|
||||
takerTokenAddresses,
|
||||
ExchangeContractErrs.MultipleTakerTokensInFillUpToDisallowed,
|
||||
);
|
||||
const exchangeContractAddresses = _.map(signedOrders, signedOrder => signedOrder.exchangeContractAddress);
|
||||
assert.hasAtMostOneUniqueValue(exchangeContractAddresses,
|
||||
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress);
|
||||
assert.hasAtMostOneUniqueValue(
|
||||
exchangeContractAddresses,
|
||||
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
|
||||
);
|
||||
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
||||
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
|
||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||
|
||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
|
||||
SHOULD_VALIDATE_BY_DEFAULT :
|
||||
orderTransactionOpts.shouldValidate;
|
||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
|
||||
? SHOULD_VALIDATE_BY_DEFAULT
|
||||
: orderTransactionOpts.shouldValidate;
|
||||
if (shouldValidate) {
|
||||
let filledTakerTokenAmount = new BigNumber(0);
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
for (const signedOrder of signedOrders) {
|
||||
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress);
|
||||
const singleFilledTakerTokenAmount = await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount.minus(filledTakerTokenAmount),
|
||||
takerAddress,
|
||||
zrxTokenAddress,
|
||||
);
|
||||
filledTakerTokenAmount = filledTakerTokenAmount.plus(singleFilledTakerTokenAmount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,29 +327,36 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
* @return Transaction hash.
|
||||
*/
|
||||
@decorators.asyncZeroExErrorHandler
|
||||
public async batchFillOrdersAsync(orderFillRequests: OrderFillRequest[],
|
||||
public async batchFillOrdersAsync(
|
||||
orderFillRequests: OrderFillRequest[],
|
||||
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
|
||||
takerAddress: string,
|
||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
||||
orderTransactionOpts: OrderTransactionOpts = {},
|
||||
): Promise<string> {
|
||||
assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema);
|
||||
const exchangeContractAddresses = _.map(
|
||||
orderFillRequests,
|
||||
orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress,
|
||||
);
|
||||
assert.hasAtMostOneUniqueValue(exchangeContractAddresses,
|
||||
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress);
|
||||
assert.hasAtMostOneUniqueValue(
|
||||
exchangeContractAddresses,
|
||||
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
|
||||
);
|
||||
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
|
||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
|
||||
SHOULD_VALIDATE_BY_DEFAULT :
|
||||
orderTransactionOpts.shouldValidate;
|
||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
|
||||
? SHOULD_VALIDATE_BY_DEFAULT
|
||||
: orderTransactionOpts.shouldValidate;
|
||||
if (shouldValidate) {
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
for (const orderFillRequest of orderFillRequests) {
|
||||
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator, orderFillRequest.signedOrder, orderFillRequest.takerTokenFillAmount,
|
||||
takerAddress, zrxTokenAddress,
|
||||
exchangeTradeEmulator,
|
||||
orderFillRequest.signedOrder,
|
||||
orderFillRequest.takerTokenFillAmount,
|
||||
takerAddress,
|
||||
zrxTokenAddress,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -373,23 +407,31 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
* @return Transaction hash.
|
||||
*/
|
||||
@decorators.asyncZeroExErrorHandler
|
||||
public async fillOrKillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber,
|
||||
public async fillOrKillOrderAsync(
|
||||
signedOrder: SignedOrder,
|
||||
fillTakerTokenAmount: BigNumber,
|
||||
takerAddress: string,
|
||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
||||
orderTransactionOpts: OrderTransactionOpts = {},
|
||||
): Promise<string> {
|
||||
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
||||
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||
|
||||
const exchangeInstance = await this._getExchangeContractAsync();
|
||||
|
||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
|
||||
SHOULD_VALIDATE_BY_DEFAULT :
|
||||
orderTransactionOpts.shouldValidate;
|
||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
|
||||
? SHOULD_VALIDATE_BY_DEFAULT
|
||||
: orderTransactionOpts.shouldValidate;
|
||||
if (shouldValidate) {
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress);
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount,
|
||||
takerAddress,
|
||||
zrxTokenAddress,
|
||||
);
|
||||
}
|
||||
|
||||
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder);
|
||||
@@ -418,33 +460,39 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
* @return Transaction hash.
|
||||
*/
|
||||
@decorators.asyncZeroExErrorHandler
|
||||
public async batchFillOrKillAsync(orderFillRequests: OrderFillRequest[],
|
||||
public async batchFillOrKillAsync(
|
||||
orderFillRequests: OrderFillRequest[],
|
||||
takerAddress: string,
|
||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
||||
assert.doesConformToSchema('orderFillRequests', orderFillRequests,
|
||||
schemas.orderFillRequestsSchema);
|
||||
orderTransactionOpts: OrderTransactionOpts = {},
|
||||
): Promise<string> {
|
||||
assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema);
|
||||
const exchangeContractAddresses = _.map(
|
||||
orderFillRequests,
|
||||
orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress,
|
||||
);
|
||||
assert.hasAtMostOneUniqueValue(exchangeContractAddresses,
|
||||
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress);
|
||||
assert.hasAtMostOneUniqueValue(
|
||||
exchangeContractAddresses,
|
||||
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
|
||||
);
|
||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||
if (_.isEmpty(orderFillRequests)) {
|
||||
throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
|
||||
}
|
||||
const exchangeInstance = await this._getExchangeContractAsync();
|
||||
|
||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
|
||||
SHOULD_VALIDATE_BY_DEFAULT :
|
||||
orderTransactionOpts.shouldValidate;
|
||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
|
||||
? SHOULD_VALIDATE_BY_DEFAULT
|
||||
: orderTransactionOpts.shouldValidate;
|
||||
if (shouldValidate) {
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
for (const orderFillRequest of orderFillRequests) {
|
||||
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator, orderFillRequest.signedOrder, orderFillRequest.takerTokenFillAmount,
|
||||
takerAddress, zrxTokenAddress,
|
||||
exchangeTradeEmulator,
|
||||
orderFillRequest.signedOrder,
|
||||
orderFillRequest.takerTokenFillAmount,
|
||||
takerAddress,
|
||||
zrxTokenAddress,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -460,8 +508,9 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
});
|
||||
|
||||
// We use _.unzip<any> because _.unzip doesn't type check if values have different types :'(
|
||||
const [orderAddresses, orderValues, fillTakerTokenAmounts, vParams, rParams, sParams] =
|
||||
_.unzip<any>(orderAddressesValuesAndTakerTokenFillAmounts);
|
||||
const [orderAddresses, orderValues, fillTakerTokenAmounts, vParams, rParams, sParams] = _.unzip<any>(
|
||||
orderAddressesValuesAndTakerTokenFillAmounts,
|
||||
);
|
||||
const txHash = await exchangeInstance.batchFillOrKillOrders.sendTransactionAsync(
|
||||
orderAddresses,
|
||||
orderValues,
|
||||
@@ -486,23 +535,28 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
* @return Transaction hash.
|
||||
*/
|
||||
@decorators.asyncZeroExErrorHandler
|
||||
public async cancelOrderAsync(order: Order|SignedOrder,
|
||||
public async cancelOrderAsync(
|
||||
order: Order | SignedOrder,
|
||||
cancelTakerTokenAmount: BigNumber,
|
||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
||||
orderTransactionOpts: OrderTransactionOpts = {},
|
||||
): Promise<string> {
|
||||
assert.doesConformToSchema('order', order, schemas.orderSchema);
|
||||
assert.isValidBaseUnitAmount('takerTokenCancelAmount', cancelTakerTokenAmount);
|
||||
await assert.isSenderAddressAsync('order.maker', order.maker, this._web3Wrapper);
|
||||
|
||||
const exchangeInstance = await this._getExchangeContractAsync();
|
||||
|
||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
|
||||
SHOULD_VALIDATE_BY_DEFAULT :
|
||||
orderTransactionOpts.shouldValidate;
|
||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
|
||||
? SHOULD_VALIDATE_BY_DEFAULT
|
||||
: orderTransactionOpts.shouldValidate;
|
||||
if (shouldValidate) {
|
||||
const orderHash = utils.getOrderHashHex(order);
|
||||
const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
|
||||
OrderValidationUtils.validateCancelOrderThrowIfInvalid(
|
||||
order, cancelTakerTokenAmount, unavailableTakerTokenAmount);
|
||||
order,
|
||||
cancelTakerTokenAmount,
|
||||
unavailableTakerTokenAmount,
|
||||
);
|
||||
}
|
||||
|
||||
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order);
|
||||
@@ -527,33 +581,40 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
* @return Transaction hash.
|
||||
*/
|
||||
@decorators.asyncZeroExErrorHandler
|
||||
public async batchCancelOrdersAsync(orderCancellationRequests: OrderCancellationRequest[],
|
||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
||||
assert.doesConformToSchema('orderCancellationRequests', orderCancellationRequests,
|
||||
schemas.orderCancellationRequestsSchema);
|
||||
public async batchCancelOrdersAsync(
|
||||
orderCancellationRequests: OrderCancellationRequest[],
|
||||
orderTransactionOpts: OrderTransactionOpts = {},
|
||||
): Promise<string> {
|
||||
assert.doesConformToSchema(
|
||||
'orderCancellationRequests',
|
||||
orderCancellationRequests,
|
||||
schemas.orderCancellationRequestsSchema,
|
||||
);
|
||||
const exchangeContractAddresses = _.map(
|
||||
orderCancellationRequests,
|
||||
orderCancellationRequest => orderCancellationRequest.order.exchangeContractAddress,
|
||||
);
|
||||
assert.hasAtMostOneUniqueValue(exchangeContractAddresses,
|
||||
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress);
|
||||
assert.hasAtMostOneUniqueValue(
|
||||
exchangeContractAddresses,
|
||||
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
|
||||
);
|
||||
const makers = _.map(orderCancellationRequests, cancellationRequest => cancellationRequest.order.maker);
|
||||
assert.hasAtMostOneUniqueValue(makers, ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed);
|
||||
const maker = makers[0];
|
||||
await assert.isSenderAddressAsync('maker', maker, this._web3Wrapper);
|
||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
|
||||
SHOULD_VALIDATE_BY_DEFAULT :
|
||||
orderTransactionOpts.shouldValidate;
|
||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
|
||||
? SHOULD_VALIDATE_BY_DEFAULT
|
||||
: orderTransactionOpts.shouldValidate;
|
||||
if (shouldValidate) {
|
||||
for (const orderCancellationRequest of orderCancellationRequests) {
|
||||
const orderHash = utils.getOrderHashHex(orderCancellationRequest.order);
|
||||
const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
|
||||
OrderValidationUtils.validateCancelOrderThrowIfInvalid(
|
||||
orderCancellationRequest.order, orderCancellationRequest.takerTokenCancelAmount,
|
||||
orderCancellationRequest.order,
|
||||
orderCancellationRequest.takerTokenCancelAmount,
|
||||
unavailableTakerTokenAmount,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
if (_.isEmpty(orderCancellationRequests)) {
|
||||
throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
|
||||
@@ -566,8 +627,9 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
];
|
||||
});
|
||||
// We use _.unzip<any> because _.unzip doesn't type check if values have different types :'(
|
||||
const [orderAddresses, orderValues, cancelTakerTokenAmounts] =
|
||||
_.unzip<any>(orderAddressesValuesAndTakerTokenCancelAmounts);
|
||||
const [orderAddresses, orderValues, cancelTakerTokenAmounts] = _.unzip<any>(
|
||||
orderAddressesValuesAndTakerTokenCancelAmounts,
|
||||
);
|
||||
const txHash = await exchangeInstance.batchCancelOrders.sendTransactionAsync(
|
||||
orderAddresses,
|
||||
orderValues,
|
||||
@@ -589,14 +651,20 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
* @return Subscription token used later to unsubscribe
|
||||
*/
|
||||
public subscribe<ArgsType extends ExchangeContractEventArgs>(
|
||||
eventName: ExchangeEvents, indexFilterValues: IndexedFilterValues,
|
||||
callback: EventCallback<ArgsType>): string {
|
||||
eventName: ExchangeEvents,
|
||||
indexFilterValues: IndexedFilterValues,
|
||||
callback: EventCallback<ArgsType>,
|
||||
): string {
|
||||
assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
|
||||
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
||||
assert.isFunction('callback', callback);
|
||||
const exchangeContractAddress = this.getContractAddress();
|
||||
const subscriptionToken = this._subscribe<ArgsType>(
|
||||
exchangeContractAddress, eventName, indexFilterValues, artifacts.ExchangeArtifact.abi, callback,
|
||||
exchangeContractAddress,
|
||||
eventName,
|
||||
indexFilterValues,
|
||||
artifacts.ExchangeArtifact.abi,
|
||||
callback,
|
||||
);
|
||||
return subscriptionToken;
|
||||
}
|
||||
@@ -622,14 +690,20 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
* @return Array of logs that match the parameters
|
||||
*/
|
||||
public async getLogsAsync<ArgsType extends ExchangeContractEventArgs>(
|
||||
eventName: ExchangeEvents, blockRange: BlockRange, indexFilterValues: IndexedFilterValues,
|
||||
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,
|
||||
exchangeContractAddress,
|
||||
eventName,
|
||||
blockRange,
|
||||
indexFilterValues,
|
||||
artifacts.ExchangeArtifact.abi,
|
||||
);
|
||||
return logs;
|
||||
}
|
||||
@@ -652,14 +726,18 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
* to validate for.
|
||||
*/
|
||||
public async validateOrderFillableOrThrowAsync(
|
||||
signedOrder: SignedOrder, opts?: ValidateOrderFillableOpts,
|
||||
signedOrder: SignedOrder,
|
||||
opts?: ValidateOrderFillableOpts,
|
||||
): Promise<void> {
|
||||
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const expectedFillTakerTokenAmount = !_.isUndefined(opts) ? opts.expectedFillTakerTokenAmount : undefined;
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
await this._orderValidationUtils.validateOrderFillableOrThrowAsync(
|
||||
exchangeTradeEmulator, signedOrder, zrxTokenAddress, expectedFillTakerTokenAmount,
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
zrxTokenAddress,
|
||||
expectedFillTakerTokenAmount,
|
||||
);
|
||||
}
|
||||
/**
|
||||
@@ -670,16 +748,23 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
* @param takerAddress The user Ethereum address who would like to fill this order.
|
||||
* Must be available via the supplied Web3.Provider passed to 0x.js.
|
||||
*/
|
||||
public async validateFillOrderThrowIfInvalidAsync(signedOrder: SignedOrder,
|
||||
public async validateFillOrderThrowIfInvalidAsync(
|
||||
signedOrder: SignedOrder,
|
||||
fillTakerTokenAmount: BigNumber,
|
||||
takerAddress: string): Promise<void> {
|
||||
takerAddress: string,
|
||||
): Promise<void> {
|
||||
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
||||
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress);
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount,
|
||||
takerAddress,
|
||||
zrxTokenAddress,
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Checks if cancelling a given order will succeed and throws an informative error if it won't.
|
||||
@@ -688,13 +773,18 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
* @param cancelTakerTokenAmount The amount (specified in taker tokens) that you would like to cancel.
|
||||
*/
|
||||
public async validateCancelOrderThrowIfInvalidAsync(
|
||||
order: Order, cancelTakerTokenAmount: BigNumber): Promise<void> {
|
||||
order: Order,
|
||||
cancelTakerTokenAmount: BigNumber,
|
||||
): Promise<void> {
|
||||
assert.doesConformToSchema('order', order, schemas.orderSchema);
|
||||
assert.isValidBaseUnitAmount('cancelTakerTokenAmount', cancelTakerTokenAmount);
|
||||
const orderHash = utils.getOrderHashHex(order);
|
||||
const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
|
||||
OrderValidationUtils.validateCancelOrderThrowIfInvalid(
|
||||
order, cancelTakerTokenAmount, unavailableTakerTokenAmount);
|
||||
order,
|
||||
cancelTakerTokenAmount,
|
||||
unavailableTakerTokenAmount,
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Checks if calling fillOrKill on a given order will succeed and throws an informative error if it won't.
|
||||
@@ -704,16 +794,23 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
* @param takerAddress The user Ethereum address who would like to fill this order.
|
||||
* Must be available via the supplied Web3.Provider passed to 0x.js.
|
||||
*/
|
||||
public async validateFillOrKillOrderThrowIfInvalidAsync(signedOrder: SignedOrder,
|
||||
public async validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
signedOrder: SignedOrder,
|
||||
fillTakerTokenAmount: BigNumber,
|
||||
takerAddress: string): Promise<void> {
|
||||
takerAddress: string,
|
||||
): Promise<void> {
|
||||
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
||||
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress);
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount,
|
||||
takerAddress,
|
||||
zrxTokenAddress,
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Checks if rounding error will be > 0.1% when computing makerTokenAmount by doing:
|
||||
@@ -724,15 +821,19 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
* @param takerTokenAmount The order size on the taker side
|
||||
* @param makerTokenAmount The order size on the maker side
|
||||
*/
|
||||
public async isRoundingErrorAsync(fillTakerTokenAmount: BigNumber,
|
||||
public async isRoundingErrorAsync(
|
||||
fillTakerTokenAmount: BigNumber,
|
||||
takerTokenAmount: BigNumber,
|
||||
makerTokenAmount: BigNumber): Promise<boolean> {
|
||||
makerTokenAmount: BigNumber,
|
||||
): Promise<boolean> {
|
||||
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
||||
assert.isValidBaseUnitAmount('takerTokenAmount', takerTokenAmount);
|
||||
assert.isValidBaseUnitAmount('makerTokenAmount', makerTokenAmount);
|
||||
const exchangeInstance = await this._getExchangeContractAsync();
|
||||
const isRoundingError = await exchangeInstance.isRoundingError.callAsync(
|
||||
fillTakerTokenAmount, takerTokenAmount, makerTokenAmount,
|
||||
fillTakerTokenAmount,
|
||||
takerTokenAmount,
|
||||
makerTokenAmount,
|
||||
);
|
||||
return isRoundingError;
|
||||
}
|
||||
@@ -756,17 +857,18 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
* @return Address of ZRX token
|
||||
*/
|
||||
public getZRXTokenAddress(): string {
|
||||
const contractAddress = this._getContractAddress(
|
||||
artifacts.ZRXArtifact, this._zrxContractAddressIfExists,
|
||||
);
|
||||
const contractAddress = this._getContractAddress(artifacts.ZRXArtifact, this._zrxContractAddressIfExists);
|
||||
return contractAddress;
|
||||
}
|
||||
private _invalidateContractInstances(): void {
|
||||
this.unsubscribeAll();
|
||||
delete this._exchangeContractIfExists;
|
||||
}
|
||||
private async _isValidSignatureUsingContractCallAsync(dataHex: string, ecSignature: ECSignature,
|
||||
signerAddressHex: string): Promise<boolean> {
|
||||
private async _isValidSignatureUsingContractCallAsync(
|
||||
dataHex: string,
|
||||
ecSignature: ECSignature,
|
||||
signerAddressHex: string,
|
||||
): Promise<boolean> {
|
||||
assert.isHexString('dataHex', dataHex);
|
||||
assert.doesConformToSchema('ecSignature', ecSignature, schemas.ecSignatureSchema);
|
||||
assert.isETHAddressHex('signerAddressHex', signerAddressHex);
|
||||
@@ -793,7 +895,8 @@ export class ExchangeWrapper extends ContractWrapper {
|
||||
return this._exchangeContractIfExists;
|
||||
}
|
||||
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
||||
artifacts.ExchangeArtifact, this._contractAddressIfExists,
|
||||
artifacts.ExchangeArtifact,
|
||||
this._contractAddressIfExists,
|
||||
);
|
||||
const contractInstance = new ExchangeContract(web3ContractInstance, this._web3Wrapper.getContractDefaults());
|
||||
this._exchangeContractIfExists = contractInstance;
|
||||
|
@@ -37,9 +37,8 @@ export class TokenRegistryWrapper extends ContractWrapper {
|
||||
*/
|
||||
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 tokenPromises: Array<Promise<Token | undefined>> = _.map(addresses, async (address: string) =>
|
||||
this.getTokenIfExistsAsync(address),
|
||||
);
|
||||
const tokens = await Promise.all(tokenPromises);
|
||||
return tokens as Token[];
|
||||
@@ -104,7 +103,8 @@ export class TokenRegistryWrapper extends ContractWrapper {
|
||||
*/
|
||||
public getContractAddress(): string {
|
||||
const contractAddress = this._getContractAddress(
|
||||
artifacts.TokenRegistryArtifact, this._contractAddressIfExists,
|
||||
artifacts.TokenRegistryArtifact,
|
||||
this._contractAddressIfExists,
|
||||
);
|
||||
return contractAddress;
|
||||
}
|
||||
@@ -116,10 +116,12 @@ export class TokenRegistryWrapper extends ContractWrapper {
|
||||
return this._tokenRegistryContractIfExists;
|
||||
}
|
||||
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
||||
artifacts.TokenRegistryArtifact, this._contractAddressIfExists,
|
||||
artifacts.TokenRegistryArtifact,
|
||||
this._contractAddressIfExists,
|
||||
);
|
||||
const contractInstance = new TokenRegistryContract(
|
||||
web3ContractInstance, this._web3Wrapper.getContractDefaults(),
|
||||
web3ContractInstance,
|
||||
this._web3Wrapper.getContractDefaults(),
|
||||
);
|
||||
this._tokenRegistryContractIfExists = contractInstance;
|
||||
return this._tokenRegistryContractIfExists;
|
||||
|
@@ -42,7 +42,8 @@ export class TokenTransferProxyWrapper extends ContractWrapper {
|
||||
*/
|
||||
public getContractAddress(): string {
|
||||
const contractAddress = this._getContractAddress(
|
||||
artifacts.TokenTransferProxyArtifact, this._contractAddressIfExists,
|
||||
artifacts.TokenTransferProxyArtifact,
|
||||
this._contractAddressIfExists,
|
||||
);
|
||||
return contractAddress;
|
||||
}
|
||||
@@ -54,10 +55,12 @@ export class TokenTransferProxyWrapper extends ContractWrapper {
|
||||
return this._tokenTransferProxyContractIfExists;
|
||||
}
|
||||
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
||||
artifacts.TokenTransferProxyArtifact, this._contractAddressIfExists,
|
||||
artifacts.TokenTransferProxyArtifact,
|
||||
this._contractAddressIfExists,
|
||||
);
|
||||
const contractInstance = new TokenTransferProxyContract(
|
||||
web3ContractInstance, this._web3Wrapper.getContractDefaults(),
|
||||
web3ContractInstance,
|
||||
this._web3Wrapper.getContractDefaults(),
|
||||
);
|
||||
this._tokenTransferProxyContractIfExists = contractInstance;
|
||||
return this._tokenTransferProxyContractIfExists;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { schemas } from '@0xproject/json-schemas';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts } from '../artifacts';
|
||||
@@ -32,8 +32,12 @@ 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) {
|
||||
constructor(
|
||||
web3Wrapper: Web3Wrapper,
|
||||
networkId: number,
|
||||
abiDecoder: AbiDecoder,
|
||||
tokenTransferProxyWrapper: TokenTransferProxyWrapper,
|
||||
) {
|
||||
super(web3Wrapper, networkId, abiDecoder);
|
||||
this._tokenContractsByAddress = {};
|
||||
this._tokenTransferProxyWrapper = tokenTransferProxyWrapper;
|
||||
@@ -45,8 +49,11 @@ export class TokenWrapper extends ContractWrapper {
|
||||
* @param methodOpts Optional arguments this method accepts.
|
||||
* @return The owner's ERC20 token balance in base units.
|
||||
*/
|
||||
public async getBalanceAsync(tokenAddress: string, ownerAddress: string,
|
||||
methodOpts?: MethodOpts): Promise<BigNumber> {
|
||||
public async getBalanceAsync(
|
||||
tokenAddress: string,
|
||||
ownerAddress: string,
|
||||
methodOpts?: MethodOpts,
|
||||
): Promise<BigNumber> {
|
||||
assert.isETHAddressHex('ownerAddress', ownerAddress);
|
||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||
|
||||
@@ -68,8 +75,13 @@ export class TokenWrapper extends ContractWrapper {
|
||||
* @param txOpts Transaction parameters.
|
||||
* @return Transaction hash.
|
||||
*/
|
||||
public async setAllowanceAsync(tokenAddress: string, ownerAddress: string, spenderAddress: string,
|
||||
amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise<string> {
|
||||
public async setAllowanceAsync(
|
||||
tokenAddress: string,
|
||||
ownerAddress: string,
|
||||
spenderAddress: string,
|
||||
amountInBaseUnits: BigNumber,
|
||||
txOpts: TransactionOpts = {},
|
||||
): Promise<string> {
|
||||
await assert.isSenderAddressAsync('ownerAddress', ownerAddress, this._web3Wrapper);
|
||||
assert.isETHAddressHex('spenderAddress', spenderAddress);
|
||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||
@@ -95,10 +107,18 @@ export class TokenWrapper extends ContractWrapper {
|
||||
* @param txOpts Transaction parameters.
|
||||
* @return Transaction hash.
|
||||
*/
|
||||
public async setUnlimitedAllowanceAsync(tokenAddress: string, ownerAddress: string,
|
||||
spenderAddress: string, txOpts: TransactionOpts = {}): Promise<string> {
|
||||
public async setUnlimitedAllowanceAsync(
|
||||
tokenAddress: string,
|
||||
ownerAddress: string,
|
||||
spenderAddress: string,
|
||||
txOpts: TransactionOpts = {},
|
||||
): Promise<string> {
|
||||
const txHash = await this.setAllowanceAsync(
|
||||
tokenAddress, ownerAddress, spenderAddress, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, txOpts,
|
||||
tokenAddress,
|
||||
ownerAddress,
|
||||
spenderAddress,
|
||||
this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
|
||||
txOpts,
|
||||
);
|
||||
return txHash;
|
||||
}
|
||||
@@ -110,8 +130,12 @@ export class TokenWrapper extends ContractWrapper {
|
||||
* @param spenderAddress The hex encoded user Ethereum address who can spend the allowance you are fetching.
|
||||
* @param methodOpts Optional arguments this method accepts.
|
||||
*/
|
||||
public async getAllowanceAsync(tokenAddress: string, ownerAddress: string,
|
||||
spenderAddress: string, methodOpts?: MethodOpts): Promise<BigNumber> {
|
||||
public async getAllowanceAsync(
|
||||
tokenAddress: string,
|
||||
ownerAddress: string,
|
||||
spenderAddress: string,
|
||||
methodOpts?: MethodOpts,
|
||||
): Promise<BigNumber> {
|
||||
assert.isETHAddressHex('ownerAddress', ownerAddress);
|
||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||
|
||||
@@ -128,8 +152,11 @@ export class TokenWrapper extends ContractWrapper {
|
||||
* @param ownerAddress The hex encoded user Ethereum address whose proxy contract allowance we are retrieving.
|
||||
* @param methodOpts Optional arguments this method accepts.
|
||||
*/
|
||||
public async getProxyAllowanceAsync(tokenAddress: string, ownerAddress: string,
|
||||
methodOpts?: MethodOpts): Promise<BigNumber> {
|
||||
public async getProxyAllowanceAsync(
|
||||
tokenAddress: string,
|
||||
ownerAddress: string,
|
||||
methodOpts?: MethodOpts,
|
||||
): Promise<BigNumber> {
|
||||
assert.isETHAddressHex('ownerAddress', ownerAddress);
|
||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||
|
||||
@@ -147,15 +174,23 @@ export class TokenWrapper extends ContractWrapper {
|
||||
* @param txOpts Transaction parameters.
|
||||
* @return Transaction hash.
|
||||
*/
|
||||
public async setProxyAllowanceAsync(tokenAddress: string, ownerAddress: string,
|
||||
amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise<string> {
|
||||
public async setProxyAllowanceAsync(
|
||||
tokenAddress: string,
|
||||
ownerAddress: string,
|
||||
amountInBaseUnits: BigNumber,
|
||||
txOpts: TransactionOpts = {},
|
||||
): Promise<string> {
|
||||
assert.isETHAddressHex('ownerAddress', ownerAddress);
|
||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||
assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
|
||||
|
||||
const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress();
|
||||
const txHash = await this.setAllowanceAsync(
|
||||
tokenAddress, ownerAddress, proxyAddress, amountInBaseUnits, txOpts,
|
||||
tokenAddress,
|
||||
ownerAddress,
|
||||
proxyAddress,
|
||||
amountInBaseUnits,
|
||||
txOpts,
|
||||
);
|
||||
return txHash;
|
||||
}
|
||||
@@ -171,10 +206,15 @@ export class TokenWrapper extends ContractWrapper {
|
||||
* @return Transaction hash.
|
||||
*/
|
||||
public async setUnlimitedProxyAllowanceAsync(
|
||||
tokenAddress: string, ownerAddress: string, txOpts: TransactionOpts = {},
|
||||
tokenAddress: string,
|
||||
ownerAddress: string,
|
||||
txOpts: TransactionOpts = {},
|
||||
): Promise<string> {
|
||||
const txHash = await this.setProxyAllowanceAsync(
|
||||
tokenAddress, ownerAddress, this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, txOpts,
|
||||
tokenAddress,
|
||||
ownerAddress,
|
||||
this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
|
||||
txOpts,
|
||||
);
|
||||
return txHash;
|
||||
}
|
||||
@@ -187,8 +227,13 @@ export class TokenWrapper extends ContractWrapper {
|
||||
* @param txOpts Transaction parameters.
|
||||
* @return Transaction hash.
|
||||
*/
|
||||
public async transferAsync(tokenAddress: string, fromAddress: string, toAddress: string,
|
||||
amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise<string> {
|
||||
public async transferAsync(
|
||||
tokenAddress: string,
|
||||
fromAddress: string,
|
||||
toAddress: string,
|
||||
amountInBaseUnits: BigNumber,
|
||||
txOpts: TransactionOpts = {},
|
||||
): Promise<string> {
|
||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||
await assert.isSenderAddressAsync('fromAddress', fromAddress, this._web3Wrapper);
|
||||
assert.isETHAddressHex('toAddress', toAddress);
|
||||
@@ -222,9 +267,14 @@ export class TokenWrapper extends ContractWrapper {
|
||||
* @param txOpts Transaction parameters.
|
||||
* @return Transaction hash.
|
||||
*/
|
||||
public async transferFromAsync(tokenAddress: string, fromAddress: string, toAddress: string,
|
||||
senderAddress: string, amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}):
|
||||
Promise<string> {
|
||||
public async transferFromAsync(
|
||||
tokenAddress: string,
|
||||
fromAddress: string,
|
||||
toAddress: string,
|
||||
senderAddress: string,
|
||||
amountInBaseUnits: BigNumber,
|
||||
txOpts: TransactionOpts = {},
|
||||
): Promise<string> {
|
||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||
assert.isETHAddressHex('fromAddress', fromAddress);
|
||||
assert.isETHAddressHex('toAddress', toAddress);
|
||||
@@ -244,7 +294,9 @@ export class TokenWrapper extends ContractWrapper {
|
||||
}
|
||||
|
||||
const txHash = await tokenContract.transferFrom.sendTransactionAsync(
|
||||
fromAddress, toAddress, amountInBaseUnits,
|
||||
fromAddress,
|
||||
toAddress,
|
||||
amountInBaseUnits,
|
||||
{
|
||||
from: senderAddress,
|
||||
gas: txOpts.gasLimit,
|
||||
@@ -263,14 +315,21 @@ export class TokenWrapper extends ContractWrapper {
|
||||
* @return Subscription token used later to unsubscribe
|
||||
*/
|
||||
public subscribe<ArgsType extends TokenContractEventArgs>(
|
||||
tokenAddress: string, eventName: TokenEvents, indexFilterValues: IndexedFilterValues,
|
||||
callback: EventCallback<ArgsType>): string {
|
||||
tokenAddress: string,
|
||||
eventName: TokenEvents,
|
||||
indexFilterValues: IndexedFilterValues,
|
||||
callback: EventCallback<ArgsType>,
|
||||
): string {
|
||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||
assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
|
||||
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
||||
assert.isFunction('callback', callback);
|
||||
const subscriptionToken = this._subscribe<ArgsType>(
|
||||
tokenAddress, eventName, indexFilterValues, artifacts.TokenArtifact.abi, callback,
|
||||
tokenAddress,
|
||||
eventName,
|
||||
indexFilterValues,
|
||||
artifacts.TokenArtifact.abi,
|
||||
callback,
|
||||
);
|
||||
return subscriptionToken;
|
||||
}
|
||||
@@ -297,14 +356,21 @@ export class TokenWrapper extends ContractWrapper {
|
||||
* @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>>> {
|
||||
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,
|
||||
tokenAddress,
|
||||
eventName,
|
||||
blockRange,
|
||||
indexFilterValues,
|
||||
artifacts.TokenArtifact.abi,
|
||||
);
|
||||
return logs;
|
||||
}
|
||||
@@ -318,11 +384,10 @@ export class TokenWrapper extends ContractWrapper {
|
||||
return tokenContract;
|
||||
}
|
||||
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
||||
artifacts.TokenArtifact, tokenAddress,
|
||||
);
|
||||
const contractInstance = new TokenContract(
|
||||
web3ContractInstance, this._web3Wrapper.getContractDefaults(),
|
||||
artifacts.TokenArtifact,
|
||||
tokenAddress,
|
||||
);
|
||||
const contractInstance = new TokenContract(web3ContractInstance, this._web3Wrapper.getContractDefaults());
|
||||
tokenContract = contractInstance;
|
||||
this._tokenContractsByAddress[tokenAddress] = tokenContract;
|
||||
return tokenContract;
|
||||
|
5
packages/0x.js/src/globals.d.ts
vendored
5
packages/0x.js/src/globals.d.ts
vendored
@@ -1,5 +1,3 @@
|
||||
/// <reference types='chai-typescript-typings' />
|
||||
/// <reference types='chai-as-promised-typescript-typings' />
|
||||
declare module 'web3_beta';
|
||||
declare module 'chai-bignumber';
|
||||
declare module 'dirty-chai';
|
||||
@@ -57,8 +55,7 @@ declare module 'truffle-hdwallet-provider' {
|
||||
}
|
||||
|
||||
// abi-decoder declarations
|
||||
interface DecodedLogArg {
|
||||
}
|
||||
interface DecodedLogArg {}
|
||||
interface DecodedLog {
|
||||
name: string;
|
||||
events: DecodedLogArg[];
|
||||
|
2
packages/0x.js/src/globalsAugment.d.ts
vendored
2
packages/0x.js/src/globalsAugment.d.ts
vendored
@@ -1,4 +1,4 @@
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
// HACK: This module overrides the Chai namespace so that we can use BigNumber types inside.
|
||||
// Source: https://github.com/Microsoft/TypeScript/issues/7352#issuecomment-191547232
|
||||
|
@@ -47,6 +47,4 @@ export {
|
||||
OrderState,
|
||||
} from './types';
|
||||
|
||||
export {
|
||||
TransactionReceipt,
|
||||
} from '@0xproject/types';
|
||||
export { TransactionReceipt } from '@0xproject/types';
|
||||
|
@@ -3,11 +3,7 @@ import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
||||
import * as _ from 'lodash';
|
||||
import * as Web3 from 'web3';
|
||||
|
||||
import {
|
||||
BlockParamLiteral,
|
||||
EventWatcherCallback,
|
||||
ZeroExError,
|
||||
} from '../types';
|
||||
import { BlockParamLiteral, EventWatcherCallback, ZeroExError } from '../types';
|
||||
import { assert } from '../utils/assert';
|
||||
|
||||
const DEFAULT_EVENT_POLLING_INTERVAL_MS = 200;
|
||||
@@ -28,9 +24,9 @@ export class EventWatcher {
|
||||
private _lastEvents: Web3.LogEntry[] = [];
|
||||
constructor(web3Wrapper: Web3Wrapper, pollingIntervalIfExistsMs: undefined | number) {
|
||||
this._web3Wrapper = web3Wrapper;
|
||||
this._pollingIntervalMs = _.isUndefined(pollingIntervalIfExistsMs) ?
|
||||
DEFAULT_EVENT_POLLING_INTERVAL_MS :
|
||||
pollingIntervalIfExistsMs;
|
||||
this._pollingIntervalMs = _.isUndefined(pollingIntervalIfExistsMs)
|
||||
? DEFAULT_EVENT_POLLING_INTERVAL_MS
|
||||
: pollingIntervalIfExistsMs;
|
||||
}
|
||||
public subscribe(callback: EventWatcherCallback): void {
|
||||
assert.isFunction('callback', callback);
|
||||
@@ -38,7 +34,12 @@ export class EventWatcher {
|
||||
throw new Error(ZeroExError.SubscriptionAlreadyPresent);
|
||||
}
|
||||
this._intervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
|
||||
this._pollForBlockchainEventsAsync.bind(this, callback), this._pollingIntervalMs,
|
||||
this._pollForBlockchainEventsAsync.bind(this, callback),
|
||||
this._pollingIntervalMs,
|
||||
(err: Error) => {
|
||||
this.unsubscribe();
|
||||
callback(err);
|
||||
},
|
||||
);
|
||||
}
|
||||
public unsubscribe(): void {
|
||||
@@ -71,7 +72,9 @@ export class EventWatcher {
|
||||
return events;
|
||||
}
|
||||
private async _emitDifferencesAsync(
|
||||
logs: Web3.LogEntry[], logEventState: LogEventState, callback: EventWatcherCallback,
|
||||
logs: Web3.LogEntry[],
|
||||
logEventState: LogEventState,
|
||||
callback: EventWatcherCallback,
|
||||
): Promise<void> {
|
||||
for (const log of logs) {
|
||||
const logEvent = {
|
||||
@@ -79,7 +82,7 @@ export class EventWatcher {
|
||||
...log,
|
||||
};
|
||||
if (!_.isUndefined(this._intervalIdIfExists)) {
|
||||
callback(logEvent);
|
||||
callback(null, logEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import {intervalUtils} from '@0xproject/utils';
|
||||
import {BigNumber} from 'bignumber.js';
|
||||
import { BigNumber, intervalUtils } from '@0xproject/utils';
|
||||
import { RBTree } from 'bintrees';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@@ -14,62 +13,62 @@ const DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS = 50;
|
||||
* It stores them in a min heap by expiration time and checks for expired ones every `orderExpirationCheckingIntervalMs`
|
||||
*/
|
||||
export class ExpirationWatcher {
|
||||
private orderHashByExpirationRBTree: RBTree<string>;
|
||||
private expiration: {[orderHash: string]: BigNumber} = {};
|
||||
private orderExpirationCheckingIntervalMs: number;
|
||||
private expirationMarginMs: number;
|
||||
private orderExpirationCheckingIntervalIdIfExists?: NodeJS.Timer;
|
||||
constructor(expirationMarginIfExistsMs?: number,
|
||||
orderExpirationCheckingIntervalIfExistsMs?: number) {
|
||||
this.expirationMarginMs = expirationMarginIfExistsMs ||
|
||||
DEFAULT_EXPIRATION_MARGIN_MS;
|
||||
this.orderExpirationCheckingIntervalMs = expirationMarginIfExistsMs ||
|
||||
DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS;
|
||||
const scoreFunction = (orderHash: string) => this.expiration[orderHash].toNumber();
|
||||
private _orderHashByExpirationRBTree: RBTree<string>;
|
||||
private _expiration: { [orderHash: string]: BigNumber } = {};
|
||||
private _orderExpirationCheckingIntervalMs: number;
|
||||
private _expirationMarginMs: number;
|
||||
private _orderExpirationCheckingIntervalIdIfExists?: NodeJS.Timer;
|
||||
constructor(expirationMarginIfExistsMs?: number, orderExpirationCheckingIntervalIfExistsMs?: number) {
|
||||
this._expirationMarginMs = expirationMarginIfExistsMs || DEFAULT_EXPIRATION_MARGIN_MS;
|
||||
this._orderExpirationCheckingIntervalMs =
|
||||
expirationMarginIfExistsMs || DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS;
|
||||
const scoreFunction = (orderHash: string) => this._expiration[orderHash].toNumber();
|
||||
const comparator = (lhs: string, rhs: string) => scoreFunction(lhs) - scoreFunction(rhs);
|
||||
this.orderHashByExpirationRBTree = new RBTree(comparator);
|
||||
this._orderHashByExpirationRBTree = new RBTree(comparator);
|
||||
}
|
||||
public subscribe(callback: (orderHash: string) => void): void {
|
||||
if (!_.isUndefined(this.orderExpirationCheckingIntervalIdIfExists)) {
|
||||
if (!_.isUndefined(this._orderExpirationCheckingIntervalIdIfExists)) {
|
||||
throw new Error(ZeroExError.SubscriptionAlreadyPresent);
|
||||
}
|
||||
this.orderExpirationCheckingIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
|
||||
this.pruneExpiredOrders.bind(this, callback), this.orderExpirationCheckingIntervalMs,
|
||||
this._orderExpirationCheckingIntervalIdIfExists = intervalUtils.setInterval(
|
||||
this._pruneExpiredOrders.bind(this, callback),
|
||||
this._orderExpirationCheckingIntervalMs,
|
||||
_.noop, // _pruneExpiredOrders never throws
|
||||
);
|
||||
}
|
||||
public unsubscribe(): void {
|
||||
if (_.isUndefined(this.orderExpirationCheckingIntervalIdIfExists)) {
|
||||
if (_.isUndefined(this._orderExpirationCheckingIntervalIdIfExists)) {
|
||||
throw new Error(ZeroExError.SubscriptionNotFound);
|
||||
}
|
||||
intervalUtils.clearAsyncExcludingInterval(this.orderExpirationCheckingIntervalIdIfExists);
|
||||
delete this.orderExpirationCheckingIntervalIdIfExists;
|
||||
intervalUtils.clearInterval(this._orderExpirationCheckingIntervalIdIfExists);
|
||||
delete this._orderExpirationCheckingIntervalIdIfExists;
|
||||
}
|
||||
public addOrder(orderHash: string, expirationUnixTimestampMs: BigNumber): void {
|
||||
this.expiration[orderHash] = expirationUnixTimestampMs;
|
||||
this.orderHashByExpirationRBTree.insert(orderHash);
|
||||
this._expiration[orderHash] = expirationUnixTimestampMs;
|
||||
this._orderHashByExpirationRBTree.insert(orderHash);
|
||||
}
|
||||
public removeOrder(orderHash: string): void {
|
||||
this.orderHashByExpirationRBTree.remove(orderHash);
|
||||
delete this.expiration[orderHash];
|
||||
this._orderHashByExpirationRBTree.remove(orderHash);
|
||||
delete this._expiration[orderHash];
|
||||
}
|
||||
private pruneExpiredOrders(callback: (orderHash: string) => void): void {
|
||||
private _pruneExpiredOrders(callback: (orderHash: string) => void): void {
|
||||
const currentUnixTimestampMs = utils.getCurrentUnixTimestampMs();
|
||||
while (true) {
|
||||
const hasTrakedOrders = this.orderHashByExpirationRBTree.size === 0;
|
||||
const hasTrakedOrders = this._orderHashByExpirationRBTree.size === 0;
|
||||
if (hasTrakedOrders) {
|
||||
break;
|
||||
}
|
||||
const nextOrderHashToExpire = this.orderHashByExpirationRBTree.min();
|
||||
const hasNoExpiredOrders = this.expiration[nextOrderHashToExpire].greaterThan(
|
||||
currentUnixTimestampMs.plus(this.expirationMarginMs),
|
||||
const nextOrderHashToExpire = this._orderHashByExpirationRBTree.min();
|
||||
const hasNoExpiredOrders = this._expiration[nextOrderHashToExpire].greaterThan(
|
||||
currentUnixTimestampMs.plus(this._expirationMarginMs),
|
||||
);
|
||||
const isSubscriptionActive = _.isUndefined(this.orderExpirationCheckingIntervalIdIfExists);
|
||||
const isSubscriptionActive = _.isUndefined(this._orderExpirationCheckingIntervalIdIfExists);
|
||||
if (hasNoExpiredOrders || isSubscriptionActive) {
|
||||
break;
|
||||
}
|
||||
const orderHash = this.orderHashByExpirationRBTree.min();
|
||||
this.orderHashByExpirationRBTree.remove(orderHash);
|
||||
delete this.expiration[orderHash];
|
||||
const orderHash = this._orderHashByExpirationRBTree.min();
|
||||
this._orderHashByExpirationRBTree.remove(orderHash);
|
||||
delete this._expiration[orderHash];
|
||||
callback(orderHash);
|
||||
}
|
||||
}
|
||||
|
@@ -74,7 +74,10 @@ export class OrderStateWatcher {
|
||||
private _cleanupJobInterval: number;
|
||||
private _cleanupJobIntervalIdIfExists?: NodeJS.Timer;
|
||||
constructor(
|
||||
web3Wrapper: Web3Wrapper, abiDecoder: AbiDecoder, token: TokenWrapper, exchange: ExchangeWrapper,
|
||||
web3Wrapper: Web3Wrapper,
|
||||
abiDecoder: AbiDecoder,
|
||||
token: TokenWrapper,
|
||||
exchange: ExchangeWrapper,
|
||||
config?: OrderStateWatcherConfig,
|
||||
) {
|
||||
this._abiDecoder = abiDecoder;
|
||||
@@ -82,24 +85,26 @@ export class OrderStateWatcher {
|
||||
const pollingIntervalIfExistsMs = _.isUndefined(config) ? undefined : config.eventPollingIntervalMs;
|
||||
this._eventWatcher = new EventWatcher(web3Wrapper, pollingIntervalIfExistsMs);
|
||||
this._balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||
token, BlockParamLiteral.Pending,
|
||||
token,
|
||||
BlockParamLiteral.Pending,
|
||||
);
|
||||
this._orderFilledCancelledLazyStore = new OrderFilledCancelledLazyStore(exchange);
|
||||
this._orderStateUtils = new OrderStateUtils(
|
||||
this._balanceAndProxyAllowanceLazyStore, this._orderFilledCancelledLazyStore,
|
||||
this._balanceAndProxyAllowanceLazyStore,
|
||||
this._orderFilledCancelledLazyStore,
|
||||
);
|
||||
const orderExpirationCheckingIntervalMsIfExists = _.isUndefined(config) ?
|
||||
undefined :
|
||||
config.orderExpirationCheckingIntervalMs;
|
||||
const expirationMarginIfExistsMs = _.isUndefined(config) ?
|
||||
undefined :
|
||||
config.expirationMarginMs;
|
||||
const orderExpirationCheckingIntervalMsIfExists = _.isUndefined(config)
|
||||
? undefined
|
||||
: config.orderExpirationCheckingIntervalMs;
|
||||
const expirationMarginIfExistsMs = _.isUndefined(config) ? undefined : config.expirationMarginMs;
|
||||
this._expirationWatcher = new ExpirationWatcher(
|
||||
expirationMarginIfExistsMs, orderExpirationCheckingIntervalMsIfExists,
|
||||
expirationMarginIfExistsMs,
|
||||
orderExpirationCheckingIntervalMsIfExists,
|
||||
);
|
||||
this._cleanupJobInterval = _.isUndefined(config) || _.isUndefined(config.cleanupJobIntervalMs) ?
|
||||
DEFAULT_CLEANUP_JOB_INTERVAL_MS :
|
||||
config.cleanupJobIntervalMs;
|
||||
this._cleanupJobInterval =
|
||||
_.isUndefined(config) || _.isUndefined(config.cleanupJobIntervalMs)
|
||||
? DEFAULT_CLEANUP_JOB_INTERVAL_MS
|
||||
: config.cleanupJobIntervalMs;
|
||||
}
|
||||
/**
|
||||
* Add an order to the orderStateWatcher. Before the order is added, it's
|
||||
@@ -111,7 +116,7 @@ export class OrderStateWatcher {
|
||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||
assert.isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker);
|
||||
this._orderByOrderHash[orderHash] = signedOrder;
|
||||
this.addToDependentOrderHashes(signedOrder, orderHash);
|
||||
this._addToDependentOrderHashes(signedOrder, orderHash);
|
||||
const expirationUnixTimestampMs = signedOrder.expirationUnixTimestampSec.times(1000);
|
||||
this._expirationWatcher.addOrder(orderHash, expirationUnixTimestampMs);
|
||||
}
|
||||
@@ -127,10 +132,10 @@ export class OrderStateWatcher {
|
||||
}
|
||||
delete this._orderByOrderHash[orderHash];
|
||||
delete this._orderStateByOrderHashCache[orderHash];
|
||||
const exchange = (this._orderFilledCancelledLazyStore as any).exchange as ExchangeWrapper;
|
||||
const exchange = (this._orderFilledCancelledLazyStore as any)._exchange as ExchangeWrapper;
|
||||
const zrxTokenAddress = exchange.getZRXTokenAddress();
|
||||
this.removeFromDependentOrderHashes(signedOrder.maker, zrxTokenAddress, orderHash);
|
||||
this.removeFromDependentOrderHashes(signedOrder.maker, signedOrder.makerTokenAddress, orderHash);
|
||||
this._removeFromDependentOrderHashes(signedOrder.maker, zrxTokenAddress, orderHash);
|
||||
this._removeFromDependentOrderHashes(signedOrder.maker, signedOrder.makerTokenAddress, orderHash);
|
||||
this._expirationWatcher.removeOrder(orderHash);
|
||||
}
|
||||
/**
|
||||
@@ -148,7 +153,12 @@ export class OrderStateWatcher {
|
||||
this._eventWatcher.subscribe(this._onEventWatcherCallbackAsync.bind(this));
|
||||
this._expirationWatcher.subscribe(this._onOrderExpired.bind(this));
|
||||
this._cleanupJobIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
|
||||
this._cleanupAsync.bind(this), this._cleanupJobInterval,
|
||||
this._cleanupAsync.bind(this),
|
||||
this._cleanupJobInterval,
|
||||
(err: Error) => {
|
||||
this.unsubscribe();
|
||||
callback(err);
|
||||
},
|
||||
);
|
||||
}
|
||||
/**
|
||||
@@ -201,11 +211,19 @@ export class OrderStateWatcher {
|
||||
if (!_.isUndefined(this._orderByOrderHash[orderHash])) {
|
||||
this.removeOrder(orderHash);
|
||||
if (!_.isUndefined(this._callbackIfExists)) {
|
||||
this._callbackIfExists(orderState);
|
||||
this._callbackIfExists(null, orderState);
|
||||
}
|
||||
}
|
||||
}
|
||||
private async _onEventWatcherCallbackAsync(log: LogEvent): Promise<void> {
|
||||
private async _onEventWatcherCallbackAsync(err: Error | null, logIfExists?: LogEvent): Promise<void> {
|
||||
if (!_.isNull(err)) {
|
||||
if (!_.isUndefined(this._callbackIfExists)) {
|
||||
this._callbackIfExists(err);
|
||||
this.unsubscribe();
|
||||
}
|
||||
return;
|
||||
}
|
||||
const log = logIfExists as LogEvent; // At this moment we are sure that no error occured and log is defined.
|
||||
const maybeDecodedLog = this._abiDecoder.tryToDecodeLogOrNoop(log);
|
||||
const isLogDecoded = !_.isUndefined((maybeDecodedLog as LogWithDecodedArgs<any>).event);
|
||||
if (!isLogDecoded) {
|
||||
@@ -215,23 +233,23 @@ export class OrderStateWatcher {
|
||||
let makerToken: string;
|
||||
let makerAddress: string;
|
||||
switch (decodedLog.event) {
|
||||
case TokenEvents.Approval:
|
||||
{
|
||||
case TokenEvents.Approval: {
|
||||
// Invalidate cache
|
||||
const args = decodedLog.args as ApprovalContractEventArgs;
|
||||
this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(decodedLog.address, args._owner);
|
||||
// Revalidate orders
|
||||
makerToken = decodedLog.address;
|
||||
makerAddress = args._owner;
|
||||
if (!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
|
||||
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])) {
|
||||
if (
|
||||
!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
|
||||
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])
|
||||
) {
|
||||
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
|
||||
await this._emitRevalidateOrdersAsync(orderHashes);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TokenEvents.Transfer:
|
||||
{
|
||||
case TokenEvents.Transfer: {
|
||||
// Invalidate cache
|
||||
const args = decodedLog.args as TransferContractEventArgs;
|
||||
this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._from);
|
||||
@@ -239,45 +257,48 @@ export class OrderStateWatcher {
|
||||
// Revalidate orders
|
||||
makerToken = decodedLog.address;
|
||||
makerAddress = args._from;
|
||||
if (!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
|
||||
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])) {
|
||||
if (
|
||||
!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
|
||||
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])
|
||||
) {
|
||||
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
|
||||
await this._emitRevalidateOrdersAsync(orderHashes);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EtherTokenEvents.Deposit:
|
||||
{
|
||||
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])) {
|
||||
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:
|
||||
{
|
||||
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])) {
|
||||
if (
|
||||
!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
|
||||
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])
|
||||
) {
|
||||
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
|
||||
await this._emitRevalidateOrdersAsync(orderHashes);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ExchangeEvents.LogFill:
|
||||
{
|
||||
case ExchangeEvents.LogFill: {
|
||||
// Invalidate cache
|
||||
const args = decodedLog.args as LogFillContractEventArgs;
|
||||
this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(args.orderHash);
|
||||
@@ -289,8 +310,7 @@ export class OrderStateWatcher {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ExchangeEvents.LogCancel:
|
||||
{
|
||||
case ExchangeEvents.LogCancel: {
|
||||
// Invalidate cache
|
||||
const args = decodedLog.args as LogCancelContractEventArgs;
|
||||
this._orderFilledCancelledLazyStore.deleteCancelledTakerAmount(args.orderHash);
|
||||
@@ -324,10 +344,10 @@ export class OrderStateWatcher {
|
||||
} else {
|
||||
this._orderStateByOrderHashCache[orderHash] = orderState;
|
||||
}
|
||||
this._callbackIfExists(orderState);
|
||||
this._callbackIfExists(null, orderState);
|
||||
}
|
||||
}
|
||||
private addToDependentOrderHashes(signedOrder: SignedOrder, orderHash: string): void {
|
||||
private _addToDependentOrderHashes(signedOrder: SignedOrder, orderHash: string): void {
|
||||
if (_.isUndefined(this._dependentOrderHashes[signedOrder.maker])) {
|
||||
this._dependentOrderHashes[signedOrder.maker] = {};
|
||||
}
|
||||
@@ -341,7 +361,7 @@ export class OrderStateWatcher {
|
||||
}
|
||||
this._dependentOrderHashes[signedOrder.maker][zrxTokenAddress].add(orderHash);
|
||||
}
|
||||
private removeFromDependentOrderHashes(makerAddress: string, tokenAddress: string, orderHash: string) {
|
||||
private _removeFromDependentOrderHashes(makerAddress: string, tokenAddress: string, orderHash: string) {
|
||||
this._dependentOrderHashes[makerAddress][tokenAddress].delete(orderHash);
|
||||
if (this._dependentOrderHashes[makerAddress][tokenAddress].size === 0) {
|
||||
delete this._dependentOrderHashes[makerAddress][tokenAddress];
|
||||
@@ -351,7 +371,7 @@ export class OrderStateWatcher {
|
||||
}
|
||||
}
|
||||
private _getZRXTokenAddress(): string {
|
||||
const exchange = (this._orderFilledCancelledLazyStore as any).exchange as ExchangeWrapper;
|
||||
const exchange = (this._orderFilledCancelledLazyStore as any)._exchange as ExchangeWrapper;
|
||||
const zrxTokenAddress = exchange.getZRXTokenAddress();
|
||||
return zrxTokenAddress;
|
||||
}
|
||||
|
@@ -1,87 +1,96 @@
|
||||
import {BigNumber} from 'bignumber.js';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
import { SignedOrder } from '../types';
|
||||
|
||||
export class RemainingFillableCalculator {
|
||||
private signedOrder: SignedOrder;
|
||||
private isMakerTokenZRX: boolean;
|
||||
private _signedOrder: SignedOrder;
|
||||
private _isMakerTokenZRX: boolean;
|
||||
// Transferrable Amount is the minimum of Approval and Balance
|
||||
private transferrableMakerTokenAmount: BigNumber;
|
||||
private transferrableMakerFeeTokenAmount: BigNumber;
|
||||
private remainingMakerTokenAmount: BigNumber;
|
||||
private remainingMakerFeeAmount: BigNumber;
|
||||
constructor(signedOrder: SignedOrder,
|
||||
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)
|
||||
remainingMakerTokenAmount: BigNumber,
|
||||
) {
|
||||
this._signedOrder = signedOrder;
|
||||
this._isMakerTokenZRX = isMakerTokenZRX;
|
||||
this._transferrableMakerTokenAmount = transferrableMakerTokenAmount;
|
||||
this._transferrableMakerFeeTokenAmount = transferrableMakerFeeTokenAmount;
|
||||
this._remainingMakerTokenAmount = remainingMakerTokenAmount;
|
||||
this._remainingMakerFeeAmount = remainingMakerTokenAmount
|
||||
.times(signedOrder.makerFee)
|
||||
.dividedToIntegerBy(signedOrder.makerTokenAmount);
|
||||
}
|
||||
public computeRemainingMakerFillable(): BigNumber {
|
||||
if (this.hasSufficientFundsForFeeAndTransferAmount()) {
|
||||
return this.remainingMakerTokenAmount;
|
||||
if (this._hasSufficientFundsForFeeAndTransferAmount()) {
|
||||
return this._remainingMakerTokenAmount;
|
||||
}
|
||||
if (this.signedOrder.makerFee.isZero()) {
|
||||
return BigNumber.min(this.remainingMakerTokenAmount, this.transferrableMakerTokenAmount);
|
||||
if (this._signedOrder.makerFee.isZero()) {
|
||||
return BigNumber.min(this._remainingMakerTokenAmount, this._transferrableMakerTokenAmount);
|
||||
}
|
||||
return this.calculatePartiallyFillableMakerTokenAmount();
|
||||
return this._calculatePartiallyFillableMakerTokenAmount();
|
||||
}
|
||||
public computeRemainingTakerFillable(): BigNumber {
|
||||
return this.computeRemainingMakerFillable().times(this.signedOrder.takerTokenAmount)
|
||||
.dividedToIntegerBy(this.signedOrder.makerTokenAmount);
|
||||
return this.computeRemainingMakerFillable()
|
||||
.times(this._signedOrder.takerTokenAmount)
|
||||
.dividedToIntegerBy(this._signedOrder.makerTokenAmount);
|
||||
}
|
||||
private hasSufficientFundsForFeeAndTransferAmount(): boolean {
|
||||
if (this.isMakerTokenZRX) {
|
||||
const totalZRXTransferAmountRequired = this.remainingMakerTokenAmount.plus(this.remainingMakerFeeAmount);
|
||||
const hasSufficientFunds = this.transferrableMakerTokenAmount.greaterThanOrEqualTo(
|
||||
totalZRXTransferAmountRequired);
|
||||
private _hasSufficientFundsForFeeAndTransferAmount(): boolean {
|
||||
if (this._isMakerTokenZRX) {
|
||||
const totalZRXTransferAmountRequired = this._remainingMakerTokenAmount.plus(this._remainingMakerFeeAmount);
|
||||
const hasSufficientFunds = this._transferrableMakerTokenAmount.greaterThanOrEqualTo(
|
||||
totalZRXTransferAmountRequired,
|
||||
);
|
||||
return hasSufficientFunds;
|
||||
} else {
|
||||
const hasSufficientFundsForTransferAmount = this.transferrableMakerTokenAmount.greaterThanOrEqualTo(
|
||||
this.remainingMakerTokenAmount);
|
||||
const hasSufficientFundsForFeeAmount = this.transferrableMakerFeeTokenAmount.greaterThanOrEqualTo(
|
||||
this.remainingMakerFeeAmount);
|
||||
const hasSufficientFundsForTransferAmount = this._transferrableMakerTokenAmount.greaterThanOrEqualTo(
|
||||
this._remainingMakerTokenAmount,
|
||||
);
|
||||
const hasSufficientFundsForFeeAmount = this._transferrableMakerFeeTokenAmount.greaterThanOrEqualTo(
|
||||
this._remainingMakerFeeAmount,
|
||||
);
|
||||
const hasSufficientFunds = hasSufficientFundsForTransferAmount && hasSufficientFundsForFeeAmount;
|
||||
return hasSufficientFunds;
|
||||
}
|
||||
}
|
||||
private calculatePartiallyFillableMakerTokenAmount(): BigNumber {
|
||||
private _calculatePartiallyFillableMakerTokenAmount(): BigNumber {
|
||||
// Given an order for 200 wei for 2 ZRXwei fee, find 100 wei for 1 ZRXwei. Order ratio is then 100:1
|
||||
const orderToFeeRatio = this.signedOrder.makerTokenAmount.dividedBy(this.signedOrder.makerFee);
|
||||
const orderToFeeRatio = this._signedOrder.makerTokenAmount.dividedBy(this._signedOrder.makerFee);
|
||||
// The number of times the maker can fill the order, if each fill only required the transfer of a single
|
||||
// baseUnit of fee tokens.
|
||||
// Given 2 ZRXwei, the maximum amount of times Maker can fill this order, in terms of fees, is 2
|
||||
const fillableTimesInFeeTokenBaseUnits = BigNumber.min(this.transferrableMakerFeeTokenAmount,
|
||||
this.remainingMakerFeeAmount);
|
||||
const fillableTimesInFeeTokenBaseUnits = BigNumber.min(
|
||||
this._transferrableMakerFeeTokenAmount,
|
||||
this._remainingMakerFeeAmount,
|
||||
);
|
||||
// The number of times the Maker can fill the order, given the Maker Token Balance
|
||||
// Assuming a balance of 150 wei, and an orderToFeeRatio of 100:1, maker can fill this order 1 time.
|
||||
let fillableTimesInMakerTokenUnits = this.transferrableMakerTokenAmount.dividedBy(orderToFeeRatio);
|
||||
if (this.isMakerTokenZRX) {
|
||||
let fillableTimesInMakerTokenUnits = this._transferrableMakerTokenAmount.dividedBy(orderToFeeRatio);
|
||||
if (this._isMakerTokenZRX) {
|
||||
// If ZRX is the maker token, the Fee and the Maker amount need to be removed from the same pool;
|
||||
// 200 ZRXwei for 2ZRXwei fee can only be filled once (need 202 ZRXwei)
|
||||
const totalZRXTokenPooled = this.transferrableMakerTokenAmount;
|
||||
const totalZRXTokenPooled = this._transferrableMakerTokenAmount;
|
||||
// The purchasing power here is less as the tokens are taken from the same Pool
|
||||
// For every one number of fills, we have to take an extra ZRX out of the pool
|
||||
fillableTimesInMakerTokenUnits = totalZRXTokenPooled.dividedBy(
|
||||
orderToFeeRatio.plus(new BigNumber(1)));
|
||||
|
||||
fillableTimesInMakerTokenUnits = totalZRXTokenPooled.dividedBy(orderToFeeRatio.plus(new BigNumber(1)));
|
||||
}
|
||||
// When Ratio is not fully divisible there can be remainders which cannot be represented, so they are floored.
|
||||
// This can result in a RoundingError being thrown by the Exchange Contract.
|
||||
const partiallyFillableMakerTokenAmount = fillableTimesInMakerTokenUnits
|
||||
.times(this.signedOrder.makerTokenAmount)
|
||||
.dividedToIntegerBy(this.signedOrder.makerFee);
|
||||
.times(this._signedOrder.makerTokenAmount)
|
||||
.dividedToIntegerBy(this._signedOrder.makerFee);
|
||||
const partiallyFillableFeeTokenAmount = fillableTimesInFeeTokenBaseUnits
|
||||
.times(this.signedOrder.makerTokenAmount)
|
||||
.dividedToIntegerBy(this.signedOrder.makerFee);
|
||||
const partiallyFillableAmount = BigNumber.min(partiallyFillableMakerTokenAmount,
|
||||
partiallyFillableFeeTokenAmount);
|
||||
.times(this._signedOrder.makerTokenAmount)
|
||||
.dividedToIntegerBy(this._signedOrder.makerFee);
|
||||
const partiallyFillableAmount = BigNumber.min(
|
||||
partiallyFillableMakerTokenAmount,
|
||||
partiallyFillableFeeTokenAmount,
|
||||
);
|
||||
return partiallyFillableAmount;
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import {BigNumber} from 'bignumber.js';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { TokenWrapper } from '../contract_wrappers/token_wrapper';
|
||||
@@ -8,77 +8,79 @@ import {BlockParamLiteral} from '../types';
|
||||
* Copy on read store for balances/proxyAllowances of tokens/accounts
|
||||
*/
|
||||
export class BalanceAndProxyAllowanceLazyStore {
|
||||
private token: TokenWrapper;
|
||||
private defaultBlock: BlockParamLiteral;
|
||||
private balance: {
|
||||
private _token: TokenWrapper;
|
||||
private _defaultBlock: BlockParamLiteral;
|
||||
private _balance: {
|
||||
[tokenAddress: string]: {
|
||||
[userAddress: string]: BigNumber;
|
||||
};
|
||||
};
|
||||
private proxyAllowance: {
|
||||
private _proxyAllowance: {
|
||||
[tokenAddress: string]: {
|
||||
[userAddress: string]: BigNumber;
|
||||
};
|
||||
};
|
||||
constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) {
|
||||
this.token = token;
|
||||
this.defaultBlock = defaultBlock;
|
||||
this.balance = {};
|
||||
this.proxyAllowance = {};
|
||||
this._token = token;
|
||||
this._defaultBlock = defaultBlock;
|
||||
this._balance = {};
|
||||
this._proxyAllowance = {};
|
||||
}
|
||||
public async getBalanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> {
|
||||
if (_.isUndefined(this.balance[tokenAddress]) || _.isUndefined(this.balance[tokenAddress][userAddress])) {
|
||||
if (_.isUndefined(this._balance[tokenAddress]) || _.isUndefined(this._balance[tokenAddress][userAddress])) {
|
||||
const methodOpts = {
|
||||
defaultBlock: this.defaultBlock,
|
||||
defaultBlock: this._defaultBlock,
|
||||
};
|
||||
const balance = await this.token.getBalanceAsync(tokenAddress, userAddress, methodOpts);
|
||||
const balance = await this._token.getBalanceAsync(tokenAddress, userAddress, methodOpts);
|
||||
this.setBalance(tokenAddress, userAddress, balance);
|
||||
}
|
||||
const cachedBalance = this.balance[tokenAddress][userAddress];
|
||||
const cachedBalance = this._balance[tokenAddress][userAddress];
|
||||
return cachedBalance;
|
||||
}
|
||||
public setBalance(tokenAddress: string, userAddress: string, balance: BigNumber): void {
|
||||
if (_.isUndefined(this.balance[tokenAddress])) {
|
||||
this.balance[tokenAddress] = {};
|
||||
if (_.isUndefined(this._balance[tokenAddress])) {
|
||||
this._balance[tokenAddress] = {};
|
||||
}
|
||||
this.balance[tokenAddress][userAddress] = balance;
|
||||
this._balance[tokenAddress][userAddress] = balance;
|
||||
}
|
||||
public deleteBalance(tokenAddress: string, userAddress: string): void {
|
||||
if (!_.isUndefined(this.balance[tokenAddress])) {
|
||||
delete this.balance[tokenAddress][userAddress];
|
||||
if (_.isEmpty(this.balance[tokenAddress])) {
|
||||
delete this.balance[tokenAddress];
|
||||
if (!_.isUndefined(this._balance[tokenAddress])) {
|
||||
delete this._balance[tokenAddress][userAddress];
|
||||
if (_.isEmpty(this._balance[tokenAddress])) {
|
||||
delete this._balance[tokenAddress];
|
||||
}
|
||||
}
|
||||
}
|
||||
public async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> {
|
||||
if (_.isUndefined(this.proxyAllowance[tokenAddress]) ||
|
||||
_.isUndefined(this.proxyAllowance[tokenAddress][userAddress])) {
|
||||
if (
|
||||
_.isUndefined(this._proxyAllowance[tokenAddress]) ||
|
||||
_.isUndefined(this._proxyAllowance[tokenAddress][userAddress])
|
||||
) {
|
||||
const methodOpts = {
|
||||
defaultBlock: this.defaultBlock,
|
||||
defaultBlock: this._defaultBlock,
|
||||
};
|
||||
const proxyAllowance = await this.token.getProxyAllowanceAsync(tokenAddress, userAddress, methodOpts);
|
||||
const proxyAllowance = await this._token.getProxyAllowanceAsync(tokenAddress, userAddress, methodOpts);
|
||||
this.setProxyAllowance(tokenAddress, userAddress, proxyAllowance);
|
||||
}
|
||||
const cachedProxyAllowance = this.proxyAllowance[tokenAddress][userAddress];
|
||||
const cachedProxyAllowance = this._proxyAllowance[tokenAddress][userAddress];
|
||||
return cachedProxyAllowance;
|
||||
}
|
||||
public setProxyAllowance(tokenAddress: string, userAddress: string, proxyAllowance: BigNumber): void {
|
||||
if (_.isUndefined(this.proxyAllowance[tokenAddress])) {
|
||||
this.proxyAllowance[tokenAddress] = {};
|
||||
if (_.isUndefined(this._proxyAllowance[tokenAddress])) {
|
||||
this._proxyAllowance[tokenAddress] = {};
|
||||
}
|
||||
this.proxyAllowance[tokenAddress][userAddress] = proxyAllowance;
|
||||
this._proxyAllowance[tokenAddress][userAddress] = proxyAllowance;
|
||||
}
|
||||
public deleteProxyAllowance(tokenAddress: string, userAddress: string): void {
|
||||
if (!_.isUndefined(this.proxyAllowance[tokenAddress])) {
|
||||
delete this.proxyAllowance[tokenAddress][userAddress];
|
||||
if (_.isEmpty(this.proxyAllowance[tokenAddress])) {
|
||||
delete this.proxyAllowance[tokenAddress];
|
||||
if (!_.isUndefined(this._proxyAllowance[tokenAddress])) {
|
||||
delete this._proxyAllowance[tokenAddress][userAddress];
|
||||
if (_.isEmpty(this._proxyAllowance[tokenAddress])) {
|
||||
delete this._proxyAllowance[tokenAddress];
|
||||
}
|
||||
}
|
||||
}
|
||||
public deleteAll(): void {
|
||||
this.balance = {};
|
||||
this.proxyAllowance = {};
|
||||
this._balance = {};
|
||||
this._proxyAllowance = {};
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import {BigNumber} from 'bignumber.js';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper';
|
||||
@@ -8,54 +8,54 @@ import {BlockParamLiteral} from '../types';
|
||||
* Copy on read store for filled/cancelled taker amounts
|
||||
*/
|
||||
export class OrderFilledCancelledLazyStore {
|
||||
private exchange: ExchangeWrapper;
|
||||
private filledTakerAmount: {
|
||||
private _exchange: ExchangeWrapper;
|
||||
private _filledTakerAmount: {
|
||||
[orderHash: string]: BigNumber;
|
||||
};
|
||||
private cancelledTakerAmount: {
|
||||
private _cancelledTakerAmount: {
|
||||
[orderHash: string]: BigNumber;
|
||||
};
|
||||
constructor(exchange: ExchangeWrapper) {
|
||||
this.exchange = exchange;
|
||||
this.filledTakerAmount = {};
|
||||
this.cancelledTakerAmount = {};
|
||||
this._exchange = exchange;
|
||||
this._filledTakerAmount = {};
|
||||
this._cancelledTakerAmount = {};
|
||||
}
|
||||
public async getFilledTakerAmountAsync(orderHash: string): Promise<BigNumber> {
|
||||
if (_.isUndefined(this.filledTakerAmount[orderHash])) {
|
||||
if (_.isUndefined(this._filledTakerAmount[orderHash])) {
|
||||
const methodOpts = {
|
||||
defaultBlock: BlockParamLiteral.Pending,
|
||||
};
|
||||
const filledTakerAmount = await this.exchange.getFilledTakerAmountAsync(orderHash, methodOpts);
|
||||
const filledTakerAmount = await this._exchange.getFilledTakerAmountAsync(orderHash, methodOpts);
|
||||
this.setFilledTakerAmount(orderHash, filledTakerAmount);
|
||||
}
|
||||
const cachedFilled = this.filledTakerAmount[orderHash];
|
||||
const cachedFilled = this._filledTakerAmount[orderHash];
|
||||
return cachedFilled;
|
||||
}
|
||||
public setFilledTakerAmount(orderHash: string, filledTakerAmount: BigNumber): void {
|
||||
this.filledTakerAmount[orderHash] = filledTakerAmount;
|
||||
this._filledTakerAmount[orderHash] = filledTakerAmount;
|
||||
}
|
||||
public deleteFilledTakerAmount(orderHash: string): void {
|
||||
delete this.filledTakerAmount[orderHash];
|
||||
delete this._filledTakerAmount[orderHash];
|
||||
}
|
||||
public async getCancelledTakerAmountAsync(orderHash: string): Promise<BigNumber> {
|
||||
if (_.isUndefined(this.cancelledTakerAmount[orderHash])) {
|
||||
if (_.isUndefined(this._cancelledTakerAmount[orderHash])) {
|
||||
const methodOpts = {
|
||||
defaultBlock: BlockParamLiteral.Pending,
|
||||
};
|
||||
const cancelledTakerAmount = await this.exchange.getCancelledTakerAmountAsync(orderHash, methodOpts);
|
||||
const cancelledTakerAmount = await this._exchange.getCancelledTakerAmountAsync(orderHash, methodOpts);
|
||||
this.setCancelledTakerAmount(orderHash, cancelledTakerAmount);
|
||||
}
|
||||
const cachedCancelled = this.cancelledTakerAmount[orderHash];
|
||||
const cachedCancelled = this._cancelledTakerAmount[orderHash];
|
||||
return cachedCancelled;
|
||||
}
|
||||
public setCancelledTakerAmount(orderHash: string, cancelledTakerAmount: BigNumber): void {
|
||||
this.cancelledTakerAmount[orderHash] = cancelledTakerAmount;
|
||||
this._cancelledTakerAmount[orderHash] = cancelledTakerAmount;
|
||||
}
|
||||
public deleteCancelledTakerAmount(orderHash: string): void {
|
||||
delete this.cancelledTakerAmount[orderHash];
|
||||
delete this._cancelledTakerAmount[orderHash];
|
||||
}
|
||||
public deleteAll(): void {
|
||||
this.filledTakerAmount = {};
|
||||
this.cancelledTakerAmount = {};
|
||||
this._filledTakerAmount = {};
|
||||
this._cancelledTakerAmount = {};
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { TransactionReceipt } from '@0xproject/types';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as Web3 from 'web3';
|
||||
|
||||
export enum ZeroExError {
|
||||
@@ -42,8 +42,7 @@ export interface ECSignature {
|
||||
|
||||
export type OrderAddresses = [string, string, string, string, string];
|
||||
|
||||
export type OrderValues = [BigNumber, BigNumber, BigNumber,
|
||||
BigNumber, BigNumber, BigNumber];
|
||||
export type OrderValues = [BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber];
|
||||
|
||||
export type LogEvent = Web3.LogEntryEvent;
|
||||
export interface DecodedLogEvent<ArgsType> {
|
||||
@@ -52,7 +51,7 @@ export interface DecodedLogEvent<ArgsType> {
|
||||
}
|
||||
|
||||
export type EventCallback<ArgsType> = (err: null | Error, log?: DecodedLogEvent<ArgsType>) => void;
|
||||
export type EventWatcherCallback = (log: LogEvent) => void;
|
||||
export type EventWatcherCallback = (err: null | Error, log?: LogEvent) => void;
|
||||
|
||||
export enum SolidityTypes {
|
||||
Address = 'address',
|
||||
@@ -136,7 +135,10 @@ export interface LogErrorContractEventArgs {
|
||||
errorId: BigNumber;
|
||||
orderHash: string;
|
||||
}
|
||||
export type ExchangeContractEventArgs = LogFillContractEventArgs|LogCancelContractEventArgs|LogErrorContractEventArgs;
|
||||
export type ExchangeContractEventArgs =
|
||||
| LogFillContractEventArgs
|
||||
| LogCancelContractEventArgs
|
||||
| LogErrorContractEventArgs;
|
||||
export interface TransferContractEventArgs {
|
||||
_from: string;
|
||||
_to: string;
|
||||
@@ -156,7 +158,10 @@ export interface WithdrawalContractEventArgs {
|
||||
_value: BigNumber;
|
||||
}
|
||||
export type TokenContractEventArgs = TransferContractEventArgs | ApprovalContractEventArgs;
|
||||
export type EtherTokenContractEventArgs = TokenContractEventArgs|DepositContractEventArgs|WithdrawalContractEventArgs;
|
||||
export type EtherTokenContractEventArgs =
|
||||
| TokenContractEventArgs
|
||||
| DepositContractEventArgs
|
||||
| WithdrawalContractEventArgs;
|
||||
export type ContractEventArgs = ExchangeContractEventArgs | TokenContractEventArgs | EtherTokenContractEventArgs;
|
||||
export type ContractEventArg = string | BigNumber;
|
||||
|
||||
@@ -401,5 +406,5 @@ export interface OrderStateInvalid {
|
||||
|
||||
export type OrderState = OrderStateValid | OrderStateInvalid;
|
||||
|
||||
export type OnOrderStateChangeCallback = (orderState: OrderState) => void;
|
||||
export type OnOrderStateChangeCallback = (err: Error | null, orderState?: OrderState) => void;
|
||||
// tslint:disable:max-file-line-count
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as _ from 'lodash';
|
||||
import * as Web3 from 'web3';
|
||||
import * as SolidityCoder from 'web3/lib/solidity/coder';
|
||||
@@ -6,9 +6,9 @@ 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) {
|
||||
private _savedABIs: Web3.AbiDefinition[] = [];
|
||||
private _methodIds: { [signatureHash: string]: Web3.EventAbi } = {};
|
||||
private static _padZeros(address: string) {
|
||||
let formatted = address;
|
||||
if (_.startsWith(formatted, '0x')) {
|
||||
formatted = formatted.slice(2);
|
||||
@@ -18,13 +18,14 @@ export class AbiDecoder {
|
||||
return `0x${formatted}`;
|
||||
}
|
||||
constructor(abiArrays: Web3.AbiDefinition[][]) {
|
||||
_.map(abiArrays, this.addABI.bind(this));
|
||||
_.map(abiArrays, this._addABI.bind(this));
|
||||
}
|
||||
// This method can only decode logs from the 0x & ERC20 smart contracts
|
||||
public tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>(
|
||||
log: Web3.LogEntry): LogWithDecodedArgs<ArgsType>|RawLog {
|
||||
log: Web3.LogEntry,
|
||||
): LogWithDecodedArgs<ArgsType> | RawLog {
|
||||
const methodId = log.topics[0];
|
||||
const event = this.methodIds[methodId];
|
||||
const event = this._methodIds[methodId];
|
||||
if (_.isUndefined(event)) {
|
||||
return log;
|
||||
}
|
||||
@@ -41,10 +42,12 @@ export class AbiDecoder {
|
||||
// Indexed parameters are stored in topics. Non-indexed ones in decodedData
|
||||
let value = param.indexed ? log.topics[topicsIndex++] : decodedData[dataIndex++];
|
||||
if (param.type === SolidityTypes.Address) {
|
||||
value = AbiDecoder.padZeros(new BigNumber(value).toString(16));
|
||||
} else if (param.type === SolidityTypes.Uint256 ||
|
||||
value = AbiDecoder._padZeros(new BigNumber(value).toString(16));
|
||||
} else if (
|
||||
param.type === SolidityTypes.Uint256 ||
|
||||
param.type === SolidityTypes.Uint8 ||
|
||||
param.type === SolidityTypes.Uint) {
|
||||
param.type === SolidityTypes.Uint
|
||||
) {
|
||||
value = new BigNumber(value);
|
||||
}
|
||||
decodedParams[param.name] = value;
|
||||
@@ -56,14 +59,14 @@ export class AbiDecoder {
|
||||
args: decodedParams,
|
||||
};
|
||||
}
|
||||
private addABI(abiArray: Web3.AbiDefinition[]): void {
|
||||
private _addABI(abiArray: Web3.AbiDefinition[]): void {
|
||||
_.map(abiArray, (abi: Web3.AbiDefinition) => {
|
||||
if (abi.type === AbiType.Event) {
|
||||
const signature = `${abi.name}(${_.map(abi.inputs, input => input.type).join(',')})`;
|
||||
const signatureHash = new Web3().sha3(signature);
|
||||
this.methodIds[signatureHash] = abi;
|
||||
this._methodIds[signatureHash] = abi;
|
||||
}
|
||||
});
|
||||
this.savedABIs = this.savedABIs.concat(abiArray);
|
||||
this._savedABIs = this._savedABIs.concat(abiArray);
|
||||
}
|
||||
}
|
||||
|
@@ -2,9 +2,9 @@ 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 { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { ECSignature } from '../types';
|
||||
@@ -16,11 +16,15 @@ export const assert = {
|
||||
const isValidSignature = signatureUtils.isValidSignature(orderHash, ecSignature, signerAddress);
|
||||
this.assert(isValidSignature, `Expected order with hash '${orderHash}' to have a valid signature`);
|
||||
},
|
||||
async isSenderAddressAsync(variableName: string, senderAddressHex: string,
|
||||
web3Wrapper: Web3Wrapper): Promise<void> {
|
||||
async isSenderAddressAsync(
|
||||
variableName: string,
|
||||
senderAddressHex: string,
|
||||
web3Wrapper: Web3Wrapper,
|
||||
): Promise<void> {
|
||||
sharedAssert.isETHAddressHex(variableName, senderAddressHex);
|
||||
const isSenderAddressAvailable = await web3Wrapper.isSenderAddressAvailableAsync(senderAddressHex);
|
||||
sharedAssert.assert(isSenderAddressAvailable,
|
||||
sharedAssert.assert(
|
||||
isSenderAddressAvailable,
|
||||
`Specified ${variableName} ${senderAddressHex} isn't available through the supplied web3 provider`,
|
||||
);
|
||||
},
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
export const constants = {
|
||||
NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
|
||||
|
@@ -18,8 +18,8 @@ const contractCallErrorTransformer = (error: 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';
|
||||
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;
|
||||
@@ -30,9 +30,11 @@ const schemaErrorTransformer = (error: Error) => {
|
||||
*/
|
||||
const asyncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
|
||||
const asyncErrorHandlingDecorator = (
|
||||
target: object, key: string|symbol, descriptor: TypedPropertyDescriptor<AsyncMethod>,
|
||||
target: object,
|
||||
key: string | symbol,
|
||||
descriptor: TypedPropertyDescriptor<AsyncMethod>,
|
||||
) => {
|
||||
const originalMethod = (descriptor.value as 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
|
||||
@@ -55,9 +57,11 @@ const asyncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
|
||||
|
||||
const syncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
|
||||
const syncErrorHandlingDecorator = (
|
||||
target: object, key: string|symbol, descriptor: TypedPropertyDescriptor<SyncMethod>,
|
||||
target: object,
|
||||
key: string | symbol,
|
||||
descriptor: TypedPropertyDescriptor<SyncMethod>,
|
||||
) => {
|
||||
const originalMethod = (descriptor.value as 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
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { TokenWrapper } from '../contract_wrappers/token_wrapper';
|
||||
@@ -34,16 +34,19 @@ const ERR_MSG_MAPPING = {
|
||||
};
|
||||
|
||||
export class ExchangeTransferSimulator {
|
||||
private store: BalanceAndProxyAllowanceLazyStore;
|
||||
private UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber;
|
||||
private static throwValidationError(failureReason: FailureReason, tradeSide: TradeSide,
|
||||
transferType: TransferType): never {
|
||||
private _store: BalanceAndProxyAllowanceLazyStore;
|
||||
private _UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber;
|
||||
private static _throwValidationError(
|
||||
failureReason: FailureReason,
|
||||
tradeSide: TradeSide,
|
||||
transferType: TransferType,
|
||||
): never {
|
||||
const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType];
|
||||
throw new Error(errMsg);
|
||||
}
|
||||
constructor(token: TokenWrapper, defaultBlock: BlockParamLiteral) {
|
||||
this.store = new BalanceAndProxyAllowanceLazyStore(token, defaultBlock);
|
||||
this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS = token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
|
||||
this._store = new BalanceAndProxyAllowanceLazyStore(token, defaultBlock);
|
||||
this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS = token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
|
||||
}
|
||||
/**
|
||||
* Simulates transferFrom call performed by a proxy
|
||||
@@ -54,36 +57,50 @@ export class ExchangeTransferSimulator {
|
||||
* @param tradeSide Is Maker/Taker transferring
|
||||
* @param transferType Is it a fee payment or a value transfer
|
||||
*/
|
||||
public async transferFromAsync(tokenAddress: string, from: string, to: string,
|
||||
amountInBaseUnits: BigNumber, tradeSide: TradeSide,
|
||||
transferType: TransferType): Promise<void> {
|
||||
const balance = await this.store.getBalanceAsync(tokenAddress, from);
|
||||
const proxyAllowance = await this.store.getProxyAllowanceAsync(tokenAddress, from);
|
||||
public async transferFromAsync(
|
||||
tokenAddress: string,
|
||||
from: string,
|
||||
to: string,
|
||||
amountInBaseUnits: BigNumber,
|
||||
tradeSide: TradeSide,
|
||||
transferType: TransferType,
|
||||
): Promise<void> {
|
||||
const balance = await this._store.getBalanceAsync(tokenAddress, from);
|
||||
const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, from);
|
||||
if (proxyAllowance.lessThan(amountInBaseUnits)) {
|
||||
ExchangeTransferSimulator.throwValidationError(FailureReason.ProxyAllowance, tradeSide, transferType);
|
||||
ExchangeTransferSimulator._throwValidationError(FailureReason.ProxyAllowance, tradeSide, transferType);
|
||||
}
|
||||
if (balance.lessThan(amountInBaseUnits)) {
|
||||
ExchangeTransferSimulator.throwValidationError(FailureReason.Balance, tradeSide, transferType);
|
||||
ExchangeTransferSimulator._throwValidationError(FailureReason.Balance, tradeSide, transferType);
|
||||
}
|
||||
await this.decreaseProxyAllowanceAsync(tokenAddress, from, amountInBaseUnits);
|
||||
await this.decreaseBalanceAsync(tokenAddress, from, amountInBaseUnits);
|
||||
await this.increaseBalanceAsync(tokenAddress, to, amountInBaseUnits);
|
||||
await this._decreaseProxyAllowanceAsync(tokenAddress, from, amountInBaseUnits);
|
||||
await this._decreaseBalanceAsync(tokenAddress, from, amountInBaseUnits);
|
||||
await this._increaseBalanceAsync(tokenAddress, to, amountInBaseUnits);
|
||||
}
|
||||
private async decreaseProxyAllowanceAsync(tokenAddress: string, userAddress: string,
|
||||
amountInBaseUnits: BigNumber): Promise<void> {
|
||||
const proxyAllowance = await this.store.getProxyAllowanceAsync(tokenAddress, userAddress);
|
||||
if (!proxyAllowance.eq(this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
|
||||
this.store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits));
|
||||
private async _decreaseProxyAllowanceAsync(
|
||||
tokenAddress: string,
|
||||
userAddress: string,
|
||||
amountInBaseUnits: BigNumber,
|
||||
): Promise<void> {
|
||||
const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, userAddress);
|
||||
if (!proxyAllowance.eq(this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
|
||||
this._store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits));
|
||||
}
|
||||
}
|
||||
private async increaseBalanceAsync(tokenAddress: string, userAddress: string,
|
||||
amountInBaseUnits: BigNumber): Promise<void> {
|
||||
const balance = await this.store.getBalanceAsync(tokenAddress, userAddress);
|
||||
this.store.setBalance(tokenAddress, userAddress, balance.plus(amountInBaseUnits));
|
||||
private async _increaseBalanceAsync(
|
||||
tokenAddress: string,
|
||||
userAddress: string,
|
||||
amountInBaseUnits: BigNumber,
|
||||
): Promise<void> {
|
||||
const balance = await this._store.getBalanceAsync(tokenAddress, userAddress);
|
||||
this._store.setBalance(tokenAddress, userAddress, balance.plus(amountInBaseUnits));
|
||||
}
|
||||
private async decreaseBalanceAsync(tokenAddress: string, userAddress: string,
|
||||
amountInBaseUnits: BigNumber): Promise<void> {
|
||||
const balance = await this.store.getBalanceAsync(tokenAddress, userAddress);
|
||||
this.store.setBalance(tokenAddress, userAddress, balance.minus(amountInBaseUnits));
|
||||
private async _decreaseBalanceAsync(
|
||||
tokenAddress: string,
|
||||
userAddress: string,
|
||||
amountInBaseUnits: BigNumber,
|
||||
): Promise<void> {
|
||||
const balance = await this._store.getBalanceAsync(tokenAddress, userAddress);
|
||||
this._store.setBalance(tokenAddress, userAddress, balance.minus(amountInBaseUnits));
|
||||
}
|
||||
}
|
||||
|
@@ -12,9 +12,13 @@ export const filterUtils = {
|
||||
generateUUID(): string {
|
||||
return uuid();
|
||||
},
|
||||
getFilter(address: string, eventName: ContractEvents,
|
||||
indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi,
|
||||
blockRange?: BlockRange): Web3.FilterObject {
|
||||
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));
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { ZeroEx } from '../0x';
|
||||
@@ -18,9 +18,9 @@ import {
|
||||
const ACCEPTABLE_RELATIVE_ROUNDING_ERROR = 0.0001;
|
||||
|
||||
export class OrderStateUtils {
|
||||
private balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore;
|
||||
private orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore;
|
||||
private static validateIfOrderIsValid(signedOrder: SignedOrder, orderRelevantState: OrderRelevantState): void {
|
||||
private _balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore;
|
||||
private _orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore;
|
||||
private static _validateIfOrderIsValid(signedOrder: SignedOrder, orderRelevantState: OrderRelevantState): void {
|
||||
const unavailableTakerTokenAmount = orderRelevantState.cancelledTakerTokenAmount.add(
|
||||
orderRelevantState.filledTakerTokenAmount,
|
||||
);
|
||||
@@ -46,21 +46,26 @@ export class OrderStateUtils {
|
||||
const minFillableTakerTokenAmountWithinNoRoundingErrorRange = signedOrder.takerTokenAmount
|
||||
.dividedBy(ACCEPTABLE_RELATIVE_ROUNDING_ERROR)
|
||||
.dividedBy(signedOrder.makerTokenAmount);
|
||||
if (orderRelevantState.remainingFillableTakerTokenAmount
|
||||
.lessThan(minFillableTakerTokenAmountWithinNoRoundingErrorRange)) {
|
||||
if (
|
||||
orderRelevantState.remainingFillableTakerTokenAmount.lessThan(
|
||||
minFillableTakerTokenAmountWithinNoRoundingErrorRange,
|
||||
)
|
||||
) {
|
||||
throw new Error(ExchangeContractErrs.OrderFillRoundingError);
|
||||
}
|
||||
}
|
||||
constructor(balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore,
|
||||
orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore) {
|
||||
this.balanceAndProxyAllowanceLazyStore = balanceAndProxyAllowanceLazyStore;
|
||||
this.orderFilledCancelledLazyStore = orderFilledCancelledLazyStore;
|
||||
constructor(
|
||||
balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore,
|
||||
orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore,
|
||||
) {
|
||||
this._balanceAndProxyAllowanceLazyStore = balanceAndProxyAllowanceLazyStore;
|
||||
this._orderFilledCancelledLazyStore = orderFilledCancelledLazyStore;
|
||||
}
|
||||
public async getOrderStateAsync(signedOrder: SignedOrder): Promise<OrderState> {
|
||||
const orderRelevantState = await this.getOrderRelevantStateAsync(signedOrder);
|
||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||
try {
|
||||
OrderStateUtils.validateIfOrderIsValid(signedOrder, orderRelevantState);
|
||||
OrderStateUtils._validateIfOrderIsValid(signedOrder, orderRelevantState);
|
||||
const orderState: OrderStateValid = {
|
||||
isValid: true,
|
||||
orderHash,
|
||||
@@ -81,40 +86,47 @@ export class OrderStateUtils {
|
||||
// If we pass it from the instantiator - there is no opportunity to get it there
|
||||
// because JS doesn't support async constructors.
|
||||
// Moreover - it's cached under the hood so it's equivalent to an async constructor.
|
||||
const exchange = (this.orderFilledCancelledLazyStore as any).exchange as ExchangeWrapper;
|
||||
const exchange = (this._orderFilledCancelledLazyStore as any)._exchange as ExchangeWrapper;
|
||||
const zrxTokenAddress = exchange.getZRXTokenAddress();
|
||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||
const makerBalance = await this.balanceAndProxyAllowanceLazyStore.getBalanceAsync(
|
||||
signedOrder.makerTokenAddress, signedOrder.maker,
|
||||
const makerBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync(
|
||||
signedOrder.makerTokenAddress,
|
||||
signedOrder.maker,
|
||||
);
|
||||
const makerProxyAllowance = await this.balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
|
||||
signedOrder.makerTokenAddress, signedOrder.maker,
|
||||
const makerProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
|
||||
signedOrder.makerTokenAddress,
|
||||
signedOrder.maker,
|
||||
);
|
||||
const makerFeeBalance = await this.balanceAndProxyAllowanceLazyStore.getBalanceAsync(
|
||||
zrxTokenAddress, signedOrder.maker,
|
||||
const makerFeeBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync(
|
||||
zrxTokenAddress,
|
||||
signedOrder.maker,
|
||||
);
|
||||
const makerFeeProxyAllowance = await this.balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
|
||||
zrxTokenAddress, signedOrder.maker,
|
||||
const makerFeeProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
|
||||
zrxTokenAddress,
|
||||
signedOrder.maker,
|
||||
);
|
||||
const filledTakerTokenAmount = await this.orderFilledCancelledLazyStore.getFilledTakerAmountAsync(orderHash);
|
||||
const cancelledTakerTokenAmount = await this.orderFilledCancelledLazyStore.getCancelledTakerAmountAsync(
|
||||
const filledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getFilledTakerAmountAsync(orderHash);
|
||||
const cancelledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getCancelledTakerAmountAsync(
|
||||
orderHash,
|
||||
);
|
||||
const unavailableTakerTokenAmount = await exchange.getUnavailableTakerAmountAsync(orderHash);
|
||||
const totalMakerTokenAmount = signedOrder.makerTokenAmount;
|
||||
const totalTakerTokenAmount = signedOrder.takerTokenAmount;
|
||||
const remainingTakerTokenAmount = totalTakerTokenAmount.minus(unavailableTakerTokenAmount);
|
||||
const remainingMakerTokenAmount = remainingTakerTokenAmount.times(totalMakerTokenAmount)
|
||||
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,
|
||||
const remainingFillableCalculator = new RemainingFillableCalculator(
|
||||
signedOrder,
|
||||
isMakerTokenZRX,
|
||||
transferrableMakerTokenAmount,
|
||||
transferrableFeeTokenAmount,
|
||||
remainingMakerTokenAmount);
|
||||
remainingMakerTokenAmount,
|
||||
);
|
||||
const remainingFillableMakerTokenAmount = remainingFillableCalculator.computeRemainingMakerFillable();
|
||||
const remainingFillableTakerTokenAmount = remainingFillableCalculator.computeRemainingTakerFillable();
|
||||
const orderRelevantState = {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { ZeroEx } from '../0x';
|
||||
@@ -10,9 +10,11 @@ import {utils} from '../utils/utils';
|
||||
import { ExchangeTransferSimulator } from './exchange_transfer_simulator';
|
||||
|
||||
export class OrderValidationUtils {
|
||||
private exchangeWrapper: ExchangeWrapper;
|
||||
private _exchangeWrapper: ExchangeWrapper;
|
||||
public static validateCancelOrderThrowIfInvalid(
|
||||
order: Order, cancelTakerTokenAmount: BigNumber, unavailableTakerTokenAmount: BigNumber,
|
||||
order: Order,
|
||||
cancelTakerTokenAmount: BigNumber,
|
||||
unavailableTakerTokenAmount: BigNumber,
|
||||
): void {
|
||||
if (cancelTakerTokenAmount.eq(0)) {
|
||||
throw new Error(ExchangeContractErrs.OrderCancelAmountZero);
|
||||
@@ -26,56 +28,75 @@ export class OrderValidationUtils {
|
||||
}
|
||||
}
|
||||
public static async validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder,
|
||||
fillTakerTokenAmount: BigNumber, senderAddress: string, zrxTokenAddress: string,
|
||||
exchangeTradeEmulator: ExchangeTransferSimulator,
|
||||
signedOrder: SignedOrder,
|
||||
fillTakerTokenAmount: BigNumber,
|
||||
senderAddress: string,
|
||||
zrxTokenAddress: string,
|
||||
): Promise<void> {
|
||||
const fillMakerTokenAmount = OrderValidationUtils.getPartialAmount(
|
||||
const fillMakerTokenAmount = OrderValidationUtils._getPartialAmount(
|
||||
fillTakerTokenAmount,
|
||||
signedOrder.takerTokenAmount,
|
||||
signedOrder.makerTokenAmount,
|
||||
);
|
||||
await exchangeTradeEmulator.transferFromAsync(
|
||||
signedOrder.makerTokenAddress, signedOrder.maker, senderAddress, fillMakerTokenAmount,
|
||||
TradeSide.Maker, TransferType.Trade,
|
||||
signedOrder.makerTokenAddress,
|
||||
signedOrder.maker,
|
||||
senderAddress,
|
||||
fillMakerTokenAmount,
|
||||
TradeSide.Maker,
|
||||
TransferType.Trade,
|
||||
);
|
||||
await exchangeTradeEmulator.transferFromAsync(
|
||||
signedOrder.takerTokenAddress, senderAddress, signedOrder.maker, fillTakerTokenAmount,
|
||||
TradeSide.Taker, TransferType.Trade,
|
||||
signedOrder.takerTokenAddress,
|
||||
senderAddress,
|
||||
signedOrder.maker,
|
||||
fillTakerTokenAmount,
|
||||
TradeSide.Taker,
|
||||
TransferType.Trade,
|
||||
);
|
||||
const makerFeeAmount = OrderValidationUtils.getPartialAmount(
|
||||
const makerFeeAmount = OrderValidationUtils._getPartialAmount(
|
||||
fillTakerTokenAmount,
|
||||
signedOrder.takerTokenAmount,
|
||||
signedOrder.makerFee,
|
||||
);
|
||||
await exchangeTradeEmulator.transferFromAsync(
|
||||
zrxTokenAddress, signedOrder.maker, signedOrder.feeRecipient, makerFeeAmount, TradeSide.Maker,
|
||||
zrxTokenAddress,
|
||||
signedOrder.maker,
|
||||
signedOrder.feeRecipient,
|
||||
makerFeeAmount,
|
||||
TradeSide.Maker,
|
||||
TransferType.Fee,
|
||||
);
|
||||
const takerFeeAmount = OrderValidationUtils.getPartialAmount(
|
||||
const takerFeeAmount = OrderValidationUtils._getPartialAmount(
|
||||
fillTakerTokenAmount,
|
||||
signedOrder.takerTokenAmount,
|
||||
signedOrder.takerFee,
|
||||
);
|
||||
await exchangeTradeEmulator.transferFromAsync(
|
||||
zrxTokenAddress, senderAddress, signedOrder.feeRecipient, takerFeeAmount, TradeSide.Taker,
|
||||
zrxTokenAddress,
|
||||
senderAddress,
|
||||
signedOrder.feeRecipient,
|
||||
takerFeeAmount,
|
||||
TradeSide.Taker,
|
||||
TransferType.Fee,
|
||||
);
|
||||
}
|
||||
private static validateRemainingFillAmountNotZeroOrThrow(
|
||||
takerTokenAmount: BigNumber, unavailableTakerTokenAmount: BigNumber,
|
||||
private static _validateRemainingFillAmountNotZeroOrThrow(
|
||||
takerTokenAmount: BigNumber,
|
||||
unavailableTakerTokenAmount: BigNumber,
|
||||
) {
|
||||
if (takerTokenAmount.eq(unavailableTakerTokenAmount)) {
|
||||
throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
||||
}
|
||||
}
|
||||
private static validateOrderNotExpiredOrThrow(expirationUnixTimestampSec: BigNumber) {
|
||||
private static _validateOrderNotExpiredOrThrow(expirationUnixTimestampSec: BigNumber) {
|
||||
const currentUnixTimestampSec = utils.getCurrentUnixTimestampSec();
|
||||
if (expirationUnixTimestampSec.lessThan(currentUnixTimestampSec)) {
|
||||
throw new Error(ExchangeContractErrs.OrderFillExpired);
|
||||
}
|
||||
}
|
||||
private static getPartialAmount(numerator: BigNumber, denominator: BigNumber,
|
||||
target: BigNumber): BigNumber {
|
||||
private static _getPartialAmount(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber {
|
||||
const fillMakerTokenAmount = numerator
|
||||
.mul(target)
|
||||
.div(denominator)
|
||||
@@ -83,44 +104,59 @@ export class OrderValidationUtils {
|
||||
return fillMakerTokenAmount;
|
||||
}
|
||||
constructor(exchangeWrapper: ExchangeWrapper) {
|
||||
this.exchangeWrapper = exchangeWrapper;
|
||||
this._exchangeWrapper = exchangeWrapper;
|
||||
}
|
||||
public async validateOrderFillableOrThrowAsync(
|
||||
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder, zrxTokenAddress: string,
|
||||
expectedFillTakerTokenAmount?: BigNumber): Promise<void> {
|
||||
exchangeTradeEmulator: ExchangeTransferSimulator,
|
||||
signedOrder: SignedOrder,
|
||||
zrxTokenAddress: string,
|
||||
expectedFillTakerTokenAmount?: BigNumber,
|
||||
): Promise<void> {
|
||||
const orderHash = utils.getOrderHashHex(signedOrder);
|
||||
const unavailableTakerTokenAmount = await this.exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
||||
OrderValidationUtils.validateRemainingFillAmountNotZeroOrThrow(
|
||||
signedOrder.takerTokenAmount, unavailableTakerTokenAmount,
|
||||
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
||||
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
|
||||
signedOrder.takerTokenAmount,
|
||||
unavailableTakerTokenAmount,
|
||||
);
|
||||
OrderValidationUtils.validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
|
||||
OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
|
||||
let fillTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
|
||||
if (!_.isUndefined(expectedFillTakerTokenAmount)) {
|
||||
fillTakerTokenAmount = expectedFillTakerTokenAmount;
|
||||
}
|
||||
const fillMakerTokenAmount = OrderValidationUtils.getPartialAmount(
|
||||
const fillMakerTokenAmount = OrderValidationUtils._getPartialAmount(
|
||||
fillTakerTokenAmount,
|
||||
signedOrder.takerTokenAmount,
|
||||
signedOrder.makerTokenAmount,
|
||||
);
|
||||
await exchangeTradeEmulator.transferFromAsync(
|
||||
signedOrder.makerTokenAddress, signedOrder.maker, signedOrder.taker, fillMakerTokenAmount,
|
||||
TradeSide.Maker, TransferType.Trade,
|
||||
signedOrder.makerTokenAddress,
|
||||
signedOrder.maker,
|
||||
signedOrder.taker,
|
||||
fillMakerTokenAmount,
|
||||
TradeSide.Maker,
|
||||
TransferType.Trade,
|
||||
);
|
||||
const makerFeeAmount = OrderValidationUtils.getPartialAmount(
|
||||
const makerFeeAmount = OrderValidationUtils._getPartialAmount(
|
||||
fillTakerTokenAmount,
|
||||
signedOrder.takerTokenAmount,
|
||||
signedOrder.makerFee,
|
||||
);
|
||||
await exchangeTradeEmulator.transferFromAsync(
|
||||
zrxTokenAddress, signedOrder.maker, signedOrder.feeRecipient, makerFeeAmount,
|
||||
TradeSide.Maker, TransferType.Fee,
|
||||
zrxTokenAddress,
|
||||
signedOrder.maker,
|
||||
signedOrder.feeRecipient,
|
||||
makerFeeAmount,
|
||||
TradeSide.Maker,
|
||||
TransferType.Fee,
|
||||
);
|
||||
}
|
||||
public async validateFillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder,
|
||||
fillTakerTokenAmount: BigNumber, takerAddress: string,
|
||||
zrxTokenAddress: string): Promise<BigNumber> {
|
||||
exchangeTradeEmulator: ExchangeTransferSimulator,
|
||||
signedOrder: SignedOrder,
|
||||
fillTakerTokenAmount: BigNumber,
|
||||
takerAddress: string,
|
||||
zrxTokenAddress: string,
|
||||
): Promise<BigNumber> {
|
||||
if (fillTakerTokenAmount.eq(0)) {
|
||||
throw new Error(ExchangeContractErrs.OrderFillAmountZero);
|
||||
}
|
||||
@@ -128,24 +164,31 @@ export class OrderValidationUtils {
|
||||
if (!ZeroEx.isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker)) {
|
||||
throw new Error(ZeroExError.InvalidSignature);
|
||||
}
|
||||
const unavailableTakerTokenAmount = await this.exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
||||
OrderValidationUtils.validateRemainingFillAmountNotZeroOrThrow(
|
||||
signedOrder.takerTokenAmount, unavailableTakerTokenAmount,
|
||||
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
||||
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
|
||||
signedOrder.takerTokenAmount,
|
||||
unavailableTakerTokenAmount,
|
||||
);
|
||||
if (signedOrder.taker !== constants.NULL_ADDRESS && signedOrder.taker !== takerAddress) {
|
||||
throw new Error(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker);
|
||||
}
|
||||
OrderValidationUtils.validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
|
||||
OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
|
||||
const remainingTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
|
||||
const filledTakerTokenAmount = remainingTakerTokenAmount.lessThan(fillTakerTokenAmount) ?
|
||||
remainingTakerTokenAmount :
|
||||
fillTakerTokenAmount;
|
||||
const filledTakerTokenAmount = remainingTakerTokenAmount.lessThan(fillTakerTokenAmount)
|
||||
? remainingTakerTokenAmount
|
||||
: fillTakerTokenAmount;
|
||||
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator, signedOrder, filledTakerTokenAmount, takerAddress, zrxTokenAddress,
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
filledTakerTokenAmount,
|
||||
takerAddress,
|
||||
zrxTokenAddress,
|
||||
);
|
||||
|
||||
const wouldRoundingErrorOccur = await this.exchangeWrapper.isRoundingErrorAsync(
|
||||
filledTakerTokenAmount, signedOrder.takerTokenAmount, signedOrder.makerTokenAmount,
|
||||
const wouldRoundingErrorOccur = await this._exchangeWrapper.isRoundingErrorAsync(
|
||||
filledTakerTokenAmount,
|
||||
signedOrder.takerTokenAmount,
|
||||
signedOrder.makerTokenAmount,
|
||||
);
|
||||
if (wouldRoundingErrorOccur) {
|
||||
throw new Error(ExchangeContractErrs.OrderFillRoundingError);
|
||||
@@ -153,10 +196,18 @@ export class OrderValidationUtils {
|
||||
return filledTakerTokenAmount;
|
||||
}
|
||||
public async validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder,
|
||||
fillTakerTokenAmount: BigNumber, takerAddress: string, zrxTokenAddress: string): Promise<void> {
|
||||
exchangeTradeEmulator: ExchangeTransferSimulator,
|
||||
signedOrder: SignedOrder,
|
||||
fillTakerTokenAmount: BigNumber,
|
||||
takerAddress: string,
|
||||
zrxTokenAddress: string,
|
||||
): Promise<void> {
|
||||
const filledTakerTokenAmount = await this.validateFillOrderThrowIfInvalidAsync(
|
||||
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress,
|
||||
exchangeTradeEmulator,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount,
|
||||
takerAddress,
|
||||
zrxTokenAddress,
|
||||
);
|
||||
if (filledTakerTokenAmount !== fillTakerTokenAmount) {
|
||||
throw new Error(ExchangeContractErrs.InsufficientRemainingFillAmount);
|
||||
|
@@ -11,7 +11,8 @@ export const signatureUtils = {
|
||||
msgHashBuff,
|
||||
signature.v,
|
||||
ethUtil.toBuffer(signature.r),
|
||||
ethUtil.toBuffer(signature.s));
|
||||
ethUtil.toBuffer(signature.s),
|
||||
);
|
||||
const retrievedAddress = ethUtil.bufferToHex(ethUtil.pubToAddress(pubKey));
|
||||
return retrievedAddress === signerAddress;
|
||||
} catch (err) {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import BN = require('bn.js');
|
||||
import * as ethABI from 'ethereumjs-abi';
|
||||
import * as ethUtil from 'ethereumjs-util';
|
||||
@@ -37,11 +37,26 @@ export const utils = {
|
||||
{ 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.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);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
import 'mocha';
|
||||
@@ -41,11 +41,11 @@ describe('ZeroEx library', () => {
|
||||
|
||||
// Check that all nested web3 wrapper instances return the updated provider
|
||||
const nestedWeb3WrapperProvider = (zeroEx as any)._web3Wrapper.getCurrentProvider();
|
||||
expect((nestedWeb3WrapperProvider).zeroExTestId).to.be.a('number');
|
||||
expect(nestedWeb3WrapperProvider.zeroExTestId).to.be.a('number');
|
||||
const exchangeWeb3WrapperProvider = (zeroEx.exchange as any)._web3Wrapper.getCurrentProvider();
|
||||
expect((exchangeWeb3WrapperProvider).zeroExTestId).to.be.a('number');
|
||||
expect(exchangeWeb3WrapperProvider.zeroExTestId).to.be.a('number');
|
||||
const tokenRegistryWeb3WrapperProvider = (zeroEx.tokenRegistry as any)._web3Wrapper.getCurrentProvider();
|
||||
expect((tokenRegistryWeb3WrapperProvider).zeroExTestId).to.be.a('number');
|
||||
expect(tokenRegistryWeb3WrapperProvider.zeroExTestId).to.be.a('number');
|
||||
});
|
||||
});
|
||||
describe('#isValidSignature', () => {
|
||||
@@ -58,21 +58,24 @@ describe('ZeroEx library', () => {
|
||||
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
|
||||
};
|
||||
const address = '0x5409ed021d9299bf6814279a6a1411a7e866a631';
|
||||
it('should return false if the data doesn\'t pertain to the signature & address', async () => {
|
||||
it("should return false if the data doesn't pertain to the signature & address", async () => {
|
||||
expect(ZeroEx.isValidSignature('0x0', signature, address)).to.be.false();
|
||||
return expect(
|
||||
(zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync('0x0', signature, address),
|
||||
).to.become(false);
|
||||
});
|
||||
it('should return false if the address doesn\'t pertain to the signature & data', async () => {
|
||||
it("should return false if the address doesn't pertain to the signature & data", async () => {
|
||||
const validUnrelatedAddress = '0x8b0292b11a196601ed2ce54b665cafeca0347d42';
|
||||
expect(ZeroEx.isValidSignature(dataHex, signature, validUnrelatedAddress)).to.be.false();
|
||||
return expect(
|
||||
(zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync(dataHex, signature,
|
||||
validUnrelatedAddress),
|
||||
(zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync(
|
||||
dataHex,
|
||||
signature,
|
||||
validUnrelatedAddress,
|
||||
),
|
||||
).to.become(false);
|
||||
});
|
||||
it('should return false if the signature doesn\'t pertain to the dataHex & address', async () => {
|
||||
it("should return false if the signature doesn't pertain to the dataHex & address", async () => {
|
||||
const wrongSignature = _.assign({}, signature, { v: 28 });
|
||||
expect(ZeroEx.isValidSignature(dataHex, wrongSignature, address)).to.be.false();
|
||||
return expect(
|
||||
@@ -114,6 +117,13 @@ describe('ZeroEx library', () => {
|
||||
});
|
||||
});
|
||||
describe('#toUnitAmount', () => {
|
||||
it('should throw if invalid baseUnit amount supplied as argument', () => {
|
||||
const invalidBaseUnitAmount = new BigNumber(1000000000.4);
|
||||
const decimals = 6;
|
||||
expect(() => ZeroEx.toUnitAmount(invalidBaseUnitAmount, decimals)).to.throw(
|
||||
'amount should be in baseUnits (no decimals), found value: 1000000000.4',
|
||||
);
|
||||
});
|
||||
it('Should return the expected unit amount for the decimals passed in', () => {
|
||||
const baseUnitAmount = new BigNumber(1000000000);
|
||||
const decimals = 6;
|
||||
@@ -130,6 +140,13 @@ describe('ZeroEx library', () => {
|
||||
const expectedUnitAmount = new BigNumber(1000000000);
|
||||
expect(baseUnitAmount).to.be.bignumber.equal(expectedUnitAmount);
|
||||
});
|
||||
it('should throw if unitAmount has more decimals then specified as the max decimal precision', () => {
|
||||
const unitAmount = new BigNumber(0.823091);
|
||||
const decimals = 5;
|
||||
expect(() => ZeroEx.toBaseUnitAmount(unitAmount, decimals)).to.throw(
|
||||
'Invalid unit amount: 0.823091 - Too many decimal places',
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('#getOrderHashHex', () => {
|
||||
const expectedOrderHash = '0x39da987067a3c9e5f1617694f1301326ba8c8b0498ebef5df4863bed394e3c83';
|
||||
@@ -155,10 +172,10 @@ describe('ZeroEx library', () => {
|
||||
it('throws a readable error message if taker format is invalid', async () => {
|
||||
const orderWithInvalidtakerFormat = {
|
||||
...order,
|
||||
taker: null as any as string,
|
||||
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';
|
||||
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);
|
||||
});
|
||||
});
|
||||
@@ -186,16 +203,15 @@ describe('ZeroEx library', () => {
|
||||
});
|
||||
it('should return the correct ECSignature for signatureHex concatenated as R + S + V', async () => {
|
||||
const orderHash = '0x34decbedc118904df65f379a175bb39ca18209d6ce41d5ed549d54e6e0a95004';
|
||||
// tslint:disable-next-line: max-line-length
|
||||
const signature = '0x22109d11d79cb8bf96ed88625e1cd9558800c4073332a9a02857499883ee5ce3050aa3cc1f2c435e67e114cdce54b9527b4f50548342401bc5d2b77adbdacb021b';
|
||||
const signature =
|
||||
'0x22109d11d79cb8bf96ed88625e1cd9558800c4073332a9a02857499883ee5ce3050aa3cc1f2c435e67e114cdce54b9527b4f50548342401bc5d2b77adbdacb021b';
|
||||
const expectedECSignature = {
|
||||
v: 27,
|
||||
r: '0x22109d11d79cb8bf96ed88625e1cd9558800c4073332a9a02857499883ee5ce3',
|
||||
s: '0x050aa3cc1f2c435e67e114cdce54b9527b4f50548342401bc5d2b77adbdacb02',
|
||||
};
|
||||
stubs = [
|
||||
Sinon.stub((zeroEx as any)._web3Wrapper, 'signTransactionAsync')
|
||||
.returns(Promise.resolve(signature)),
|
||||
Sinon.stub((zeroEx as any)._web3Wrapper, 'signTransactionAsync').returns(Promise.resolve(signature)),
|
||||
Sinon.stub(ZeroEx, 'isValidSignature').returns(true),
|
||||
];
|
||||
|
||||
@@ -204,16 +220,15 @@ describe('ZeroEx library', () => {
|
||||
});
|
||||
it('should return the correct ECSignature for signatureHex concatenated as V + R + S', async () => {
|
||||
const orderHash = '0xc793e33ffded933b76f2f48d9aa3339fc090399d5e7f5dec8d3660f5480793f7';
|
||||
// tslint:disable-next-line: max-line-length
|
||||
const signature = '0x1bc80bedc6756722672753413efdd749b5adbd4fd552595f59c13427407ee9aee02dea66f25a608bbae457e020fb6decb763deb8b7192abab624997242da248960';
|
||||
const signature =
|
||||
'0x1bc80bedc6756722672753413efdd749b5adbd4fd552595f59c13427407ee9aee02dea66f25a608bbae457e020fb6decb763deb8b7192abab624997242da248960';
|
||||
const expectedECSignature = {
|
||||
v: 27,
|
||||
r: '0xc80bedc6756722672753413efdd749b5adbd4fd552595f59c13427407ee9aee0',
|
||||
s: '0x2dea66f25a608bbae457e020fb6decb763deb8b7192abab624997242da248960',
|
||||
};
|
||||
stubs = [
|
||||
Sinon.stub((zeroEx as any)._web3Wrapper, 'signTransactionAsync')
|
||||
.returns(Promise.resolve(signature)),
|
||||
Sinon.stub((zeroEx as any)._web3Wrapper, 'signTransactionAsync').returns(Promise.resolve(signature)),
|
||||
Sinon.stub(ZeroEx, 'isValidSignature').returns(true),
|
||||
];
|
||||
|
||||
@@ -259,8 +274,9 @@ describe('ZeroEx library', () => {
|
||||
networkId: constants.TESTRPC_NETWORK_ID,
|
||||
};
|
||||
const zeroExWithWrongTokenRegistryAddress = new ZeroEx(web3.currentProvider, zeroExConfig);
|
||||
expect(zeroExWithWrongTokenRegistryAddress.tokenRegistry.getContractAddress())
|
||||
.to.be.equal(ZeroEx.NULL_ADDRESS);
|
||||
expect(zeroExWithWrongTokenRegistryAddress.tokenRegistry.getContractAddress()).to.be.equal(
|
||||
ZeroEx.NULL_ADDRESS,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -19,22 +19,25 @@ describe('Assertion library', () => {
|
||||
it('throws when address is invalid', async () => {
|
||||
const address = '0xdeadbeef';
|
||||
const varName = 'address';
|
||||
return expect(assert.isSenderAddressAsync(varName, address, (zeroEx as any)._web3Wrapper))
|
||||
.to.be.rejectedWith(`Expected ${varName} to be of type ETHAddressHex, encountered: ${address}`);
|
||||
return expect(
|
||||
assert.isSenderAddressAsync(varName, address, (zeroEx as any)._web3Wrapper),
|
||||
).to.be.rejectedWith(`Expected ${varName} to be of type ETHAddressHex, encountered: ${address}`);
|
||||
});
|
||||
it('throws when address is unavailable', async () => {
|
||||
const validUnrelatedAddress = '0x8b0292b11a196601eddce54b665cafeca0347d42';
|
||||
const varName = 'address';
|
||||
return expect(assert.isSenderAddressAsync(varName, validUnrelatedAddress, (zeroEx as any)._web3Wrapper))
|
||||
.to.be.rejectedWith(
|
||||
return expect(
|
||||
assert.isSenderAddressAsync(varName, validUnrelatedAddress, (zeroEx as any)._web3Wrapper),
|
||||
).to.be.rejectedWith(
|
||||
`Specified ${varName} ${validUnrelatedAddress} isn't available through the supplied web3 provider`,
|
||||
);
|
||||
});
|
||||
it('doesn\'t throw if address is available', async () => {
|
||||
it("doesn't throw if address is available", async () => {
|
||||
const availableAddress = (await zeroEx.getAvailableAddressesAsync())[0];
|
||||
const varName = 'address';
|
||||
return expect(assert.isSenderAddressAsync(varName, availableAddress, (zeroEx as any)._web3Wrapper))
|
||||
.to.become(undefined);
|
||||
return expect(
|
||||
assert.isSenderAddressAsync(varName, availableAddress, (zeroEx as any)._web3Wrapper),
|
||||
).to.become(undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import 'mocha';
|
||||
import * as Web3 from 'web3';
|
||||
@@ -22,6 +22,7 @@ import {DoneCallback} from '../src/types';
|
||||
|
||||
import { chaiSetup } from './utils/chai_setup';
|
||||
import { constants } from './utils/constants';
|
||||
import { reportNodeCallbackErrors } from './utils/report_callback_errors';
|
||||
import { TokenUtils } from './utils/token_utils';
|
||||
import { web3Factory } from './utils/web3_factory';
|
||||
|
||||
@@ -153,8 +154,8 @@ describe('EtherTokenWrapper', () => {
|
||||
// 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();
|
||||
const callback = reportNodeCallbackErrors(done)(
|
||||
(logEvent: DecodedLogEvent<TransferContractEventArgs>) => {
|
||||
expect(logEvent).to.not.be.undefined();
|
||||
expect(logEvent.isRemoved).to.be.false();
|
||||
expect(logEvent.log.logIndex).to.be.equal(0);
|
||||
@@ -164,107 +165,126 @@ describe('EtherTokenWrapper', () => {
|
||||
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);
|
||||
zeroEx.etherToken.subscribe(etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callback);
|
||||
await zeroEx.token.transferAsync(
|
||||
etherTokenAddress, addressWithETH, addressWithoutFunds, transferAmount,
|
||||
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();
|
||||
const callback = reportNodeCallbackErrors(done)(
|
||||
(logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
||||
expect(logEvent).to.not.be.undefined();
|
||||
expect(logEvent.isRemoved).to.be.false();
|
||||
const args = logEvent.log.args;
|
||||
expect(args._owner).to.be.equal(addressWithETH);
|
||||
expect(args._spender).to.be.equal(addressWithoutFunds);
|
||||
expect(args._value).to.be.bignumber.equal(allowanceAmount);
|
||||
done();
|
||||
};
|
||||
zeroEx.etherToken.subscribe(
|
||||
etherTokenAddress, EtherTokenEvents.Approval, indexFilterValues, callback);
|
||||
},
|
||||
);
|
||||
zeroEx.etherToken.subscribe(etherTokenAddress, EtherTokenEvents.Approval, indexFilterValues, callback);
|
||||
await zeroEx.token.setAllowanceAsync(
|
||||
etherTokenAddress, addressWithETH, addressWithoutFunds, allowanceAmount,
|
||||
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();
|
||||
const callback = reportNodeCallbackErrors(done)(
|
||||
(logEvent: DecodedLogEvent<DepositContractEventArgs>) => {
|
||||
expect(logEvent).to.not.be.undefined();
|
||||
expect(logEvent.isRemoved).to.be.false();
|
||||
const args = logEvent.log.args;
|
||||
expect(args._owner).to.be.equal(addressWithETH);
|
||||
expect(args._value).to.be.bignumber.equal(depositAmount);
|
||||
done();
|
||||
};
|
||||
zeroEx.etherToken.subscribe(
|
||||
etherTokenAddress, EtherTokenEvents.Deposit, indexFilterValues, callback);
|
||||
await zeroEx.etherToken.depositAsync(
|
||||
etherTokenAddress, depositAmount, addressWithETH,
|
||||
},
|
||||
);
|
||||
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();
|
||||
const callback = reportNodeCallbackErrors(done)(
|
||||
(logEvent: DecodedLogEvent<WithdrawalContractEventArgs>) => {
|
||||
expect(logEvent).to.not.be.undefined();
|
||||
expect(logEvent.isRemoved).to.be.false();
|
||||
const args = logEvent.log.args;
|
||||
expect(args._owner).to.be.equal(addressWithETH);
|
||||
expect(args._value).to.be.bignumber.equal(depositAmount);
|
||||
done();
|
||||
};
|
||||
await zeroEx.etherToken.depositAsync(
|
||||
etherTokenAddress, depositAmount, addressWithETH,
|
||||
},
|
||||
);
|
||||
await zeroEx.etherToken.depositAsync(etherTokenAddress, depositAmount, addressWithETH);
|
||||
zeroEx.etherToken.subscribe(
|
||||
etherTokenAddress, EtherTokenEvents.Withdrawal, indexFilterValues, callback);
|
||||
await zeroEx.etherToken.withdrawAsync(
|
||||
etherTokenAddress, withdrawalAmount, addressWithETH,
|
||||
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>) => {
|
||||
const callbackNeverToBeCalled = reportNodeCallbackErrors(done)(
|
||||
(logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
||||
done(new Error('Expected this subscription to have been cancelled'));
|
||||
};
|
||||
zeroEx.etherToken.subscribe(
|
||||
etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled,
|
||||
},
|
||||
);
|
||||
const callbackToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
||||
done();
|
||||
};
|
||||
zeroEx.etherToken.subscribe(
|
||||
etherTokenAddress,
|
||||
EtherTokenEvents.Transfer,
|
||||
indexFilterValues,
|
||||
callbackNeverToBeCalled,
|
||||
);
|
||||
const callbackToBeCalled = reportNodeCallbackErrors(done)();
|
||||
const newProvider = web3Factory.getRpcProvider();
|
||||
zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID);
|
||||
await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
|
||||
zeroEx.etherToken.subscribe(
|
||||
etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callbackToBeCalled,
|
||||
etherTokenAddress,
|
||||
EtherTokenEvents.Transfer,
|
||||
indexFilterValues,
|
||||
callbackToBeCalled,
|
||||
);
|
||||
await zeroEx.token.transferAsync(
|
||||
etherTokenAddress, addressWithETH, addressWithoutFunds, transferAmount,
|
||||
etherTokenAddress,
|
||||
addressWithETH,
|
||||
addressWithoutFunds,
|
||||
transferAmount,
|
||||
);
|
||||
})().catch(done);
|
||||
});
|
||||
it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
||||
const callbackNeverToBeCalled = reportNodeCallbackErrors(done)(
|
||||
(logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
||||
done(new Error('Expected this subscription to have been cancelled'));
|
||||
};
|
||||
},
|
||||
);
|
||||
await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
|
||||
const subscriptionToken = zeroEx.etherToken.subscribe(
|
||||
etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled);
|
||||
etherTokenAddress,
|
||||
EtherTokenEvents.Transfer,
|
||||
indexFilterValues,
|
||||
callbackNeverToBeCalled,
|
||||
);
|
||||
zeroEx.etherToken.unsubscribe(subscriptionToken);
|
||||
await zeroEx.token.transferAsync(
|
||||
etherTokenAddress, addressWithETH, addressWithoutFunds, transferAmount,
|
||||
etherTokenAddress,
|
||||
addressWithETH,
|
||||
addressWithoutFunds,
|
||||
transferAmount,
|
||||
);
|
||||
done();
|
||||
})().catch(done);
|
||||
@@ -291,7 +311,10 @@ describe('EtherTokenWrapper', () => {
|
||||
const eventName = EtherTokenEvents.Approval;
|
||||
const indexFilterValues = {};
|
||||
const logs = await zeroEx.etherToken.getLogsAsync<ApprovalContractEventArgs>(
|
||||
etherTokenAddress, eventName, blockRange, indexFilterValues,
|
||||
etherTokenAddress,
|
||||
eventName,
|
||||
blockRange,
|
||||
indexFilterValues,
|
||||
);
|
||||
expect(logs).to.have.length(1);
|
||||
const args = logs[0].args;
|
||||
@@ -305,7 +328,10 @@ describe('EtherTokenWrapper', () => {
|
||||
const eventName = EtherTokenEvents.Deposit;
|
||||
const indexFilterValues = {};
|
||||
const logs = await zeroEx.etherToken.getLogsAsync<DepositContractEventArgs>(
|
||||
etherTokenAddress, eventName, blockRange, indexFilterValues,
|
||||
etherTokenAddress,
|
||||
eventName,
|
||||
blockRange,
|
||||
indexFilterValues,
|
||||
);
|
||||
expect(logs).to.have.length(1);
|
||||
const args = logs[0].args;
|
||||
@@ -319,7 +345,10 @@ describe('EtherTokenWrapper', () => {
|
||||
const differentEventName = EtherTokenEvents.Transfer;
|
||||
const indexFilterValues = {};
|
||||
const logs = await zeroEx.etherToken.getLogsAsync(
|
||||
etherTokenAddress, differentEventName, blockRange, indexFilterValues,
|
||||
etherTokenAddress,
|
||||
differentEventName,
|
||||
blockRange,
|
||||
indexFilterValues,
|
||||
);
|
||||
expect(logs).to.have.length(0);
|
||||
});
|
||||
@@ -333,7 +362,10 @@ describe('EtherTokenWrapper', () => {
|
||||
_owner: addressWithETH,
|
||||
};
|
||||
const logs = await zeroEx.etherToken.getLogsAsync<ApprovalContractEventArgs>(
|
||||
etherTokenAddress, eventName, blockRange, indexFilterValues,
|
||||
etherTokenAddress,
|
||||
eventName,
|
||||
blockRange,
|
||||
indexFilterValues,
|
||||
);
|
||||
expect(logs).to.have.length(1);
|
||||
const args = logs[0].args;
|
||||
|
@@ -5,13 +5,12 @@ import 'mocha';
|
||||
import * as Sinon from 'sinon';
|
||||
import * as Web3 from 'web3';
|
||||
|
||||
import {
|
||||
LogEvent,
|
||||
} from '../src';
|
||||
import { LogEvent } from '../src';
|
||||
import { EventWatcher } from '../src/order_watcher/event_watcher';
|
||||
import { DoneCallback } from '../src/types';
|
||||
|
||||
import { chaiSetup } from './utils/chai_setup';
|
||||
import { reportNodeCallbackErrors } from './utils/report_callback_errors';
|
||||
import { web3Factory } from './utils/web3_factory';
|
||||
|
||||
chaiSetup.configure();
|
||||
@@ -79,13 +78,14 @@ describe('EventWatcher', () => {
|
||||
const getLogsStub = Sinon.stub(web3Wrapper, 'getLogsAsync');
|
||||
getLogsStub.onCall(0).returns(logs);
|
||||
stubs.push(getLogsStub);
|
||||
const callback = (event: LogEvent) => {
|
||||
const expectedToBeCalledOnce = false;
|
||||
const callback = reportNodeCallbackErrors(done, expectedToBeCalledOnce)((event: LogEvent) => {
|
||||
const expectedLogEvent = expectedLogEvents.shift();
|
||||
expect(event).to.be.deep.equal(expectedLogEvent);
|
||||
if (_.isEmpty(expectedLogEvents)) {
|
||||
done();
|
||||
}
|
||||
};
|
||||
});
|
||||
eventWatcher.subscribe(callback);
|
||||
});
|
||||
it('correctly computes the difference and emits only changes', (done: DoneCallback) => {
|
||||
@@ -113,13 +113,14 @@ describe('EventWatcher', () => {
|
||||
getLogsStub.onCall(0).returns(initialLogs);
|
||||
getLogsStub.onCall(1).returns(changedLogs);
|
||||
stubs.push(getLogsStub);
|
||||
const callback = (event: LogEvent) => {
|
||||
const expectedToBeCalledOnce = false;
|
||||
const callback = reportNodeCallbackErrors(done, expectedToBeCalledOnce)((event: LogEvent) => {
|
||||
const expectedLogEvent = expectedLogEvents.shift();
|
||||
expect(event).to.be.deep.equal(expectedLogEvent);
|
||||
if (_.isEmpty(expectedLogEvents)) {
|
||||
done();
|
||||
}
|
||||
};
|
||||
});
|
||||
eventWatcher.subscribe(callback);
|
||||
});
|
||||
});
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
|
||||
import { ExchangeContractErrs, Token, ZeroEx } from '../src';
|
||||
@@ -45,17 +45,31 @@ describe('ExchangeTransferSimulator', () => {
|
||||
beforeEach(() => {
|
||||
exchangeTransferSimulator = new ExchangeTransferSimulator(zeroEx.token, BlockParamLiteral.Latest);
|
||||
});
|
||||
it('throws if the user doesn\'t have enough allowance', async () => {
|
||||
return expect(exchangeTransferSimulator.transferFromAsync(
|
||||
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade,
|
||||
)).to.be.rejectedWith(ExchangeContractErrs.InsufficientTakerAllowance);
|
||||
it("throws if the user doesn't have enough allowance", async () => {
|
||||
return expect(
|
||||
exchangeTransferSimulator.transferFromAsync(
|
||||
exampleTokenAddress,
|
||||
sender,
|
||||
recipient,
|
||||
transferAmount,
|
||||
TradeSide.Taker,
|
||||
TransferType.Trade,
|
||||
),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.InsufficientTakerAllowance);
|
||||
});
|
||||
it('throws if the user doesn\'t have enough balance', async () => {
|
||||
it("throws if the user doesn't have enough balance", async () => {
|
||||
txHash = await zeroEx.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount);
|
||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||
return expect(exchangeTransferSimulator.transferFromAsync(
|
||||
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Maker, TransferType.Trade,
|
||||
)).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance);
|
||||
return expect(
|
||||
exchangeTransferSimulator.transferFromAsync(
|
||||
exampleTokenAddress,
|
||||
sender,
|
||||
recipient,
|
||||
transferAmount,
|
||||
TradeSide.Maker,
|
||||
TransferType.Trade,
|
||||
),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance);
|
||||
});
|
||||
it('updates balances and proxyAllowance after transfer', async () => {
|
||||
txHash = await zeroEx.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount);
|
||||
@@ -63,9 +77,14 @@ describe('ExchangeTransferSimulator', () => {
|
||||
txHash = await zeroEx.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount);
|
||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||
await exchangeTransferSimulator.transferFromAsync(
|
||||
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade,
|
||||
exampleTokenAddress,
|
||||
sender,
|
||||
recipient,
|
||||
transferAmount,
|
||||
TradeSide.Taker,
|
||||
TransferType.Trade,
|
||||
);
|
||||
const store = (exchangeTransferSimulator as any).store;
|
||||
const store = (exchangeTransferSimulator as any)._store;
|
||||
const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender);
|
||||
const recipientBalance = await store.getBalanceAsync(exampleTokenAddress, recipient);
|
||||
const senderProxyAllowance = await store.getProxyAllowanceAsync(exampleTokenAddress, sender);
|
||||
@@ -73,15 +92,20 @@ describe('ExchangeTransferSimulator', () => {
|
||||
expect(recipientBalance).to.be.bignumber.equal(transferAmount);
|
||||
expect(senderProxyAllowance).to.be.bignumber.equal(0);
|
||||
});
|
||||
it('doesn\'t update proxyAllowance after transfer if unlimited', async () => {
|
||||
it("doesn't update proxyAllowance after transfer if unlimited", async () => {
|
||||
txHash = await zeroEx.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount);
|
||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||
txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(exampleTokenAddress, sender);
|
||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||
await exchangeTransferSimulator.transferFromAsync(
|
||||
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade,
|
||||
exampleTokenAddress,
|
||||
sender,
|
||||
recipient,
|
||||
transferAmount,
|
||||
TradeSide.Taker,
|
||||
TransferType.Trade,
|
||||
);
|
||||
const store = (exchangeTransferSimulator as any).store;
|
||||
const store = (exchangeTransferSimulator as any)._store;
|
||||
const senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender);
|
||||
const recipientBalance = await store.getBalanceAsync(exampleTokenAddress, recipient);
|
||||
const senderProxyAllowance = await store.getProxyAllowanceAsync(exampleTokenAddress, sender);
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
import 'mocha';
|
||||
import * as Web3 from 'web3';
|
||||
|
||||
@@ -22,6 +23,7 @@ import {BlockParamLiteral, DoneCallback} from '../src/types';
|
||||
import { chaiSetup } from './utils/chai_setup';
|
||||
import { constants } from './utils/constants';
|
||||
import { FillScenarios } from './utils/fill_scenarios';
|
||||
import { reportNodeCallbackErrors } from './utils/report_callback_errors';
|
||||
import { TokenUtils } from './utils/token_utils';
|
||||
import { web3Factory } from './utils/web3_factory';
|
||||
|
||||
@@ -80,10 +82,18 @@ describe('ExchangeWrapper', () => {
|
||||
const fillableAmount = new BigNumber(5);
|
||||
const partialFillTakerAmount = new BigNumber(2);
|
||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
const anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
const orderFillRequests = [
|
||||
{
|
||||
@@ -103,7 +113,11 @@ describe('ExchangeWrapper', () => {
|
||||
const fillableAmount = new BigNumber(5);
|
||||
beforeEach(async () => {
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
orderFillRequests = [
|
||||
{
|
||||
@@ -113,18 +127,23 @@ describe('ExchangeWrapper', () => {
|
||||
];
|
||||
});
|
||||
it('should validate when orderTransactionOptions are not present', async () => {
|
||||
return expect(zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress))
|
||||
.to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
return expect(
|
||||
zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
});
|
||||
it('should validate when orderTransactionOptions specify to validate', async () => {
|
||||
return expect(zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress, {
|
||||
return expect(
|
||||
zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress, {
|
||||
shouldValidate: true,
|
||||
})).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
}),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
});
|
||||
it('should not validate when orderTransactionOptions specify not to validate', async () => {
|
||||
return expect(zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress, {
|
||||
return expect(
|
||||
zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress, {
|
||||
shouldValidate: false,
|
||||
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
}),
|
||||
).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -133,57 +152,78 @@ describe('ExchangeWrapper', () => {
|
||||
const fillableAmount = new BigNumber(5);
|
||||
beforeEach(async () => {
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
});
|
||||
describe('successful fills', () => {
|
||||
it('should fill a valid order', async () => {
|
||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress))
|
||||
.to.be.bignumber.equal(fillableAmount);
|
||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress))
|
||||
.to.be.bignumber.equal(0);
|
||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress))
|
||||
.to.be.bignumber.equal(0);
|
||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress))
|
||||
.to.be.bignumber.equal(fillableAmount);
|
||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal(
|
||||
fillableAmount,
|
||||
);
|
||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal(
|
||||
0,
|
||||
);
|
||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal(
|
||||
0,
|
||||
);
|
||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal(
|
||||
fillableAmount,
|
||||
);
|
||||
await zeroEx.exchange.fillOrKillOrderAsync(signedOrder, takerTokenFillAmount, takerAddress);
|
||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress))
|
||||
.to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount));
|
||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress))
|
||||
.to.be.bignumber.equal(takerTokenFillAmount);
|
||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress))
|
||||
.to.be.bignumber.equal(takerTokenFillAmount);
|
||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress))
|
||||
.to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount));
|
||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal(
|
||||
fillableAmount.minus(takerTokenFillAmount),
|
||||
);
|
||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal(
|
||||
takerTokenFillAmount,
|
||||
);
|
||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal(
|
||||
takerTokenFillAmount,
|
||||
);
|
||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal(
|
||||
fillableAmount.minus(takerTokenFillAmount),
|
||||
);
|
||||
});
|
||||
it('should partially fill a valid order', async () => {
|
||||
const partialFillAmount = new BigNumber(3);
|
||||
await zeroEx.exchange.fillOrKillOrderAsync(signedOrder, partialFillAmount, takerAddress);
|
||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress))
|
||||
.to.be.bignumber.equal(fillableAmount.minus(partialFillAmount));
|
||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress))
|
||||
.to.be.bignumber.equal(partialFillAmount);
|
||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress))
|
||||
.to.be.bignumber.equal(partialFillAmount);
|
||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress))
|
||||
.to.be.bignumber.equal(fillableAmount.minus(partialFillAmount));
|
||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal(
|
||||
fillableAmount.minus(partialFillAmount),
|
||||
);
|
||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal(
|
||||
partialFillAmount,
|
||||
);
|
||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal(
|
||||
partialFillAmount,
|
||||
);
|
||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal(
|
||||
fillableAmount.minus(partialFillAmount),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('order transaction options', () => {
|
||||
const emptyFillableAmount = new BigNumber(0);
|
||||
it('should validate when orderTransactionOptions are not present', async () => {
|
||||
return expect(zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress))
|
||||
.to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
return expect(
|
||||
zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
});
|
||||
it('should validate when orderTransactionOptions specify to validate', async () => {
|
||||
return expect(zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress, {
|
||||
return expect(
|
||||
zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress, {
|
||||
shouldValidate: true,
|
||||
})).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
}),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
});
|
||||
it('should not validate when orderTransactionOptions specify not to validate', async () => {
|
||||
return expect(zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress, {
|
||||
return expect(
|
||||
zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress, {
|
||||
shouldValidate: false,
|
||||
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
}),
|
||||
).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -209,57 +249,96 @@ describe('ExchangeWrapper', () => {
|
||||
describe('successful fills', () => {
|
||||
it('should fill a valid order', async () => {
|
||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
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,
|
||||
);
|
||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress))
|
||||
.to.be.bignumber.equal(fillableAmount);
|
||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress))
|
||||
.to.be.bignumber.equal(0);
|
||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress))
|
||||
.to.be.bignumber.equal(0);
|
||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress))
|
||||
.to.be.bignumber.equal(fillableAmount);
|
||||
const txHash = await zeroEx.exchange.fillOrderAsync(
|
||||
signedOrder, takerTokenFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress);
|
||||
signedOrder,
|
||||
takerTokenFillAmount,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress))
|
||||
.to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount));
|
||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress))
|
||||
.to.be.bignumber.equal(takerTokenFillAmount);
|
||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress))
|
||||
.to.be.bignumber.equal(takerTokenFillAmount);
|
||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress))
|
||||
.to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount));
|
||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal(
|
||||
fillableAmount.minus(takerTokenFillAmount),
|
||||
);
|
||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal(
|
||||
takerTokenFillAmount,
|
||||
);
|
||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal(
|
||||
takerTokenFillAmount,
|
||||
);
|
||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal(
|
||||
fillableAmount.minus(takerTokenFillAmount),
|
||||
);
|
||||
});
|
||||
it('should partially fill the valid order', async () => {
|
||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
const partialFillAmount = new BigNumber(3);
|
||||
const txHash = await zeroEx.exchange.fillOrderAsync(
|
||||
signedOrder, partialFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress);
|
||||
signedOrder,
|
||||
partialFillAmount,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress))
|
||||
.to.be.bignumber.equal(fillableAmount.minus(partialFillAmount));
|
||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress))
|
||||
.to.be.bignumber.equal(partialFillAmount);
|
||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress))
|
||||
.to.be.bignumber.equal(partialFillAmount);
|
||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress))
|
||||
.to.be.bignumber.equal(fillableAmount.minus(partialFillAmount));
|
||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal(
|
||||
fillableAmount.minus(partialFillAmount),
|
||||
);
|
||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal(
|
||||
partialFillAmount,
|
||||
);
|
||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal(
|
||||
partialFillAmount,
|
||||
);
|
||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal(
|
||||
fillableAmount.minus(partialFillAmount),
|
||||
);
|
||||
});
|
||||
it('should fill the valid orders with fees', async () => {
|
||||
const makerFee = new BigNumber(1);
|
||||
const takerFee = new BigNumber(2);
|
||||
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerFee, takerFee,
|
||||
makerAddress, takerAddress, fillableAmount, feeRecipient,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerFee,
|
||||
takerFee,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
feeRecipient,
|
||||
);
|
||||
const txHash = await zeroEx.exchange.fillOrderAsync(
|
||||
signedOrder, takerTokenFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress);
|
||||
signedOrder,
|
||||
takerTokenFillAmount,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||
expect(await zeroEx.token.getBalanceAsync(zrxTokenAddress, feeRecipient))
|
||||
.to.be.bignumber.equal(makerFee.plus(takerFee));
|
||||
expect(await zeroEx.token.getBalanceAsync(zrxTokenAddress, feeRecipient)).to.be.bignumber.equal(
|
||||
makerFee.plus(takerFee),
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('order transaction options', () => {
|
||||
@@ -267,25 +346,48 @@ describe('ExchangeWrapper', () => {
|
||||
const emptyFillTakerAmount = new BigNumber(0);
|
||||
beforeEach(async () => {
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
});
|
||||
it('should validate when orderTransactionOptions are not present', async () => {
|
||||
return expect(zeroEx.exchange.fillOrderAsync(
|
||||
signedOrder, emptyFillTakerAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
|
||||
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
return expect(
|
||||
zeroEx.exchange.fillOrderAsync(
|
||||
signedOrder,
|
||||
emptyFillTakerAmount,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
});
|
||||
it('should validate when orderTransactionOptions specify to validate', async () => {
|
||||
return expect(zeroEx.exchange.fillOrderAsync(
|
||||
signedOrder, emptyFillTakerAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, {
|
||||
return expect(
|
||||
zeroEx.exchange.fillOrderAsync(
|
||||
signedOrder,
|
||||
emptyFillTakerAmount,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
{
|
||||
shouldValidate: true,
|
||||
})).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
},
|
||||
),
|
||||
).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, {
|
||||
return expect(
|
||||
zeroEx.exchange.fillOrderAsync(
|
||||
signedOrder,
|
||||
emptyFillTakerAmount,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
{
|
||||
shouldValidate: false,
|
||||
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
},
|
||||
),
|
||||
).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -297,11 +399,19 @@ describe('ExchangeWrapper', () => {
|
||||
let orderFillBatch: OrderFillRequest[];
|
||||
beforeEach(async () => {
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
signedOrderHashHex = ZeroEx.getOrderHashHex(signedOrder);
|
||||
anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder);
|
||||
});
|
||||
@@ -319,13 +429,20 @@ describe('ExchangeWrapper', () => {
|
||||
];
|
||||
});
|
||||
it('should throw if a batch is empty', async () => {
|
||||
return expect(zeroEx.exchange.batchFillOrdersAsync(
|
||||
[], shouldThrowOnInsufficientBalanceOrAllowance, takerAddress),
|
||||
return expect(
|
||||
zeroEx.exchange.batchFillOrdersAsync(
|
||||
[],
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
|
||||
});
|
||||
it('should successfully fill multiple orders', async () => {
|
||||
const txHash = await zeroEx.exchange.batchFillOrdersAsync(
|
||||
orderFillBatch, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress);
|
||||
orderFillBatch,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||
const filledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
|
||||
const anotherFilledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(anotherOrderHashHex);
|
||||
@@ -348,21 +465,37 @@ describe('ExchangeWrapper', () => {
|
||||
];
|
||||
});
|
||||
it('should validate when orderTransactionOptions are not present', async () => {
|
||||
return expect(zeroEx.exchange.batchFillOrdersAsync(
|
||||
orderFillBatch, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress),
|
||||
return expect(
|
||||
zeroEx.exchange.batchFillOrdersAsync(
|
||||
orderFillBatch,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
});
|
||||
it('should validate when orderTransactionOptions specify to validate', async () => {
|
||||
return expect(zeroEx.exchange.batchFillOrdersAsync(
|
||||
orderFillBatch, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, {
|
||||
return expect(
|
||||
zeroEx.exchange.batchFillOrdersAsync(
|
||||
orderFillBatch,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
{
|
||||
shouldValidate: true,
|
||||
})).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
},
|
||||
),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
});
|
||||
it('should not validate when orderTransactionOptions specify not to validate', async () => {
|
||||
return expect(zeroEx.exchange.batchFillOrdersAsync(
|
||||
orderFillBatch, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, {
|
||||
return expect(
|
||||
zeroEx.exchange.batchFillOrdersAsync(
|
||||
orderFillBatch,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
{
|
||||
shouldValidate: false,
|
||||
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
},
|
||||
),
|
||||
).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -375,24 +508,57 @@ describe('ExchangeWrapper', () => {
|
||||
const fillUpToAmount = fillableAmount.plus(fillableAmount).minus(1);
|
||||
beforeEach(async () => {
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
signedOrderHashHex = ZeroEx.getOrderHashHex(signedOrder);
|
||||
anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder);
|
||||
signedOrders = [signedOrder, anotherSignedOrder];
|
||||
});
|
||||
describe('successful batch fills', () => {
|
||||
it('should throw if a batch is empty', async () => {
|
||||
return expect(zeroEx.exchange.fillOrdersUpToAsync(
|
||||
[], fillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress),
|
||||
return expect(
|
||||
zeroEx.exchange.fillOrdersUpToAsync(
|
||||
[],
|
||||
fillUpToAmount,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
|
||||
});
|
||||
it('should successfully fill up to specified amount', async () => {
|
||||
it('should successfully fill up to specified amount when all orders are fully funded', async () => {
|
||||
const txHash = await zeroEx.exchange.fillOrdersUpToAsync(
|
||||
signedOrders, fillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
|
||||
signedOrders,
|
||||
fillUpToAmount,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||
const filledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
|
||||
const anotherFilledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(anotherOrderHashHex);
|
||||
expect(filledAmount).to.be.bignumber.equal(fillableAmount);
|
||||
const remainingFillAmount = fillableAmount.minus(1);
|
||||
expect(anotherFilledAmount).to.be.bignumber.equal(remainingFillAmount);
|
||||
});
|
||||
it('should successfully fill up to specified amount even if filling all orders would fail', async () => {
|
||||
const missingBalance = new BigNumber(1); // User will still have enough balance to fill up to 9,
|
||||
// but won't have 10 to fully fill all orders in a batch.
|
||||
await zeroEx.token.transferAsync(makerTokenAddress, makerAddress, coinbase, missingBalance);
|
||||
const txHash = await zeroEx.exchange.fillOrdersUpToAsync(
|
||||
signedOrders,
|
||||
fillUpToAmount,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||
const filledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
|
||||
@@ -402,24 +568,57 @@ describe('ExchangeWrapper', () => {
|
||||
expect(anotherFilledAmount).to.be.bignumber.equal(remainingFillAmount);
|
||||
});
|
||||
});
|
||||
describe('failed batch fills', () => {
|
||||
it("should fail validation if user doesn't have enough balance without fill up to", async () => {
|
||||
const missingBalance = new BigNumber(2); // User will only have enough balance to fill up to 8
|
||||
await zeroEx.token.transferAsync(makerTokenAddress, makerAddress, coinbase, missingBalance);
|
||||
return expect(
|
||||
zeroEx.exchange.fillOrdersUpToAsync(
|
||||
signedOrders,
|
||||
fillUpToAmount,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance);
|
||||
});
|
||||
});
|
||||
describe('order transaction options', () => {
|
||||
const emptyFillUpToAmount = new BigNumber(0);
|
||||
it('should validate when orderTransactionOptions are not present', async () => {
|
||||
return expect(zeroEx.exchange.fillOrdersUpToAsync(
|
||||
signedOrders, emptyFillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
|
||||
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
return expect(
|
||||
zeroEx.exchange.fillOrdersUpToAsync(
|
||||
signedOrders,
|
||||
emptyFillUpToAmount,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
});
|
||||
it('should validate when orderTransactionOptions specify to validate', async () => {
|
||||
return expect(zeroEx.exchange.fillOrdersUpToAsync(
|
||||
signedOrders, emptyFillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, {
|
||||
return expect(
|
||||
zeroEx.exchange.fillOrdersUpToAsync(
|
||||
signedOrders,
|
||||
emptyFillUpToAmount,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
{
|
||||
shouldValidate: true,
|
||||
})).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
},
|
||||
),
|
||||
).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, {
|
||||
return expect(
|
||||
zeroEx.exchange.fillOrdersUpToAsync(
|
||||
signedOrders,
|
||||
emptyFillUpToAmount,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
{
|
||||
shouldValidate: false,
|
||||
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
},
|
||||
),
|
||||
).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -440,7 +639,11 @@ describe('ExchangeWrapper', () => {
|
||||
makerTokenAddress = makerToken.address;
|
||||
takerTokenAddress = takerToken.address;
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
orderHashHex = ZeroEx.getOrderHashHex(signedOrder);
|
||||
});
|
||||
@@ -456,18 +659,23 @@ describe('ExchangeWrapper', () => {
|
||||
describe('order transaction options', () => {
|
||||
const emptyCancelTakerTokenAmount = new BigNumber(0);
|
||||
it('should validate when orderTransactionOptions are not present', async () => {
|
||||
return expect(zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount))
|
||||
.to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
||||
return expect(
|
||||
zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
||||
});
|
||||
it('should validate when orderTransactionOptions specify to validate', async () => {
|
||||
return expect(zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount, {
|
||||
return expect(
|
||||
zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount, {
|
||||
shouldValidate: true,
|
||||
})).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
||||
}),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
||||
});
|
||||
it('should not validate when orderTransactionOptions specify not to validate', async () => {
|
||||
return expect(zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount, {
|
||||
return expect(
|
||||
zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount, {
|
||||
shouldValidate: false,
|
||||
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
||||
}),
|
||||
).to.not.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -477,7 +685,11 @@ describe('ExchangeWrapper', () => {
|
||||
let cancelBatch: OrderCancellationRequest[];
|
||||
beforeEach(async () => {
|
||||
anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder);
|
||||
cancelBatch = [
|
||||
@@ -494,15 +706,21 @@ describe('ExchangeWrapper', () => {
|
||||
describe('failed batch cancels', () => {
|
||||
it('should throw when orders have different makers', async () => {
|
||||
const signedOrderWithDifferentMaker = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, takerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
takerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
return expect(zeroEx.exchange.batchCancelOrdersAsync([
|
||||
return expect(
|
||||
zeroEx.exchange.batchCancelOrdersAsync([
|
||||
cancelBatch[0],
|
||||
{
|
||||
order: signedOrderWithDifferentMaker,
|
||||
takerTokenCancelAmount: cancelAmount,
|
||||
},
|
||||
])).to.be.rejectedWith(ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed);
|
||||
]),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed);
|
||||
});
|
||||
});
|
||||
describe('successful batch cancels', () => {
|
||||
@@ -531,18 +749,23 @@ describe('ExchangeWrapper', () => {
|
||||
];
|
||||
});
|
||||
it('should validate when orderTransactionOptions are not present', async () => {
|
||||
return expect(zeroEx.exchange.batchCancelOrdersAsync(cancelBatch))
|
||||
.to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
||||
return expect(zeroEx.exchange.batchCancelOrdersAsync(cancelBatch)).to.be.rejectedWith(
|
||||
ExchangeContractErrs.OrderCancelAmountZero,
|
||||
);
|
||||
});
|
||||
it('should validate when orderTransactionOptions specify to validate', async () => {
|
||||
return expect(zeroEx.exchange.batchCancelOrdersAsync(cancelBatch, {
|
||||
return expect(
|
||||
zeroEx.exchange.batchCancelOrdersAsync(cancelBatch, {
|
||||
shouldValidate: true,
|
||||
})).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
||||
}),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
||||
});
|
||||
it('should not validate when orderTransactionOptions specify not to validate', async () => {
|
||||
return expect(zeroEx.exchange.batchCancelOrdersAsync(cancelBatch, {
|
||||
return expect(
|
||||
zeroEx.exchange.batchCancelOrdersAsync(cancelBatch, {
|
||||
shouldValidate: false,
|
||||
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
||||
}),
|
||||
).to.not.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -566,7 +789,11 @@ describe('ExchangeWrapper', () => {
|
||||
fillableAmount = new BigNumber(5);
|
||||
partialFillAmount = new BigNumber(2);
|
||||
signedOrder = await fillScenarios.createPartiallyFilledSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, takerAddress, fillableAmount, partialFillAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
partialFillAmount,
|
||||
);
|
||||
orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||
});
|
||||
@@ -590,8 +817,7 @@ describe('ExchangeWrapper', () => {
|
||||
return expect(zeroEx.exchange.getFilledTakerAmountAsync(invalidOrderHashHex)).to.be.rejected();
|
||||
});
|
||||
it('should return zero if passed a valid but non-existent orderHash', async () => {
|
||||
const filledValueT = await zeroEx.exchange.getFilledTakerAmountAsync(NON_EXISTENT_ORDER_HASH,
|
||||
);
|
||||
const filledValueT = await zeroEx.exchange.getFilledTakerAmountAsync(NON_EXISTENT_ORDER_HASH);
|
||||
expect(filledValueT).to.be.bignumber.equal(0);
|
||||
});
|
||||
it('should return the filledValueT for a valid and partially filled orderHash', async () => {
|
||||
@@ -641,7 +867,11 @@ describe('ExchangeWrapper', () => {
|
||||
beforeEach(async () => {
|
||||
fillableAmount = new BigNumber(5);
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
});
|
||||
afterEach(async () => {
|
||||
@@ -654,70 +884,74 @@ describe('ExchangeWrapper', () => {
|
||||
// Source: https://github.com/mochajs/mocha/issues/2407
|
||||
it('Should receive the LogFill event when an order is filled', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
|
||||
const callback = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
|
||||
const callback = reportNodeCallbackErrors(done)(
|
||||
(logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
|
||||
expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogFill);
|
||||
done();
|
||||
};
|
||||
zeroEx.exchange.subscribe(
|
||||
ExchangeEvents.LogFill, indexFilterValues, callback,
|
||||
},
|
||||
);
|
||||
zeroEx.exchange.subscribe(ExchangeEvents.LogFill, indexFilterValues, callback);
|
||||
await zeroEx.exchange.fillOrderAsync(
|
||||
signedOrder, takerTokenFillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
signedOrder,
|
||||
takerTokenFillAmountInBaseUnits,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
})().catch(done);
|
||||
});
|
||||
it('Should receive the LogCancel event when an order is cancelled', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
|
||||
const callback = (err: Error, logEvent: DecodedLogEvent<LogCancelContractEventArgs>) => {
|
||||
const callback = reportNodeCallbackErrors(done)(
|
||||
(logEvent: DecodedLogEvent<LogCancelContractEventArgs>) => {
|
||||
expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogCancel);
|
||||
done();
|
||||
};
|
||||
zeroEx.exchange.subscribe(
|
||||
ExchangeEvents.LogCancel, indexFilterValues, callback,
|
||||
},
|
||||
);
|
||||
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>) => {
|
||||
const callbackNeverToBeCalled = reportNodeCallbackErrors(done)(
|
||||
(logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
|
||||
done(new Error('Expected this subscription to have been cancelled'));
|
||||
};
|
||||
zeroEx.exchange.subscribe(
|
||||
ExchangeEvents.LogFill, indexFilterValues, callbackNeverToBeCalled,
|
||||
},
|
||||
);
|
||||
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>) => {
|
||||
const callback = reportNodeCallbackErrors(done)(
|
||||
(logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
|
||||
expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogFill);
|
||||
done();
|
||||
};
|
||||
zeroEx.exchange.subscribe(
|
||||
ExchangeEvents.LogFill, indexFilterValues, callback,
|
||||
},
|
||||
);
|
||||
zeroEx.exchange.subscribe(ExchangeEvents.LogFill, indexFilterValues, callback);
|
||||
await zeroEx.exchange.fillOrderAsync(
|
||||
signedOrder, takerTokenFillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
signedOrder,
|
||||
takerTokenFillAmountInBaseUnits,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
})().catch(done);
|
||||
});
|
||||
it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
|
||||
const callbackNeverToBeCalled = reportNodeCallbackErrors(done)(
|
||||
(logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
|
||||
done(new Error('Expected this subscription to have been cancelled'));
|
||||
};
|
||||
},
|
||||
);
|
||||
const subscriptionToken = zeroEx.exchange.subscribe(
|
||||
ExchangeEvents.LogFill, indexFilterValues, callbackNeverToBeCalled,
|
||||
ExchangeEvents.LogFill,
|
||||
indexFilterValues,
|
||||
callbackNeverToBeCalled,
|
||||
);
|
||||
zeroEx.exchange.unsubscribe(subscriptionToken);
|
||||
await zeroEx.exchange.fillOrderAsync(
|
||||
signedOrder, takerTokenFillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
signedOrder,
|
||||
takerTokenFillAmountInBaseUnits,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
done();
|
||||
@@ -736,13 +970,18 @@ describe('ExchangeWrapper', () => {
|
||||
makerTokenAddress = makerToken.address;
|
||||
takerTokenAddress = takerToken.address;
|
||||
});
|
||||
it('get\'s the same hash as the local function', async () => {
|
||||
it("get's the same hash as the local function", async () => {
|
||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||
const orderHashFromContract = await (zeroEx.exchange as any)
|
||||
._getOrderHashHexUsingContractCallAsync(signedOrder);
|
||||
const orderHashFromContract = await (zeroEx.exchange as any)._getOrderHashHexUsingContractCallAsync(
|
||||
signedOrder,
|
||||
);
|
||||
expect(orderHash).to.equal(orderHashFromContract);
|
||||
});
|
||||
});
|
||||
@@ -773,10 +1012,17 @@ describe('ExchangeWrapper', () => {
|
||||
});
|
||||
it('should get logs with decoded args emitted by LogFill', async () => {
|
||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
txHash = await zeroEx.exchange.fillOrderAsync(
|
||||
signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
|
||||
signedOrder,
|
||||
fillableAmount,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||
const eventName = ExchangeEvents.LogFill;
|
||||
@@ -787,10 +1033,17 @@ describe('ExchangeWrapper', () => {
|
||||
});
|
||||
it('should only get the logs with the correct event name', async () => {
|
||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
txHash = await zeroEx.exchange.fillOrderAsync(
|
||||
signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
|
||||
signedOrder,
|
||||
fillableAmount,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||
const differentEventName = ExchangeEvents.LogCancel;
|
||||
@@ -800,19 +1053,33 @@ describe('ExchangeWrapper', () => {
|
||||
});
|
||||
it('should only get the logs with the correct indexed fields', async () => {
|
||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
txHash = await zeroEx.exchange.fillOrderAsync(
|
||||
signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
|
||||
signedOrder,
|
||||
fillableAmount,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||
|
||||
const differentMakerAddress = userAddresses[2];
|
||||
const anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, differentMakerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
differentMakerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
txHash = await zeroEx.exchange.fillOrderAsync(
|
||||
anotherSignedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
|
||||
anotherSignedOrder,
|
||||
fillableAmount,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||
|
||||
@@ -821,7 +1088,9 @@ describe('ExchangeWrapper', () => {
|
||||
maker: differentMakerAddress,
|
||||
};
|
||||
const logs = await zeroEx.exchange.getLogsAsync<LogFillContractEventArgs>(
|
||||
eventName, blockRange, indexFilterValues,
|
||||
eventName,
|
||||
blockRange,
|
||||
indexFilterValues,
|
||||
);
|
||||
expect(logs).to.have.length(1);
|
||||
const args = logs[0].args;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
import 'mocha';
|
||||
@@ -15,7 +15,7 @@ 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 { reportNoErrorCallbackErrors } from './utils/report_callback_errors';
|
||||
import { TokenUtils } from './utils/token_utils';
|
||||
import { web3Factory } from './utils/web3_factory';
|
||||
|
||||
@@ -78,31 +78,38 @@ describe('ExpirationWatcher', () => {
|
||||
const orderLifetimeSec = 60;
|
||||
const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec);
|
||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
expirationUnixTimestampSec,
|
||||
);
|
||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||
expirationWatcher.addOrder(orderHash, signedOrder.expirationUnixTimestampSec.times(1000));
|
||||
const callbackAsync = reportCallbackErrors(done)(async (hash: string) => {
|
||||
const callbackAsync = reportNoErrorCallbackErrors(done)((hash: string) => {
|
||||
expect(hash).to.be.equal(orderHash);
|
||||
expect(utils.getCurrentUnixTimestampSec()).to.be.bignumber.gte(expirationUnixTimestampSec);
|
||||
done();
|
||||
});
|
||||
expirationWatcher.subscribe(callbackAsync);
|
||||
timer.tick(orderLifetimeSec * 1000);
|
||||
})().catch(done);
|
||||
});
|
||||
it('doesn\'t emit events before order expires', (done: DoneCallback) => {
|
||||
it("doesn't emit events before order expires", (done: DoneCallback) => {
|
||||
(async () => {
|
||||
const orderLifetimeSec = 60;
|
||||
const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec);
|
||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
expirationUnixTimestampSec,
|
||||
);
|
||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||
expirationWatcher.addOrder(orderHash, signedOrder.expirationUnixTimestampSec.times(1000));
|
||||
const callbackAsync = reportCallbackErrors(done)(async (hash: string) => {
|
||||
const callbackAsync = reportNoErrorCallbackErrors(done)(async (hash: string) => {
|
||||
done(new Error('Emitted expiration went before the order actually expired'));
|
||||
});
|
||||
expirationWatcher.subscribe(callbackAsync);
|
||||
@@ -118,11 +125,19 @@ describe('ExpirationWatcher', () => {
|
||||
const order1ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order1Lifetime);
|
||||
const order2ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order2Lifetime);
|
||||
const signedOrder1 = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
order1ExpirationUnixTimestampSec,
|
||||
);
|
||||
const signedOrder2 = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
order2ExpirationUnixTimestampSec,
|
||||
);
|
||||
const orderHash1 = ZeroEx.getOrderHashHex(signedOrder1);
|
||||
@@ -130,7 +145,8 @@ describe('ExpirationWatcher', () => {
|
||||
expirationWatcher.addOrder(orderHash2, signedOrder2.expirationUnixTimestampSec.times(1000));
|
||||
expirationWatcher.addOrder(orderHash1, signedOrder1.expirationUnixTimestampSec.times(1000));
|
||||
const expirationOrder = [orderHash1, orderHash2];
|
||||
const callbackAsync = reportCallbackErrors(done)(async (hash: string) => {
|
||||
const expectToBeCalledOnce = false;
|
||||
const callbackAsync = reportNoErrorCallbackErrors(done, expectToBeCalledOnce)((hash: string) => {
|
||||
const orderHash = expirationOrder.shift();
|
||||
expect(hash).to.be.equal(orderHash);
|
||||
if (_.isEmpty(expirationOrder)) {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
import 'mocha';
|
||||
@@ -20,7 +20,7 @@ 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 { reportNodeCallbackErrors } from './utils/report_callback_errors';
|
||||
import { TokenUtils } from './utils/token_utils';
|
||||
import { web3Factory } from './utils/web3_factory';
|
||||
|
||||
@@ -71,7 +71,11 @@ describe('OrderStateWatcher', () => {
|
||||
describe('#removeOrder', async () => {
|
||||
it('should successfully remove existing order', async () => {
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
||||
makerToken.address,
|
||||
takerToken.address,
|
||||
maker,
|
||||
taker,
|
||||
fillableAmount,
|
||||
);
|
||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||
@@ -89,10 +93,18 @@ describe('OrderStateWatcher', () => {
|
||||
});
|
||||
it('should no-op when removing a non-existing order', async () => {
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
||||
makerToken.address,
|
||||
takerToken.address,
|
||||
maker,
|
||||
taker,
|
||||
fillableAmount,
|
||||
);
|
||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||
const nonExistentOrderHash = `0x${orderHash.substr(2).split('').reverse().join('')}`;
|
||||
const nonExistentOrderHash = `0x${orderHash
|
||||
.substr(2)
|
||||
.split('')
|
||||
.reverse()
|
||||
.join('')}`;
|
||||
zeroEx.orderStateWatcher.removeOrder(nonExistentOrderHash);
|
||||
});
|
||||
});
|
||||
@@ -102,8 +114,7 @@ describe('OrderStateWatcher', () => {
|
||||
});
|
||||
it('should fail when trying to subscribe twice', async () => {
|
||||
zeroEx.orderStateWatcher.subscribe(_.noop);
|
||||
expect(() => zeroEx.orderStateWatcher.subscribe(_.noop))
|
||||
.to.throw(ZeroExError.SubscriptionAlreadyPresent);
|
||||
expect(() => zeroEx.orderStateWatcher.subscribe(_.noop)).to.throw(ZeroExError.SubscriptionAlreadyPresent);
|
||||
});
|
||||
});
|
||||
describe('tests with cleanup', async () => {
|
||||
@@ -115,16 +126,19 @@ describe('OrderStateWatcher', () => {
|
||||
it('should emit orderStateInvalid when maker allowance set to 0 for watched order', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
||||
makerToken.address,
|
||||
takerToken.address,
|
||||
maker,
|
||||
taker,
|
||||
fillableAmount,
|
||||
);
|
||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||
expect(orderState.isValid).to.be.false();
|
||||
const invalidOrderState = orderState as OrderStateInvalid;
|
||||
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
|
||||
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance);
|
||||
done();
|
||||
});
|
||||
zeroEx.orderStateWatcher.subscribe(callback);
|
||||
await zeroEx.token.setProxyAllowanceAsync(makerToken.address, maker, new BigNumber(0));
|
||||
@@ -133,10 +147,14 @@ describe('OrderStateWatcher', () => {
|
||||
it('should not emit an orderState event when irrelevant Transfer event received', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
||||
makerToken.address,
|
||||
takerToken.address,
|
||||
maker,
|
||||
taker,
|
||||
fillableAmount,
|
||||
);
|
||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||
throw new Error('OrderState callback fired for irrelevant order');
|
||||
});
|
||||
zeroEx.orderStateWatcher.subscribe(callback);
|
||||
@@ -152,16 +170,19 @@ describe('OrderStateWatcher', () => {
|
||||
it('should emit orderStateInvalid when maker moves balance backing watched order', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
||||
makerToken.address,
|
||||
takerToken.address,
|
||||
maker,
|
||||
taker,
|
||||
fillableAmount,
|
||||
);
|
||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||
expect(orderState.isValid).to.be.false();
|
||||
const invalidOrderState = orderState as OrderStateInvalid;
|
||||
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
|
||||
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerBalance);
|
||||
done();
|
||||
});
|
||||
zeroEx.orderStateWatcher.subscribe(callback);
|
||||
const anyRecipient = taker;
|
||||
@@ -172,30 +193,40 @@ describe('OrderStateWatcher', () => {
|
||||
it('should emit orderStateInvalid when watched order fully filled', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
||||
makerToken.address,
|
||||
takerToken.address,
|
||||
maker,
|
||||
taker,
|
||||
fillableAmount,
|
||||
);
|
||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||
|
||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||
expect(orderState.isValid).to.be.false();
|
||||
const invalidOrderState = orderState as OrderStateInvalid;
|
||||
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
|
||||
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
||||
done();
|
||||
});
|
||||
zeroEx.orderStateWatcher.subscribe(callback);
|
||||
|
||||
const shouldThrowOnInsufficientBalanceOrAllowance = true;
|
||||
await zeroEx.exchange.fillOrderAsync(
|
||||
signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, taker,
|
||||
signedOrder,
|
||||
fillableAmount,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
taker,
|
||||
);
|
||||
})().catch(done);
|
||||
});
|
||||
it('should emit orderStateValid when watched order partially filled', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
||||
makerToken.address,
|
||||
takerToken.address,
|
||||
maker,
|
||||
taker,
|
||||
fillableAmount,
|
||||
);
|
||||
|
||||
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
|
||||
@@ -203,7 +234,7 @@ describe('OrderStateWatcher', () => {
|
||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||
|
||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||
expect(orderState.isValid).to.be.true();
|
||||
const validOrderState = orderState as OrderStateValid;
|
||||
expect(validOrderState.orderHash).to.be.equal(orderHash);
|
||||
@@ -211,16 +242,20 @@ describe('OrderStateWatcher', () => {
|
||||
const remainingMakerBalance = makerBalance.sub(fillAmountInBaseUnits);
|
||||
const remainingFillable = fillableAmount.minus(fillAmountInBaseUnits);
|
||||
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
||||
remainingFillable);
|
||||
remainingFillable,
|
||||
);
|
||||
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
|
||||
remainingFillable);
|
||||
remainingFillable,
|
||||
);
|
||||
expect(orderRelevantState.makerBalance).to.be.bignumber.equal(remainingMakerBalance);
|
||||
done();
|
||||
});
|
||||
zeroEx.orderStateWatcher.subscribe(callback);
|
||||
const shouldThrowOnInsufficientBalanceOrAllowance = true;
|
||||
await zeroEx.exchange.fillOrderAsync(
|
||||
signedOrder, fillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance, taker,
|
||||
signedOrder,
|
||||
fillAmountInBaseUnits,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
taker,
|
||||
);
|
||||
})().catch(done);
|
||||
});
|
||||
@@ -229,11 +264,16 @@ describe('OrderStateWatcher', () => {
|
||||
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(2), 18);
|
||||
const takerFee = ZeroEx.toBaseUnitAmount(new BigNumber(0), 18);
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||
makerToken.address, takerToken.address, makerFee, takerFee, maker, taker, fillableAmount,
|
||||
taker);
|
||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||
done();
|
||||
});
|
||||
makerToken.address,
|
||||
takerToken.address,
|
||||
makerFee,
|
||||
takerFee,
|
||||
maker,
|
||||
taker,
|
||||
fillableAmount,
|
||||
taker,
|
||||
);
|
||||
const callback = reportNodeCallbackErrors(done)();
|
||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||
zeroEx.orderStateWatcher.subscribe(callback);
|
||||
await zeroEx.token.setProxyAllowanceAsync(zrxTokenAddress, maker, new BigNumber(0));
|
||||
@@ -245,47 +285,60 @@ describe('OrderStateWatcher', () => {
|
||||
const takerFillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(10), decimals);
|
||||
const makerFillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(20), decimals);
|
||||
signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
||||
makerToken.address, takerToken.address, maker, taker, makerFillableAmount,
|
||||
makerToken.address,
|
||||
takerToken.address,
|
||||
maker,
|
||||
taker,
|
||||
makerFillableAmount,
|
||||
takerFillableAmount,
|
||||
);
|
||||
const fillAmountInBaseUnits = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||
expect(orderState.isValid).to.be.true();
|
||||
const validOrderState = orderState as OrderStateValid;
|
||||
expect(validOrderState.orderHash).to.be.equal(orderHash);
|
||||
const orderRelevantState = validOrderState.orderRelevantState;
|
||||
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
||||
ZeroEx.toBaseUnitAmount(new BigNumber(16), decimals));
|
||||
ZeroEx.toBaseUnitAmount(new BigNumber(16), decimals),
|
||||
);
|
||||
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
|
||||
ZeroEx.toBaseUnitAmount(new BigNumber(8), decimals));
|
||||
done();
|
||||
ZeroEx.toBaseUnitAmount(new BigNumber(8), decimals),
|
||||
);
|
||||
});
|
||||
zeroEx.orderStateWatcher.subscribe(callback);
|
||||
const shouldThrowOnInsufficientBalanceOrAllowance = true;
|
||||
await zeroEx.exchange.fillOrderAsync(
|
||||
signedOrder, fillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance, taker,
|
||||
signedOrder,
|
||||
fillAmountInBaseUnits,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
taker,
|
||||
);
|
||||
})().catch(done);
|
||||
});
|
||||
it('should equal approved amount when approved amount is lowest', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
||||
makerToken.address,
|
||||
takerToken.address,
|
||||
maker,
|
||||
taker,
|
||||
fillableAmount,
|
||||
);
|
||||
|
||||
const changedMakerApprovalAmount = ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals);
|
||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||
|
||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||
const validOrderState = orderState as OrderStateValid;
|
||||
const orderRelevantState = validOrderState.orderRelevantState;
|
||||
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
||||
changedMakerApprovalAmount);
|
||||
changedMakerApprovalAmount,
|
||||
);
|
||||
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
|
||||
changedMakerApprovalAmount);
|
||||
done();
|
||||
changedMakerApprovalAmount,
|
||||
);
|
||||
});
|
||||
zeroEx.orderStateWatcher.subscribe(callback);
|
||||
await zeroEx.token.setProxyAllowanceAsync(makerToken.address, maker, changedMakerApprovalAmount);
|
||||
@@ -294,7 +347,11 @@ describe('OrderStateWatcher', () => {
|
||||
it('should equal balance amount when balance amount is lowest', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
||||
makerToken.address,
|
||||
takerToken.address,
|
||||
maker,
|
||||
taker,
|
||||
fillableAmount,
|
||||
);
|
||||
|
||||
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
|
||||
@@ -303,19 +360,19 @@ describe('OrderStateWatcher', () => {
|
||||
const transferAmount = makerBalance.sub(remainingAmount);
|
||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||
|
||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||
expect(orderState.isValid).to.be.true();
|
||||
const validOrderState = orderState as OrderStateValid;
|
||||
const orderRelevantState = validOrderState.orderRelevantState;
|
||||
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
||||
remainingAmount);
|
||||
remainingAmount,
|
||||
);
|
||||
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
|
||||
remainingAmount);
|
||||
done();
|
||||
remainingAmount,
|
||||
);
|
||||
});
|
||||
zeroEx.orderStateWatcher.subscribe(callback);
|
||||
await zeroEx.token.transferAsync(
|
||||
makerToken.address, maker, ZeroEx.NULL_ADDRESS, transferAmount);
|
||||
await zeroEx.token.transferAsync(makerToken.address, maker, ZeroEx.NULL_ADDRESS, transferAmount);
|
||||
})().catch(done);
|
||||
});
|
||||
it('should equal remaining amount when partially cancelled and order has fees', (done: DoneCallback) => {
|
||||
@@ -324,20 +381,27 @@ describe('OrderStateWatcher', () => {
|
||||
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals);
|
||||
const feeRecipient = taker;
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||
makerToken.address, takerToken.address, makerFee, takerFee, maker,
|
||||
taker, fillableAmount, feeRecipient);
|
||||
makerToken.address,
|
||||
takerToken.address,
|
||||
makerFee,
|
||||
takerFee,
|
||||
maker,
|
||||
taker,
|
||||
fillableAmount,
|
||||
feeRecipient,
|
||||
);
|
||||
|
||||
const remainingTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(4), decimals);
|
||||
const transferTokenAmount = makerFee.sub(remainingTokenAmount);
|
||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||
|
||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||
expect(orderState.isValid).to.be.true();
|
||||
const validOrderState = orderState as OrderStateValid;
|
||||
const orderRelevantState = validOrderState.orderRelevantState;
|
||||
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
||||
remainingTokenAmount);
|
||||
done();
|
||||
remainingTokenAmount,
|
||||
);
|
||||
});
|
||||
zeroEx.orderStateWatcher.subscribe(callback);
|
||||
await zeroEx.exchange.cancelOrderAsync(signedOrder, transferTokenAmount);
|
||||
@@ -349,8 +413,15 @@ describe('OrderStateWatcher', () => {
|
||||
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals);
|
||||
const feeRecipient = taker;
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||
makerToken.address, takerToken.address, makerFee, takerFee, maker,
|
||||
taker, fillableAmount, feeRecipient);
|
||||
makerToken.address,
|
||||
takerToken.address,
|
||||
makerFee,
|
||||
takerFee,
|
||||
maker,
|
||||
taker,
|
||||
fillableAmount,
|
||||
feeRecipient,
|
||||
);
|
||||
|
||||
const remainingFeeAmount = ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals);
|
||||
|
||||
@@ -358,17 +429,21 @@ describe('OrderStateWatcher', () => {
|
||||
const transferTokenAmount = makerFee.sub(remainingTokenAmount);
|
||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||
|
||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||
const validOrderState = orderState as OrderStateValid;
|
||||
const orderRelevantState = validOrderState.orderRelevantState;
|
||||
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
||||
remainingFeeAmount);
|
||||
done();
|
||||
remainingFeeAmount,
|
||||
);
|
||||
});
|
||||
zeroEx.orderStateWatcher.subscribe(callback);
|
||||
await zeroEx.token.setProxyAllowanceAsync(zrxTokenAddress, maker, remainingFeeAmount);
|
||||
await zeroEx.token.transferAsync(
|
||||
makerToken.address, maker, ZeroEx.NULL_ADDRESS, transferTokenAmount);
|
||||
makerToken.address,
|
||||
maker,
|
||||
ZeroEx.NULL_ADDRESS,
|
||||
transferTokenAmount,
|
||||
);
|
||||
})().catch(done);
|
||||
});
|
||||
it('should calculate full amount when all available and non-divisible', (done: DoneCallback) => {
|
||||
@@ -377,38 +452,51 @@ describe('OrderStateWatcher', () => {
|
||||
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
||||
const feeRecipient = taker;
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||
makerToken.address, takerToken.address, makerFee, takerFee, maker,
|
||||
taker, fillableAmount, feeRecipient);
|
||||
makerToken.address,
|
||||
takerToken.address,
|
||||
makerFee,
|
||||
takerFee,
|
||||
maker,
|
||||
taker,
|
||||
fillableAmount,
|
||||
feeRecipient,
|
||||
);
|
||||
|
||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||
|
||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||
const validOrderState = orderState as OrderStateValid;
|
||||
const orderRelevantState = validOrderState.orderRelevantState;
|
||||
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
||||
fillableAmount);
|
||||
done();
|
||||
fillableAmount,
|
||||
);
|
||||
});
|
||||
zeroEx.orderStateWatcher.subscribe(callback);
|
||||
await zeroEx.token.setProxyAllowanceAsync(
|
||||
makerToken.address, maker, ZeroEx.toBaseUnitAmount(new BigNumber(100), decimals));
|
||||
makerToken.address,
|
||||
maker,
|
||||
ZeroEx.toBaseUnitAmount(new BigNumber(100), decimals),
|
||||
);
|
||||
})().catch(done);
|
||||
});
|
||||
});
|
||||
it('should emit orderStateInvalid when watched order cancelled', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
||||
makerToken.address,
|
||||
takerToken.address,
|
||||
maker,
|
||||
taker,
|
||||
fillableAmount,
|
||||
);
|
||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||
|
||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||
expect(orderState.isValid).to.be.false();
|
||||
const invalidOrderState = orderState as OrderStateInvalid;
|
||||
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
|
||||
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
||||
done();
|
||||
});
|
||||
zeroEx.orderStateWatcher.subscribe(callback);
|
||||
|
||||
@@ -419,41 +507,48 @@ describe('OrderStateWatcher', () => {
|
||||
(async () => {
|
||||
const remainingFillableAmountInBaseUnits = new BigNumber(100);
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
||||
makerToken.address,
|
||||
takerToken.address,
|
||||
maker,
|
||||
taker,
|
||||
fillableAmount,
|
||||
);
|
||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||
|
||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||
expect(orderState.isValid).to.be.false();
|
||||
const invalidOrderState = orderState as OrderStateInvalid;
|
||||
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
|
||||
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderFillRoundingError);
|
||||
done();
|
||||
});
|
||||
zeroEx.orderStateWatcher.subscribe(callback);
|
||||
await zeroEx.exchange.cancelOrderAsync(
|
||||
signedOrder, fillableAmount.minus(remainingFillableAmountInBaseUnits),
|
||||
signedOrder,
|
||||
fillableAmount.minus(remainingFillableAmountInBaseUnits),
|
||||
);
|
||||
})().catch(done);
|
||||
});
|
||||
it('should emit orderStateValid when watched order partially cancelled', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
||||
makerToken.address,
|
||||
takerToken.address,
|
||||
maker,
|
||||
taker,
|
||||
fillableAmount,
|
||||
);
|
||||
|
||||
const cancelAmountInBaseUnits = new BigNumber(2);
|
||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||
|
||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||
const callback = reportNodeCallbackErrors(done)((orderState: OrderState) => {
|
||||
expect(orderState.isValid).to.be.true();
|
||||
const validOrderState = orderState as OrderStateValid;
|
||||
expect(validOrderState.orderHash).to.be.equal(orderHash);
|
||||
const orderRelevantState = validOrderState.orderRelevantState;
|
||||
expect(orderRelevantState.cancelledTakerTokenAmount).to.be.bignumber.equal(cancelAmountInBaseUnits);
|
||||
done();
|
||||
});
|
||||
zeroEx.orderStateWatcher.subscribe(callback);
|
||||
await zeroEx.exchange.cancelOrderAsync(signedOrder, cancelAmountInBaseUnits);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as Sinon from 'sinon';
|
||||
import * as Web3 from 'web3';
|
||||
@@ -62,108 +62,152 @@ describe('OrderValidation', () => {
|
||||
describe('validateOrderFillableOrThrowAsync', () => {
|
||||
it('should succeed if the order is fillable', async () => {
|
||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
);
|
||||
await zeroEx.exchange.validateOrderFillableOrThrowAsync(
|
||||
signedOrder,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
await zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder);
|
||||
});
|
||||
it('should succeed if the order is asymmetric and fillable', async () => {
|
||||
const makerFillableAmount = fillableAmount;
|
||||
const takerFillableAmount = fillableAmount.minus(4);
|
||||
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
||||
makerFillableAmount, takerFillableAmount,
|
||||
);
|
||||
await zeroEx.exchange.validateOrderFillableOrThrowAsync(
|
||||
signedOrder,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
makerFillableAmount,
|
||||
takerFillableAmount,
|
||||
);
|
||||
await zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder);
|
||||
});
|
||||
it('should throw when the order is fully filled or cancelled', async () => {
|
||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
|
||||
return expect(zeroEx.exchange.validateOrderFillableOrThrowAsync(
|
||||
signedOrder,
|
||||
)).to.be.rejectedWith(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
||||
return expect(zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder)).to.be.rejectedWith(
|
||||
ExchangeContractErrs.OrderRemainingFillAmountZero,
|
||||
);
|
||||
});
|
||||
it('should throw when order is expired', async () => {
|
||||
const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
|
||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
||||
fillableAmount, expirationInPast,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
expirationInPast,
|
||||
);
|
||||
return expect(zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder)).to.be.rejectedWith(
|
||||
ExchangeContractErrs.OrderFillExpired,
|
||||
);
|
||||
return expect(zeroEx.exchange.validateOrderFillableOrThrowAsync(
|
||||
signedOrder,
|
||||
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillExpired);
|
||||
});
|
||||
});
|
||||
describe('validateFillOrderAndThrowIfInvalidAsync', () => {
|
||||
it('should throw when the fill amount is zero', async () => {
|
||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
const zeroFillAmount = new BigNumber(0);
|
||||
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
||||
signedOrder, zeroFillAmount, takerAddress,
|
||||
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
return expect(
|
||||
zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, zeroFillAmount, takerAddress),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||
});
|
||||
it('should throw when the signature is invalid', async () => {
|
||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
// 27 <--> 28
|
||||
signedOrder.ecSignature.v = (28 - signedOrder.ecSignature.v) + 27;
|
||||
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
||||
signedOrder, fillableAmount, takerAddress,
|
||||
)).to.be.rejectedWith(ZeroExError.InvalidSignature);
|
||||
signedOrder.ecSignature.v = 28 - signedOrder.ecSignature.v + 27;
|
||||
return expect(
|
||||
zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillableAmount, takerAddress),
|
||||
).to.be.rejectedWith(ZeroExError.InvalidSignature);
|
||||
});
|
||||
it('should throw when the order is fully filled or cancelled', async () => {
|
||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
|
||||
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
||||
signedOrder, fillableAmount, takerAddress,
|
||||
)).to.be.rejectedWith(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
||||
return expect(
|
||||
zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillableAmount, takerAddress),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
||||
});
|
||||
it('should throw when sender is not a taker', async () => {
|
||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
const nonTakerAddress = userAddresses[6];
|
||||
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
||||
signedOrder, fillTakerAmount, nonTakerAddress,
|
||||
)).to.be.rejectedWith(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker);
|
||||
return expect(
|
||||
zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillTakerAmount, nonTakerAddress),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker);
|
||||
});
|
||||
it('should throw when order is expired', async () => {
|
||||
const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
|
||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
||||
fillableAmount, expirationInPast,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
expirationInPast,
|
||||
);
|
||||
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
||||
signedOrder, fillTakerAmount, takerAddress,
|
||||
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillExpired);
|
||||
return expect(
|
||||
zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillTakerAmount, takerAddress),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.OrderFillExpired);
|
||||
});
|
||||
it('should throw when there a rounding error would have occurred', async () => {
|
||||
const makerAmount = new BigNumber(3);
|
||||
const takerAmount = new BigNumber(5);
|
||||
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
||||
makerAmount, takerAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
makerAmount,
|
||||
takerAmount,
|
||||
);
|
||||
const fillTakerAmountThatCausesRoundingError = new BigNumber(3);
|
||||
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
||||
signedOrder, fillTakerAmountThatCausesRoundingError, takerAddress,
|
||||
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillRoundingError);
|
||||
return expect(
|
||||
zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
||||
signedOrder,
|
||||
fillTakerAmountThatCausesRoundingError,
|
||||
takerAddress,
|
||||
),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.OrderFillRoundingError);
|
||||
});
|
||||
});
|
||||
describe('#validateFillOrKillOrderAndThrowIfInvalidAsync', () => {
|
||||
it('should throw if remaining fillAmount is less then the desired fillAmount', async () => {
|
||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
);
|
||||
const tooLargeFillAmount = new BigNumber(7);
|
||||
const fillAmountDifference = tooLargeFillAmount.minus(fillableAmount);
|
||||
@@ -172,9 +216,13 @@ describe('OrderValidation', () => {
|
||||
await zeroEx.token.transferAsync(makerTokenAddress, coinbase, makerAddress, fillAmountDifference);
|
||||
await zeroEx.token.setProxyAllowanceAsync(makerTokenAddress, makerAddress, tooLargeFillAmount);
|
||||
|
||||
return expect(zeroEx.exchange.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
signedOrder, tooLargeFillAmount, takerAddress,
|
||||
)).to.be.rejectedWith(ExchangeContractErrs.InsufficientRemainingFillAmount);
|
||||
return expect(
|
||||
zeroEx.exchange.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||
signedOrder,
|
||||
tooLargeFillAmount,
|
||||
takerAddress,
|
||||
),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.InsufficientRemainingFillAmount);
|
||||
});
|
||||
});
|
||||
describe('validateCancelOrderAndThrowIfInvalidAsync', () => {
|
||||
@@ -186,27 +234,38 @@ describe('OrderValidation', () => {
|
||||
makerTokenAddress = makerToken.address;
|
||||
takerTokenAddress = takerToken.address;
|
||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
||||
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);
|
||||
return expect(
|
||||
zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, zeroCancelAmount),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
||||
});
|
||||
it('should throw when order is expired', async () => {
|
||||
const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
|
||||
const expiredSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
||||
fillableAmount, expirationInPast,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
expirationInPast,
|
||||
);
|
||||
return expect(zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(expiredSignedOrder, cancelAmount))
|
||||
.to.be.rejectedWith(ExchangeContractErrs.OrderCancelExpired);
|
||||
return expect(
|
||||
zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(expiredSignedOrder, cancelAmount),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.OrderCancelExpired);
|
||||
});
|
||||
it('should throw when order is already cancelled or filled', async () => {
|
||||
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
|
||||
return expect(zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, fillableAmount))
|
||||
.to.be.rejectedWith(ExchangeContractErrs.OrderAlreadyCancelledOrFilled);
|
||||
return expect(
|
||||
zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, fillableAmount),
|
||||
).to.be.rejectedWith(ExchangeContractErrs.OrderAlreadyCancelledOrFilled);
|
||||
});
|
||||
});
|
||||
describe('#validateFillOrderBalancesAllowancesThrowIfInvalidAsync', () => {
|
||||
@@ -224,35 +283,69 @@ describe('OrderValidation', () => {
|
||||
const makerFee = new BigNumber(2);
|
||||
const takerFee = new BigNumber(2);
|
||||
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerFee, takerFee,
|
||||
makerAddress, takerAddress, fillableAmount, feeRecipient,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerFee,
|
||||
takerFee,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
feeRecipient,
|
||||
);
|
||||
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
||||
exchangeTransferSimulator, signedOrder, fillableAmount, takerAddress, zrxTokenAddress,
|
||||
exchangeTransferSimulator,
|
||||
signedOrder,
|
||||
fillableAmount,
|
||||
takerAddress,
|
||||
zrxTokenAddress,
|
||||
);
|
||||
expect(transferFromAsync.callCount).to.be.equal(4);
|
||||
expect(
|
||||
transferFromAsync.getCall(0).calledWith(
|
||||
makerTokenAddress, makerAddress, takerAddress, bigNumberMatch(fillableAmount),
|
||||
TradeSide.Maker, TransferType.Trade,
|
||||
transferFromAsync
|
||||
.getCall(0)
|
||||
.calledWith(
|
||||
makerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
bigNumberMatch(fillableAmount),
|
||||
TradeSide.Maker,
|
||||
TransferType.Trade,
|
||||
),
|
||||
).to.be.true();
|
||||
expect(
|
||||
transferFromAsync.getCall(1).calledWith(
|
||||
takerTokenAddress, takerAddress, makerAddress, bigNumberMatch(fillableAmount),
|
||||
TradeSide.Taker, TransferType.Trade,
|
||||
transferFromAsync
|
||||
.getCall(1)
|
||||
.calledWith(
|
||||
takerTokenAddress,
|
||||
takerAddress,
|
||||
makerAddress,
|
||||
bigNumberMatch(fillableAmount),
|
||||
TradeSide.Taker,
|
||||
TransferType.Trade,
|
||||
),
|
||||
).to.be.true();
|
||||
expect(
|
||||
transferFromAsync.getCall(2).calledWith(
|
||||
zrxTokenAddress, makerAddress, feeRecipient, bigNumberMatch(makerFee),
|
||||
TradeSide.Maker, TransferType.Fee,
|
||||
transferFromAsync
|
||||
.getCall(2)
|
||||
.calledWith(
|
||||
zrxTokenAddress,
|
||||
makerAddress,
|
||||
feeRecipient,
|
||||
bigNumberMatch(makerFee),
|
||||
TradeSide.Maker,
|
||||
TransferType.Fee,
|
||||
),
|
||||
).to.be.true();
|
||||
expect(
|
||||
transferFromAsync.getCall(3).calledWith(
|
||||
zrxTokenAddress, takerAddress, feeRecipient, bigNumberMatch(takerFee),
|
||||
TradeSide.Taker, TransferType.Fee,
|
||||
transferFromAsync
|
||||
.getCall(3)
|
||||
.calledWith(
|
||||
zrxTokenAddress,
|
||||
takerAddress,
|
||||
feeRecipient,
|
||||
bigNumberMatch(takerFee),
|
||||
TradeSide.Taker,
|
||||
TransferType.Fee,
|
||||
),
|
||||
).to.be.true();
|
||||
});
|
||||
@@ -260,35 +353,69 @@ describe('OrderValidation', () => {
|
||||
const makerFee = new BigNumber(2);
|
||||
const takerFee = new BigNumber(2);
|
||||
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerFee, takerFee,
|
||||
makerAddress, ZeroEx.NULL_ADDRESS, fillableAmount, feeRecipient,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerFee,
|
||||
takerFee,
|
||||
makerAddress,
|
||||
ZeroEx.NULL_ADDRESS,
|
||||
fillableAmount,
|
||||
feeRecipient,
|
||||
);
|
||||
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
||||
exchangeTransferSimulator, signedOrder, fillableAmount, takerAddress, zrxTokenAddress,
|
||||
exchangeTransferSimulator,
|
||||
signedOrder,
|
||||
fillableAmount,
|
||||
takerAddress,
|
||||
zrxTokenAddress,
|
||||
);
|
||||
expect(transferFromAsync.callCount).to.be.equal(4);
|
||||
expect(
|
||||
transferFromAsync.getCall(0).calledWith(
|
||||
makerTokenAddress, makerAddress, takerAddress, bigNumberMatch(fillableAmount),
|
||||
TradeSide.Maker, TransferType.Trade,
|
||||
transferFromAsync
|
||||
.getCall(0)
|
||||
.calledWith(
|
||||
makerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
bigNumberMatch(fillableAmount),
|
||||
TradeSide.Maker,
|
||||
TransferType.Trade,
|
||||
),
|
||||
).to.be.true();
|
||||
expect(
|
||||
transferFromAsync.getCall(1).calledWith(
|
||||
takerTokenAddress, takerAddress, makerAddress, bigNumberMatch(fillableAmount),
|
||||
TradeSide.Taker, TransferType.Trade,
|
||||
transferFromAsync
|
||||
.getCall(1)
|
||||
.calledWith(
|
||||
takerTokenAddress,
|
||||
takerAddress,
|
||||
makerAddress,
|
||||
bigNumberMatch(fillableAmount),
|
||||
TradeSide.Taker,
|
||||
TransferType.Trade,
|
||||
),
|
||||
).to.be.true();
|
||||
expect(
|
||||
transferFromAsync.getCall(2).calledWith(
|
||||
zrxTokenAddress, makerAddress, feeRecipient, bigNumberMatch(makerFee),
|
||||
TradeSide.Maker, TransferType.Fee,
|
||||
transferFromAsync
|
||||
.getCall(2)
|
||||
.calledWith(
|
||||
zrxTokenAddress,
|
||||
makerAddress,
|
||||
feeRecipient,
|
||||
bigNumberMatch(makerFee),
|
||||
TradeSide.Maker,
|
||||
TransferType.Fee,
|
||||
),
|
||||
).to.be.true();
|
||||
expect(
|
||||
transferFromAsync.getCall(3).calledWith(
|
||||
zrxTokenAddress, takerAddress, feeRecipient, bigNumberMatch(takerFee),
|
||||
TradeSide.Taker, TransferType.Fee,
|
||||
transferFromAsync
|
||||
.getCall(3)
|
||||
.calledWith(
|
||||
zrxTokenAddress,
|
||||
takerAddress,
|
||||
feeRecipient,
|
||||
bigNumberMatch(takerFee),
|
||||
TradeSide.Taker,
|
||||
TransferType.Fee,
|
||||
),
|
||||
).to.be.true();
|
||||
});
|
||||
@@ -296,10 +423,19 @@ describe('OrderValidation', () => {
|
||||
const makerTokenAmount = new BigNumber(3);
|
||||
const takerTokenAmount = new BigNumber(1);
|
||||
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, makerTokenAmount, takerTokenAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
makerTokenAmount,
|
||||
takerTokenAmount,
|
||||
);
|
||||
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
||||
exchangeTransferSimulator, signedOrder, takerTokenAmount, takerAddress, zrxTokenAddress,
|
||||
exchangeTransferSimulator,
|
||||
signedOrder,
|
||||
takerTokenAmount,
|
||||
takerAddress,
|
||||
zrxTokenAddress,
|
||||
);
|
||||
expect(transferFromAsync.callCount).to.be.equal(4);
|
||||
const makerFillAmount = transferFromAsync.getCall(0).args[3];
|
||||
@@ -309,12 +445,22 @@ describe('OrderValidation', () => {
|
||||
const makerFee = new BigNumber(2);
|
||||
const takerFee = new BigNumber(4);
|
||||
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress,
|
||||
fillableAmount, ZeroEx.NULL_ADDRESS,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerFee,
|
||||
takerFee,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
ZeroEx.NULL_ADDRESS,
|
||||
);
|
||||
const fillTakerTokenAmount = fillableAmount.div(2).round(0);
|
||||
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
||||
exchangeTransferSimulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress,
|
||||
exchangeTransferSimulator,
|
||||
signedOrder,
|
||||
fillTakerTokenAmount,
|
||||
takerAddress,
|
||||
zrxTokenAddress,
|
||||
);
|
||||
const makerPartialFee = makerFee.div(2);
|
||||
const takerPartialFee = takerFee.div(2);
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import 'mocha';
|
||||
|
||||
@@ -28,15 +28,19 @@ describe('RemainingFillableCalculator', () => {
|
||||
const zeroAddress = '0x0';
|
||||
const signature: ECSignature = { v: 27, r: '', s: '' };
|
||||
beforeEach(async () => {
|
||||
[makerAmount, takerAmount, makerFeeAmount] = [ZeroEx.toBaseUnitAmount(new BigNumber(50), decimals),
|
||||
[makerAmount, takerAmount, makerFeeAmount] = [
|
||||
ZeroEx.toBaseUnitAmount(new BigNumber(50), decimals),
|
||||
ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals),
|
||||
ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals)];
|
||||
ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals),
|
||||
];
|
||||
[transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount] = [
|
||||
ZeroEx.toBaseUnitAmount(new BigNumber(50), decimals),
|
||||
ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals)];
|
||||
ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals),
|
||||
];
|
||||
});
|
||||
function buildSignedOrder(): SignedOrder {
|
||||
return { ecSignature: signature,
|
||||
return {
|
||||
ecSignature: signature,
|
||||
exchangeContractAddress: zeroAddress,
|
||||
feeRecipient: zeroAddress,
|
||||
maker: zeroAddress,
|
||||
@@ -48,7 +52,8 @@ describe('RemainingFillableCalculator', () => {
|
||||
makerTokenAddress: makerToken,
|
||||
takerTokenAddress: takerToken,
|
||||
salt: zero,
|
||||
expirationUnixTimestampSec: zero };
|
||||
expirationUnixTimestampSec: zero,
|
||||
};
|
||||
}
|
||||
describe('Maker token is NOT ZRX', () => {
|
||||
before(async () => {
|
||||
@@ -57,23 +62,38 @@ describe('RemainingFillableCalculator', () => {
|
||||
it('calculates the correct amount when unfilled and funds available', () => {
|
||||
signedOrder = buildSignedOrder();
|
||||
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
||||
calculator = new RemainingFillableCalculator(
|
||||
signedOrder,
|
||||
isMakerTokenZRX,
|
||||
transferrableMakerTokenAmount,
|
||||
transferrableMakerFeeTokenAmount,
|
||||
remainingMakerTokenAmount,
|
||||
);
|
||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
|
||||
});
|
||||
it('calculates the correct amount when partially filled and funds available', () => {
|
||||
signedOrder = buildSignedOrder();
|
||||
remainingMakerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals);
|
||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
||||
calculator = new RemainingFillableCalculator(
|
||||
signedOrder,
|
||||
isMakerTokenZRX,
|
||||
transferrableMakerTokenAmount,
|
||||
transferrableMakerFeeTokenAmount,
|
||||
remainingMakerTokenAmount,
|
||||
);
|
||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
|
||||
});
|
||||
it('calculates the amount to be 0 when all fee funds are transferred', () => {
|
||||
signedOrder = buildSignedOrder();
|
||||
transferrableMakerFeeTokenAmount = zero;
|
||||
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
||||
calculator = new RemainingFillableCalculator(
|
||||
signedOrder,
|
||||
isMakerTokenZRX,
|
||||
transferrableMakerTokenAmount,
|
||||
transferrableMakerFeeTokenAmount,
|
||||
remainingMakerTokenAmount,
|
||||
);
|
||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(zero);
|
||||
});
|
||||
it('calculates the correct amount when balance is less than remaining fillable', () => {
|
||||
@@ -81,41 +101,58 @@ describe('RemainingFillableCalculator', () => {
|
||||
const partiallyFilledAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
||||
remainingMakerTokenAmount = signedOrder.makerTokenAmount.minus(partiallyFilledAmount);
|
||||
transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(partiallyFilledAmount);
|
||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
||||
calculator = new RemainingFillableCalculator(
|
||||
signedOrder,
|
||||
isMakerTokenZRX,
|
||||
transferrableMakerTokenAmount,
|
||||
transferrableMakerFeeTokenAmount,
|
||||
remainingMakerTokenAmount,
|
||||
);
|
||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(transferrableMakerTokenAmount);
|
||||
});
|
||||
describe('Order to Fee Ratio is < 1', () => {
|
||||
beforeEach(async () => {
|
||||
[makerAmount, takerAmount, makerFeeAmount] = [ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals),
|
||||
[makerAmount, takerAmount, makerFeeAmount] = [
|
||||
ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals),
|
||||
ZeroEx.toBaseUnitAmount(new BigNumber(6), decimals),
|
||||
ZeroEx.toBaseUnitAmount(new BigNumber(6), decimals)];
|
||||
ZeroEx.toBaseUnitAmount(new BigNumber(6), decimals),
|
||||
];
|
||||
});
|
||||
it('calculates the correct amount when funds unavailable', () => {
|
||||
signedOrder = buildSignedOrder();
|
||||
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
||||
const transferredAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
||||
transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(transferredAmount);
|
||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount,
|
||||
remainingMakerTokenAmount);
|
||||
calculator = new RemainingFillableCalculator(
|
||||
signedOrder,
|
||||
isMakerTokenZRX,
|
||||
transferrableMakerTokenAmount,
|
||||
transferrableMakerFeeTokenAmount,
|
||||
remainingMakerTokenAmount,
|
||||
);
|
||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(transferrableMakerTokenAmount);
|
||||
});
|
||||
});
|
||||
describe('Ratio is not evenly divisble', () => {
|
||||
beforeEach(async () => {
|
||||
[makerAmount, takerAmount, makerFeeAmount] = [ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals),
|
||||
[makerAmount, takerAmount, makerFeeAmount] = [
|
||||
ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals),
|
||||
ZeroEx.toBaseUnitAmount(new BigNumber(7), decimals),
|
||||
ZeroEx.toBaseUnitAmount(new BigNumber(7), decimals)];
|
||||
ZeroEx.toBaseUnitAmount(new BigNumber(7), decimals),
|
||||
];
|
||||
});
|
||||
it('calculates the correct amount when funds unavailable', () => {
|
||||
signedOrder = buildSignedOrder();
|
||||
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
||||
const transferredAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
||||
transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(transferredAmount);
|
||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount,
|
||||
remainingMakerTokenAmount);
|
||||
calculator = new RemainingFillableCalculator(
|
||||
signedOrder,
|
||||
isMakerTokenZRX,
|
||||
transferrableMakerTokenAmount,
|
||||
transferrableMakerFeeTokenAmount,
|
||||
remainingMakerTokenAmount,
|
||||
);
|
||||
const calculatedFillableAmount = calculator.computeRemainingMakerFillable();
|
||||
expect(calculatedFillableAmount.lessThanOrEqualTo(transferrableMakerTokenAmount)).to.be.true();
|
||||
expect(calculatedFillableAmount).to.be.bignumber.greaterThan(new BigNumber(0));
|
||||
@@ -134,15 +171,25 @@ describe('RemainingFillableCalculator', () => {
|
||||
transferrableMakerTokenAmount = makerAmount.plus(makerFeeAmount);
|
||||
transferrableMakerFeeTokenAmount = transferrableMakerTokenAmount;
|
||||
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
||||
calculator = new RemainingFillableCalculator(
|
||||
signedOrder,
|
||||
isMakerTokenZRX,
|
||||
transferrableMakerTokenAmount,
|
||||
transferrableMakerFeeTokenAmount,
|
||||
remainingMakerTokenAmount,
|
||||
);
|
||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
|
||||
});
|
||||
it('calculates the correct amount when partially filled and funds available', () => {
|
||||
signedOrder = buildSignedOrder();
|
||||
remainingMakerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals);
|
||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
||||
calculator = new RemainingFillableCalculator(
|
||||
signedOrder,
|
||||
isMakerTokenZRX,
|
||||
transferrableMakerTokenAmount,
|
||||
transferrableMakerFeeTokenAmount,
|
||||
remainingMakerTokenAmount,
|
||||
);
|
||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
|
||||
});
|
||||
it('calculates the amount to be 0 when all fee funds are transferred', () => {
|
||||
@@ -150,8 +197,13 @@ describe('RemainingFillableCalculator', () => {
|
||||
transferrableMakerTokenAmount = zero;
|
||||
transferrableMakerFeeTokenAmount = zero;
|
||||
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
||||
calculator = new RemainingFillableCalculator(
|
||||
signedOrder,
|
||||
isMakerTokenZRX,
|
||||
transferrableMakerTokenAmount,
|
||||
transferrableMakerFeeTokenAmount,
|
||||
remainingMakerTokenAmount,
|
||||
);
|
||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(zero);
|
||||
});
|
||||
it('calculates the correct amount when balance is less than remaining fillable', () => {
|
||||
@@ -163,8 +215,13 @@ describe('RemainingFillableCalculator', () => {
|
||||
|
||||
const orderToFeeRatio = signedOrder.makerTokenAmount.dividedToIntegerBy(signedOrder.makerFee);
|
||||
const expectedFillableAmount = new BigNumber(450980);
|
||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
||||
calculator = new RemainingFillableCalculator(
|
||||
signedOrder,
|
||||
isMakerTokenZRX,
|
||||
transferrableMakerTokenAmount,
|
||||
transferrableMakerFeeTokenAmount,
|
||||
remainingMakerTokenAmount,
|
||||
);
|
||||
const calculatedFillableAmount = calculator.computeRemainingMakerFillable();
|
||||
const numberOfFillsInRatio = calculatedFillableAmount.dividedToIntegerBy(orderToFeeRatio);
|
||||
const calculatedFillableAmountPlusFees = calculatedFillableAmount.plus(numberOfFillsInRatio);
|
||||
|
@@ -1,27 +1,19 @@
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import * as chai from 'chai';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as _ from 'lodash';
|
||||
import 'mocha';
|
||||
import * as Sinon from 'sinon';
|
||||
import * as Web3 from 'web3';
|
||||
|
||||
import {
|
||||
ApprovalContractEventArgs,
|
||||
DecodedLogEvent,
|
||||
Token,
|
||||
TokenEvents,
|
||||
ZeroEx,
|
||||
} from '../src';
|
||||
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 { assertNodeCallbackError } 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', () => {
|
||||
@@ -65,50 +57,26 @@ describe('SubscriptionTest', () => {
|
||||
it('Should receive the Error when an error occurs while fetching the block', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
const errMsg = 'Error fetching block';
|
||||
const callback = reportCallbackErrors(done)(
|
||||
(err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
||||
expect(err.message).to.be.equal(errMsg);
|
||||
expect(logEvent).to.be.undefined();
|
||||
done();
|
||||
},
|
||||
);
|
||||
stubs = [
|
||||
Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync')
|
||||
.throws(new Error(errMsg)),
|
||||
];
|
||||
zeroEx.token.subscribe(
|
||||
tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
||||
const callback = assertNodeCallbackError(done, errMsg);
|
||||
stubs = [Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync').throws(new Error(errMsg))];
|
||||
zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
||||
await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount);
|
||||
})().catch(done);
|
||||
});
|
||||
it('Should receive the Error when an error occurs while reconciling the new block', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
const errMsg = 'Error fetching logs';
|
||||
const callback = reportCallbackErrors(done)(
|
||||
(err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
||||
expect(err.message).to.be.equal(errMsg);
|
||||
expect(logEvent).to.be.undefined();
|
||||
done();
|
||||
},
|
||||
);
|
||||
stubs = [
|
||||
Sinon.stub((zeroEx as any)._web3Wrapper, 'getLogsAsync')
|
||||
.throws(new Error(errMsg)),
|
||||
];
|
||||
zeroEx.token.subscribe(
|
||||
tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
||||
const callback = assertNodeCallbackError(done, errMsg);
|
||||
stubs = [Sinon.stub((zeroEx as any)._web3Wrapper, 'getLogsAsync').throws(new Error(errMsg))];
|
||||
zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
||||
await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount);
|
||||
})().catch(done);
|
||||
});
|
||||
it('Should allow unsubscribeAll to be called successfully after an error', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
const callback = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => _.noop;
|
||||
zeroEx.token.subscribe(
|
||||
tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
||||
stubs = [
|
||||
Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync')
|
||||
.throws(new Error('JSON RPC error')),
|
||||
];
|
||||
const callback = (err: Error | null, logEvent?: DecodedLogEvent<ApprovalContractEventArgs>) => _.noop;
|
||||
zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
||||
stubs = [Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync').throws(new Error('JSON RPC error'))];
|
||||
zeroEx.token.unsubscribeAll();
|
||||
done();
|
||||
})().catch(done);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import * as chai from 'chai';
|
||||
import 'mocha';
|
||||
import * as Web3 from 'web3';
|
||||
@@ -20,6 +20,7 @@ import {DoneCallback} from '../src/types';
|
||||
|
||||
import { chaiSetup } from './utils/chai_setup';
|
||||
import { constants } from './utils/constants';
|
||||
import { reportNodeCallbackErrors } from './utils/report_callback_errors';
|
||||
import { TokenUtils } from './utils/token_utils';
|
||||
import { web3Factory } from './utils/web3_factory';
|
||||
|
||||
@@ -74,17 +75,17 @@ describe('TokenWrapper', () => {
|
||||
it('should fail to transfer tokens if fromAddress has an insufficient balance', async () => {
|
||||
const fromAddress = addressWithoutFunds;
|
||||
const toAddress = coinbase;
|
||||
return expect(zeroEx.token.transferAsync(
|
||||
token.address, fromAddress, toAddress, transferAmount,
|
||||
)).to.be.rejectedWith(ZeroExError.InsufficientBalanceForTransfer);
|
||||
return expect(
|
||||
zeroEx.token.transferAsync(token.address, fromAddress, toAddress, transferAmount),
|
||||
).to.be.rejectedWith(ZeroExError.InsufficientBalanceForTransfer);
|
||||
});
|
||||
it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
|
||||
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
|
||||
const fromAddress = coinbase;
|
||||
const toAddress = coinbase;
|
||||
return expect(zeroEx.token.transferAsync(
|
||||
nonExistentTokenAddress, fromAddress, toAddress, transferAmount,
|
||||
)).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
|
||||
return expect(
|
||||
zeroEx.token.transferAsync(nonExistentTokenAddress, fromAddress, toAddress, transferAmount),
|
||||
).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
|
||||
});
|
||||
});
|
||||
describe('#transferFromAsync', () => {
|
||||
@@ -103,24 +104,22 @@ describe('TokenWrapper', () => {
|
||||
const fromAddressBalance = await zeroEx.token.getBalanceAsync(token.address, fromAddress);
|
||||
expect(fromAddressBalance).to.be.bignumber.greaterThan(transferAmount);
|
||||
|
||||
const fromAddressAllowance = await zeroEx.token.getAllowanceAsync(token.address, fromAddress,
|
||||
toAddress);
|
||||
const fromAddressAllowance = await zeroEx.token.getAllowanceAsync(token.address, fromAddress, toAddress);
|
||||
expect(fromAddressAllowance).to.be.bignumber.equal(0);
|
||||
|
||||
return expect(zeroEx.token.transferFromAsync(
|
||||
token.address, fromAddress, toAddress, senderAddress, transferAmount,
|
||||
)).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer);
|
||||
return expect(
|
||||
zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount),
|
||||
).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer);
|
||||
});
|
||||
it('[regression] should fail to transfer tokens if set allowance for toAddress instead of senderAddress',
|
||||
async () => {
|
||||
it('[regression] should fail to transfer tokens if set allowance for toAddress instead of senderAddress', async () => {
|
||||
const fromAddress = coinbase;
|
||||
const transferAmount = new BigNumber(42);
|
||||
|
||||
await zeroEx.token.setAllowanceAsync(token.address, fromAddress, toAddress, transferAmount);
|
||||
|
||||
return expect(zeroEx.token.transferFromAsync(
|
||||
token.address, fromAddress, toAddress, senderAddress, transferAmount,
|
||||
)).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer);
|
||||
return expect(
|
||||
zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount),
|
||||
).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer);
|
||||
});
|
||||
it('should fail to transfer tokens if fromAddress has insufficient balance', async () => {
|
||||
const fromAddress = addressWithoutFunds;
|
||||
@@ -130,13 +129,16 @@ describe('TokenWrapper', () => {
|
||||
expect(fromAddressBalance).to.be.bignumber.equal(0);
|
||||
|
||||
await zeroEx.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount);
|
||||
const fromAddressAllowance = await zeroEx.token.getAllowanceAsync(token.address, fromAddress,
|
||||
senderAddress);
|
||||
const fromAddressAllowance = await zeroEx.token.getAllowanceAsync(
|
||||
token.address,
|
||||
fromAddress,
|
||||
senderAddress,
|
||||
);
|
||||
expect(fromAddressAllowance).to.be.bignumber.equal(transferAmount);
|
||||
|
||||
return expect(zeroEx.token.transferFromAsync(
|
||||
token.address, fromAddress, toAddress, senderAddress, transferAmount,
|
||||
)).to.be.rejectedWith(ZeroExError.InsufficientBalanceForTransfer);
|
||||
return expect(
|
||||
zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount),
|
||||
).to.be.rejectedWith(ZeroExError.InsufficientBalanceForTransfer);
|
||||
});
|
||||
it('should successfully transfer tokens', async () => {
|
||||
const fromAddress = coinbase;
|
||||
@@ -147,17 +149,22 @@ describe('TokenWrapper', () => {
|
||||
const transferAmount = new BigNumber(42);
|
||||
await zeroEx.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount);
|
||||
|
||||
await zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress,
|
||||
transferAmount);
|
||||
await zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount);
|
||||
const postBalance = await zeroEx.token.getBalanceAsync(token.address, toAddress);
|
||||
return expect(postBalance).to.be.bignumber.equal(transferAmount);
|
||||
});
|
||||
it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
|
||||
const fromAddress = coinbase;
|
||||
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
|
||||
return expect(zeroEx.token.transferFromAsync(
|
||||
nonExistentTokenAddress, fromAddress, toAddress, senderAddress, new BigNumber(42),
|
||||
)).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
|
||||
return expect(
|
||||
zeroEx.token.transferFromAsync(
|
||||
nonExistentTokenAddress,
|
||||
fromAddress,
|
||||
toAddress,
|
||||
senderAddress,
|
||||
new BigNumber(42),
|
||||
),
|
||||
).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
|
||||
});
|
||||
});
|
||||
describe('#getBalanceAsync', () => {
|
||||
@@ -172,8 +179,9 @@ describe('TokenWrapper', () => {
|
||||
it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
|
||||
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
|
||||
const ownerAddress = coinbase;
|
||||
return expect(zeroEx.token.getBalanceAsync(nonExistentTokenAddress, ownerAddress))
|
||||
.to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
|
||||
return expect(zeroEx.token.getBalanceAsync(nonExistentTokenAddress, ownerAddress)).to.be.rejectedWith(
|
||||
ZeroExError.TokenContractDoesNotExist,
|
||||
);
|
||||
});
|
||||
it('should return a balance of 0 for a non-existent owner address', async () => {
|
||||
const token = tokens[0];
|
||||
@@ -200,13 +208,16 @@ describe('TokenWrapper', () => {
|
||||
});
|
||||
});
|
||||
describe('#setAllowanceAsync', () => {
|
||||
it('should set the spender\'s allowance', async () => {
|
||||
it("should set the spender's allowance", async () => {
|
||||
const token = tokens[0];
|
||||
const ownerAddress = coinbase;
|
||||
const spenderAddress = addressWithoutFunds;
|
||||
|
||||
const allowanceBeforeSet = await zeroEx.token.getAllowanceAsync(token.address, ownerAddress,
|
||||
spenderAddress);
|
||||
const allowanceBeforeSet = await zeroEx.token.getAllowanceAsync(
|
||||
token.address,
|
||||
ownerAddress,
|
||||
spenderAddress,
|
||||
);
|
||||
const expectedAllowanceBeforeAllowanceSet = new BigNumber(0);
|
||||
expect(allowanceBeforeSet).to.be.bignumber.equal(expectedAllowanceBeforeAllowanceSet);
|
||||
|
||||
@@ -219,7 +230,7 @@ describe('TokenWrapper', () => {
|
||||
});
|
||||
});
|
||||
describe('#setUnlimitedAllowanceAsync', () => {
|
||||
it('should set the unlimited spender\'s allowance', async () => {
|
||||
it("should set the unlimited spender's allowance", async () => {
|
||||
const token = tokens[0];
|
||||
const ownerAddress = coinbase;
|
||||
const spenderAddress = addressWithoutFunds;
|
||||
@@ -241,10 +252,18 @@ describe('TokenWrapper', () => {
|
||||
);
|
||||
|
||||
await zeroEx.token.transferFromAsync(
|
||||
zrx.address, coinbase, userWithNormalAllowance, userWithNormalAllowance, transferAmount,
|
||||
zrx.address,
|
||||
coinbase,
|
||||
userWithNormalAllowance,
|
||||
userWithNormalAllowance,
|
||||
transferAmount,
|
||||
);
|
||||
await zeroEx.token.transferFromAsync(
|
||||
zrx.address, coinbase, userWithUnlimitedAllowance, userWithUnlimitedAllowance, transferAmount,
|
||||
zrx.address,
|
||||
coinbase,
|
||||
userWithUnlimitedAllowance,
|
||||
userWithUnlimitedAllowance,
|
||||
transferAmount,
|
||||
);
|
||||
|
||||
const finalBalanceWithNormalAllowance = await web3Wrapper.getBalanceInWeiAsync(userWithNormalAllowance);
|
||||
@@ -300,7 +319,9 @@ describe('TokenWrapper', () => {
|
||||
await zeroEx.token.setAllowanceAsync(token.address, ownerAddress, spenderAddress, amountInBaseUnits);
|
||||
|
||||
const allowance = await zeroExWithoutAccounts.token.getAllowanceAsync(
|
||||
token.address, ownerAddress, spenderAddress,
|
||||
token.address,
|
||||
ownerAddress,
|
||||
spenderAddress,
|
||||
);
|
||||
const expectedAllowance = amountInBaseUnits;
|
||||
return expect(allowance).to.be.bignumber.equal(expectedAllowance);
|
||||
@@ -366,8 +387,8 @@ describe('TokenWrapper', () => {
|
||||
// Source: https://github.com/mochajs/mocha/issues/2407
|
||||
it('Should receive the Transfer event when tokens are transfered', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
const callback = (err: Error, logEvent: DecodedLogEvent<TransferContractEventArgs>) => {
|
||||
expect(logEvent).to.not.be.undefined();
|
||||
const callback = reportNodeCallbackErrors(done)(
|
||||
(logEvent: DecodedLogEvent<TransferContractEventArgs>) => {
|
||||
expect(logEvent.isRemoved).to.be.false();
|
||||
expect(logEvent.log.logIndex).to.be.equal(0);
|
||||
expect(logEvent.log.transactionIndex).to.be.equal(0);
|
||||
@@ -376,55 +397,56 @@ describe('TokenWrapper', () => {
|
||||
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);
|
||||
},
|
||||
);
|
||||
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>) => {
|
||||
const callback = reportNodeCallbackErrors(done)(
|
||||
(logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
||||
expect(logEvent).to.not.be.undefined();
|
||||
expect(logEvent.isRemoved).to.be.false();
|
||||
const args = logEvent.log.args;
|
||||
expect(args._owner).to.be.equal(coinbase);
|
||||
expect(args._spender).to.be.equal(addressWithoutFunds);
|
||||
expect(args._value).to.be.bignumber.equal(allowanceAmount);
|
||||
done();
|
||||
};
|
||||
zeroEx.token.subscribe(
|
||||
tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
||||
},
|
||||
);
|
||||
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>) => {
|
||||
const callbackNeverToBeCalled = reportNodeCallbackErrors(done)(
|
||||
(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();
|
||||
};
|
||||
zeroEx.token.subscribe(tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled);
|
||||
const callbackToBeCalled = reportNodeCallbackErrors(done)();
|
||||
const newProvider = web3Factory.getRpcProvider();
|
||||
zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID);
|
||||
zeroEx.token.subscribe(
|
||||
tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackToBeCalled,
|
||||
);
|
||||
zeroEx.token.subscribe(tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackToBeCalled);
|
||||
await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
|
||||
})().catch(done);
|
||||
});
|
||||
it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => {
|
||||
(async () => {
|
||||
const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
||||
const callbackNeverToBeCalled = reportNodeCallbackErrors(done)(
|
||||
(logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
||||
done(new Error('Expected this subscription to have been cancelled'));
|
||||
};
|
||||
},
|
||||
);
|
||||
const subscriptionToken = zeroEx.token.subscribe(
|
||||
tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled);
|
||||
tokenAddress,
|
||||
TokenEvents.Transfer,
|
||||
indexFilterValues,
|
||||
callbackNeverToBeCalled,
|
||||
);
|
||||
zeroEx.token.unsubscribe(subscriptionToken);
|
||||
await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
|
||||
done();
|
||||
@@ -450,7 +472,10 @@ describe('TokenWrapper', () => {
|
||||
const eventName = TokenEvents.Approval;
|
||||
const indexFilterValues = {};
|
||||
const logs = await zeroEx.token.getLogsAsync<ApprovalContractEventArgs>(
|
||||
tokenAddress, eventName, blockRange, indexFilterValues,
|
||||
tokenAddress,
|
||||
eventName,
|
||||
blockRange,
|
||||
indexFilterValues,
|
||||
);
|
||||
expect(logs).to.have.length(1);
|
||||
const args = logs[0].args;
|
||||
@@ -465,7 +490,10 @@ describe('TokenWrapper', () => {
|
||||
const differentEventName = TokenEvents.Transfer;
|
||||
const indexFilterValues = {};
|
||||
const logs = await zeroEx.token.getLogsAsync(
|
||||
tokenAddress, differentEventName, blockRange, indexFilterValues,
|
||||
tokenAddress,
|
||||
differentEventName,
|
||||
blockRange,
|
||||
indexFilterValues,
|
||||
);
|
||||
expect(logs).to.have.length(0);
|
||||
});
|
||||
@@ -479,7 +507,10 @@ describe('TokenWrapper', () => {
|
||||
_owner: coinbase,
|
||||
};
|
||||
const logs = await zeroEx.token.getLogsAsync<ApprovalContractEventArgs>(
|
||||
tokenAddress, eventName, blockRange, indexFilterValues,
|
||||
tokenAddress,
|
||||
eventName,
|
||||
blockRange,
|
||||
indexFilterValues,
|
||||
);
|
||||
expect(logs).to.have.length(1);
|
||||
const args = logs[0].args;
|
||||
@@ -487,3 +518,4 @@ describe('TokenWrapper', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
// tslint:disable:max-file-line-count
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||
import BigNumber from 'bignumber.js';
|
||||
|
||||
import { SignedOrder, Token, ZeroEx } from '../../src';
|
||||
import { artifacts } from '../../src/artifacts';
|
||||
@@ -11,128 +11,192 @@ import {constants} from './constants';
|
||||
const INITIAL_COINBASE_TOKEN_SUPPLY_IN_UNITS = new BigNumber(100);
|
||||
|
||||
export class FillScenarios {
|
||||
private zeroEx: ZeroEx;
|
||||
private userAddresses: string[];
|
||||
private tokens: Token[];
|
||||
private coinbase: string;
|
||||
private zrxTokenAddress: string;
|
||||
private exchangeContractAddress: string;
|
||||
constructor(zeroEx: ZeroEx, userAddresses: string[],
|
||||
tokens: Token[], zrxTokenAddress: string, exchangeContractAddress: string) {
|
||||
this.zeroEx = zeroEx;
|
||||
this.userAddresses = userAddresses;
|
||||
this.tokens = tokens;
|
||||
this.coinbase = userAddresses[0];
|
||||
this.zrxTokenAddress = zrxTokenAddress;
|
||||
this.exchangeContractAddress = exchangeContractAddress;
|
||||
private _zeroEx: ZeroEx;
|
||||
private _userAddresses: string[];
|
||||
private _tokens: Token[];
|
||||
private _coinbase: string;
|
||||
private _zrxTokenAddress: string;
|
||||
private _exchangeContractAddress: string;
|
||||
constructor(
|
||||
zeroEx: ZeroEx,
|
||||
userAddresses: string[],
|
||||
tokens: Token[],
|
||||
zrxTokenAddress: string,
|
||||
exchangeContractAddress: string,
|
||||
) {
|
||||
this._zeroEx = zeroEx;
|
||||
this._userAddresses = userAddresses;
|
||||
this._tokens = tokens;
|
||||
this._coinbase = userAddresses[0];
|
||||
this._zrxTokenAddress = zrxTokenAddress;
|
||||
this._exchangeContractAddress = exchangeContractAddress;
|
||||
}
|
||||
public async initTokenBalancesAsync() {
|
||||
const web3Wrapper = (this.zeroEx as any)._web3Wrapper as Web3Wrapper;
|
||||
for (const token of this.tokens) {
|
||||
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,
|
||||
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,
|
||||
const txHash = await dummyToken.setBalance.sendTransactionAsync(this._coinbase, tokenSupply, {
|
||||
from: this._coinbase,
|
||||
});
|
||||
await this.zeroEx.awaitTransactionMinedAsync(txHash);
|
||||
await this._zeroEx.awaitTransactionMinedAsync(txHash);
|
||||
}
|
||||
}
|
||||
}
|
||||
public async createFillableSignedOrderAsync(makerTokenAddress: string, takerTokenAddress: string,
|
||||
makerAddress: string, takerAddress: string,
|
||||
public async createFillableSignedOrderAsync(
|
||||
makerTokenAddress: string,
|
||||
takerTokenAddress: string,
|
||||
makerAddress: string,
|
||||
takerAddress: string,
|
||||
fillableAmount: BigNumber,
|
||||
expirationUnixTimestampSec?: BigNumber):
|
||||
Promise<SignedOrder> {
|
||||
expirationUnixTimestampSec?: BigNumber,
|
||||
): Promise<SignedOrder> {
|
||||
return this.createAsymmetricFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
||||
fillableAmount, fillableAmount, expirationUnixTimestampSec,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
fillableAmount,
|
||||
expirationUnixTimestampSec,
|
||||
);
|
||||
}
|
||||
public async createFillableSignedOrderWithFeesAsync(
|
||||
makerTokenAddress: string, takerTokenAddress: string,
|
||||
makerFee: BigNumber, takerFee: BigNumber,
|
||||
makerAddress: string, takerAddress: string,
|
||||
makerTokenAddress: string,
|
||||
takerTokenAddress: string,
|
||||
makerFee: BigNumber,
|
||||
takerFee: BigNumber,
|
||||
makerAddress: string,
|
||||
takerAddress: string,
|
||||
fillableAmount: BigNumber,
|
||||
feeRecepient: string, expirationUnixTimestampSec?: BigNumber,
|
||||
feeRecepient: string,
|
||||
expirationUnixTimestampSec?: BigNumber,
|
||||
): Promise<SignedOrder> {
|
||||
return this.createAsymmetricFillableSignedOrderWithFeesAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress,
|
||||
fillableAmount, fillableAmount, feeRecepient, expirationUnixTimestampSec,
|
||||
return this._createAsymmetricFillableSignedOrderWithFeesAsync(
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerFee,
|
||||
takerFee,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
fillableAmount,
|
||||
feeRecepient,
|
||||
expirationUnixTimestampSec,
|
||||
);
|
||||
}
|
||||
public async createAsymmetricFillableSignedOrderAsync(
|
||||
makerTokenAddress: string, takerTokenAddress: string, makerAddress: string, takerAddress: string,
|
||||
makerFillableAmount: BigNumber, takerFillableAmount: BigNumber,
|
||||
expirationUnixTimestampSec?: BigNumber): Promise<SignedOrder> {
|
||||
makerTokenAddress: string,
|
||||
takerTokenAddress: string,
|
||||
makerAddress: string,
|
||||
takerAddress: string,
|
||||
makerFillableAmount: BigNumber,
|
||||
takerFillableAmount: BigNumber,
|
||||
expirationUnixTimestampSec?: BigNumber,
|
||||
): Promise<SignedOrder> {
|
||||
const makerFee = new BigNumber(0);
|
||||
const takerFee = new BigNumber(0);
|
||||
const feeRecepient = constants.NULL_ADDRESS;
|
||||
return this.createAsymmetricFillableSignedOrderWithFeesAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress,
|
||||
makerFillableAmount, takerFillableAmount, feeRecepient, expirationUnixTimestampSec,
|
||||
return this._createAsymmetricFillableSignedOrderWithFeesAsync(
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerFee,
|
||||
takerFee,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
makerFillableAmount,
|
||||
takerFillableAmount,
|
||||
feeRecepient,
|
||||
expirationUnixTimestampSec,
|
||||
);
|
||||
}
|
||||
public async createPartiallyFilledSignedOrderAsync(makerTokenAddress: string, takerTokenAddress: string,
|
||||
takerAddress: string, fillableAmount: BigNumber,
|
||||
partialFillAmount: BigNumber) {
|
||||
const [makerAddress] = this.userAddresses;
|
||||
public async createPartiallyFilledSignedOrderAsync(
|
||||
makerTokenAddress: string,
|
||||
takerTokenAddress: string,
|
||||
takerAddress: string,
|
||||
fillableAmount: BigNumber,
|
||||
partialFillAmount: BigNumber,
|
||||
) {
|
||||
const [makerAddress] = this._userAddresses;
|
||||
const signedOrder = await this.createAsymmetricFillableSignedOrderAsync(
|
||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
||||
fillableAmount, fillableAmount,
|
||||
makerTokenAddress,
|
||||
takerTokenAddress,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
fillableAmount,
|
||||
fillableAmount,
|
||||
);
|
||||
const shouldThrowOnInsufficientBalanceOrAllowance = false;
|
||||
await this.zeroEx.exchange.fillOrderAsync(
|
||||
signedOrder, partialFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
|
||||
await this._zeroEx.exchange.fillOrderAsync(
|
||||
signedOrder,
|
||||
partialFillAmount,
|
||||
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||
takerAddress,
|
||||
);
|
||||
return signedOrder;
|
||||
}
|
||||
private async createAsymmetricFillableSignedOrderWithFeesAsync(
|
||||
makerTokenAddress: string, takerTokenAddress: string,
|
||||
makerFee: BigNumber, takerFee: BigNumber,
|
||||
makerAddress: string, takerAddress: string,
|
||||
makerFillableAmount: BigNumber, takerFillableAmount: BigNumber,
|
||||
feeRecepient: string, expirationUnixTimestampSec?: BigNumber): Promise<SignedOrder> {
|
||||
|
||||
private async _createAsymmetricFillableSignedOrderWithFeesAsync(
|
||||
makerTokenAddress: string,
|
||||
takerTokenAddress: string,
|
||||
makerFee: BigNumber,
|
||||
takerFee: BigNumber,
|
||||
makerAddress: string,
|
||||
takerAddress: string,
|
||||
makerFillableAmount: BigNumber,
|
||||
takerFillableAmount: BigNumber,
|
||||
feeRecepient: string,
|
||||
expirationUnixTimestampSec?: BigNumber,
|
||||
): Promise<SignedOrder> {
|
||||
await Promise.all([
|
||||
this.increaseBalanceAndAllowanceAsync(makerTokenAddress, makerAddress, makerFillableAmount),
|
||||
this.increaseBalanceAndAllowanceAsync(takerTokenAddress, takerAddress, takerFillableAmount),
|
||||
this._increaseBalanceAndAllowanceAsync(makerTokenAddress, makerAddress, makerFillableAmount),
|
||||
this._increaseBalanceAndAllowanceAsync(takerTokenAddress, takerAddress, takerFillableAmount),
|
||||
]);
|
||||
await Promise.all([
|
||||
this.increaseBalanceAndAllowanceAsync(this.zrxTokenAddress, makerAddress, makerFee),
|
||||
this.increaseBalanceAndAllowanceAsync(this.zrxTokenAddress, takerAddress, takerFee),
|
||||
this._increaseBalanceAndAllowanceAsync(this._zrxTokenAddress, makerAddress, makerFee),
|
||||
this._increaseBalanceAndAllowanceAsync(this._zrxTokenAddress, takerAddress, takerFee),
|
||||
]);
|
||||
|
||||
const signedOrder = await orderFactory.createSignedOrderAsync(this.zeroEx,
|
||||
makerAddress, takerAddress, makerFee, takerFee,
|
||||
makerFillableAmount, makerTokenAddress, takerFillableAmount, takerTokenAddress,
|
||||
this.exchangeContractAddress, feeRecepient, expirationUnixTimestampSec);
|
||||
const signedOrder = await orderFactory.createSignedOrderAsync(
|
||||
this._zeroEx,
|
||||
makerAddress,
|
||||
takerAddress,
|
||||
makerFee,
|
||||
takerFee,
|
||||
makerFillableAmount,
|
||||
makerTokenAddress,
|
||||
takerFillableAmount,
|
||||
takerTokenAddress,
|
||||
this._exchangeContractAddress,
|
||||
feeRecepient,
|
||||
expirationUnixTimestampSec,
|
||||
);
|
||||
return signedOrder;
|
||||
}
|
||||
private async increaseBalanceAndAllowanceAsync(
|
||||
tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
|
||||
private async _increaseBalanceAndAllowanceAsync(
|
||||
tokenAddress: string,
|
||||
address: string,
|
||||
amount: BigNumber,
|
||||
): Promise<void> {
|
||||
if (amount.isZero() || address === ZeroEx.NULL_ADDRESS) {
|
||||
return; // noop
|
||||
}
|
||||
await Promise.all([
|
||||
this.increaseBalanceAsync(tokenAddress, address, amount),
|
||||
this.increaseAllowanceAsync(tokenAddress, address, amount),
|
||||
this._increaseBalanceAsync(tokenAddress, address, amount),
|
||||
this._increaseAllowanceAsync(tokenAddress, address, amount),
|
||||
]);
|
||||
}
|
||||
private async increaseBalanceAsync(
|
||||
tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
|
||||
await this.zeroEx.token.transferAsync(tokenAddress, this.coinbase, address, amount);
|
||||
private async _increaseBalanceAsync(tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
|
||||
await this._zeroEx.token.transferAsync(tokenAddress, this._coinbase, address, amount);
|
||||
}
|
||||
private async increaseAllowanceAsync(
|
||||
tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
|
||||
const oldMakerAllowance = await this.zeroEx.token.getProxyAllowanceAsync(tokenAddress, address);
|
||||
private async _increaseAllowanceAsync(tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
|
||||
const oldMakerAllowance = await this._zeroEx.token.getProxyAllowanceAsync(tokenAddress, address);
|
||||
const newMakerAllowance = oldMakerAllowance.plus(amount);
|
||||
await this.zeroEx.token.setProxyAllowanceAsync(
|
||||
tokenAddress, address, newMakerAllowance,
|
||||
);
|
||||
await this._zeroEx.token.setProxyAllowanceAsync(tokenAddress, address, newMakerAllowance);
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { SignedOrder, ZeroEx } from '../../src';
|
||||
@@ -16,11 +16,12 @@ export const orderFactory = {
|
||||
takerTokenAddress: string,
|
||||
exchangeContractAddress: string,
|
||||
feeRecipient: string,
|
||||
expirationUnixTimestampSecIfExists?: BigNumber): Promise<SignedOrder> {
|
||||
expirationUnixTimestampSecIfExists?: BigNumber,
|
||||
): Promise<SignedOrder> {
|
||||
const defaultExpirationUnixTimestampSec = new BigNumber(2524604400); // Close to infinite
|
||||
const expirationUnixTimestampSec = _.isUndefined(expirationUnixTimestampSecIfExists) ?
|
||||
defaultExpirationUnixTimestampSec :
|
||||
expirationUnixTimestampSecIfExists;
|
||||
const expirationUnixTimestampSec = _.isUndefined(expirationUnixTimestampSecIfExists)
|
||||
? defaultExpirationUnixTimestampSec
|
||||
: expirationUnixTimestampSecIfExists;
|
||||
const order = {
|
||||
maker,
|
||||
taker,
|
||||
|
@@ -1,10 +1,22 @@
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { DoneCallback } from '../../src/types';
|
||||
|
||||
export const reportCallbackErrors = (done: DoneCallback) => {
|
||||
return (f: (...args: any[]) => void) => {
|
||||
const wrapped = async (...args: any[]) => {
|
||||
const expect = chai.expect;
|
||||
|
||||
export const reportNoErrorCallbackErrors = (done: DoneCallback, expectToBeCalledOnce = true) => {
|
||||
return <T>(f?: (value: T) => void) => {
|
||||
const wrapped = (value: T) => {
|
||||
if (_.isUndefined(f)) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
f(...args);
|
||||
f(value);
|
||||
if (expectToBeCalledOnce) {
|
||||
done();
|
||||
}
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
@@ -12,3 +24,43 @@ export const reportCallbackErrors = (done: DoneCallback) => {
|
||||
return wrapped;
|
||||
};
|
||||
};
|
||||
|
||||
export const reportNodeCallbackErrors = (done: DoneCallback, expectToBeCalledOnce = true) => {
|
||||
return <T>(f?: (value: T) => void) => {
|
||||
const wrapped = (error: Error | null, value: T | undefined) => {
|
||||
if (!_.isNull(error)) {
|
||||
done(error);
|
||||
} else {
|
||||
if (_.isUndefined(f)) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
f(value as T);
|
||||
if (expectToBeCalledOnce) {
|
||||
done();
|
||||
}
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
}
|
||||
};
|
||||
return wrapped;
|
||||
};
|
||||
};
|
||||
|
||||
export const assertNodeCallbackError = (done: DoneCallback, errMsg: string) => {
|
||||
const wrapped = <T>(error: Error | null, value: T | undefined) => {
|
||||
if (_.isNull(error)) {
|
||||
done(new Error('Expected callback to receive an error'));
|
||||
} else {
|
||||
try {
|
||||
expect(error.message).to.be.equal(errMsg);
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
}
|
||||
};
|
||||
return wrapped;
|
||||
};
|
||||
|
@@ -9,16 +9,16 @@ import {JSONRPCPayload} from '../../../src/types';
|
||||
* Source: https://github.com/MetaMask/provider-engine/blob/master/subproviders/subprovider.js
|
||||
*/
|
||||
export class FakeGasEstimateSubprovider {
|
||||
private constantGasAmount: number;
|
||||
private _constantGasAmount: number;
|
||||
constructor(constantGasAmount: number) {
|
||||
this.constantGasAmount = constantGasAmount;
|
||||
this._constantGasAmount = constantGasAmount;
|
||||
}
|
||||
// This method needs to be here to satisfy the interface but linter wants it to be static.
|
||||
// tslint:disable-next-line:prefer-function-over-method
|
||||
public handleRequest(payload: JSONRPCPayload, next: () => void, end: (err: Error | null, result: any) => void) {
|
||||
switch (payload.method) {
|
||||
case 'eth_estimateGas':
|
||||
end(null, this.constantGasAmount);
|
||||
end(null, this._constantGasAmount);
|
||||
return;
|
||||
|
||||
default:
|
||||
|
@@ -6,26 +6,26 @@ const PROTOCOL_TOKEN_SYMBOL = 'ZRX';
|
||||
const WETH_TOKEN_SYMBOL = 'WETH';
|
||||
|
||||
export class TokenUtils {
|
||||
private tokens: Token[];
|
||||
private _tokens: Token[];
|
||||
constructor(tokens: Token[]) {
|
||||
this.tokens = tokens;
|
||||
this._tokens = tokens;
|
||||
}
|
||||
public getProtocolTokenOrThrow(): Token {
|
||||
const zrxToken = _.find(this.tokens, {symbol: PROTOCOL_TOKEN_SYMBOL});
|
||||
const zrxToken = _.find(this._tokens, { symbol: PROTOCOL_TOKEN_SYMBOL });
|
||||
if (_.isUndefined(zrxToken)) {
|
||||
throw new Error(InternalZeroExError.ZrxNotInTokenRegistry);
|
||||
}
|
||||
return zrxToken;
|
||||
}
|
||||
public getWethTokenOrThrow(): Token {
|
||||
const wethToken = _.find(this.tokens, {symbol: WETH_TOKEN_SYMBOL});
|
||||
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 => {
|
||||
const dummyTokens = _.filter(this._tokens, token => {
|
||||
return !_.includes([PROTOCOL_TOKEN_SYMBOL, WETH_TOKEN_SYMBOL], token.symbol);
|
||||
});
|
||||
return dummyTokens;
|
||||
|
@@ -31,9 +31,11 @@ export const web3Factory = {
|
||||
provider.addProvider(new EmptyWalletSubprovider());
|
||||
}
|
||||
provider.addProvider(new FakeGasEstimateSubprovider(constants.GAS_ESTIMATE));
|
||||
provider.addProvider(new RpcSubprovider({
|
||||
provider.addProvider(
|
||||
new RpcSubprovider({
|
||||
rpcUrl: constants.RPC_URL,
|
||||
}));
|
||||
}),
|
||||
);
|
||||
provider.start();
|
||||
return provider;
|
||||
},
|
||||
|
@@ -1,14 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"lib": [ "es2015", "dom" ],
|
||||
"outDir": "lib",
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"noImplicitAny": true,
|
||||
"experimentalDecorators": true,
|
||||
"strictNullChecks": true
|
||||
"noImplicitThis": false
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*",
|
||||
|
@@ -1,5 +1,3 @@
|
||||
{
|
||||
"extends": [
|
||||
"@0xproject/tslint-config"
|
||||
]
|
||||
"extends": ["@0xproject/tslint-config"]
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@ const path = require('path');
|
||||
const production = process.env.NODE_ENV === 'production';
|
||||
|
||||
let entry = {
|
||||
'index': './src/index.ts',
|
||||
index: './src/index.ts',
|
||||
};
|
||||
if (production) {
|
||||
entry = _.assign({}, entry, { 'index.min': './src/index.ts' });
|
||||
|
@@ -1,4 +1,7 @@
|
||||
# CHANGELOG
|
||||
|
||||
vx.x.x
|
||||
------------------------
|
||||
## v0.1.0 - _January 11, 2018_
|
||||
|
||||
* Fixed array typings with union types (#295)
|
||||
* Add event ABIs to context data passed to templates (#302)
|
||||
* Add constructor ABIs to context data passed to templates (#304)
|
||||
|
@@ -5,11 +5,14 @@ It's heavily inspired by [Geth abigen](https://github.com/ethereum/go-ethereum/w
|
||||
You can write your custom handlebars templates which will allow you to seamlessly integrate the generated code into your existing codebase with existing conventions.
|
||||
|
||||
For an example of the generated [wrapper files](https://github.com/0xProject/0x.js/tree/development/packages/0x.js/src/contract_wrappers/generated) check out 0x.js.
|
||||
[Here](https://github.com/0xProject/0x.js/tree/development/packages/0x.js/src/contract_templates) are the templates used to generate those files.
|
||||
[Here](https://github.com/0xProject/0x.js/tree/development/packages/0x.js/contract_templates) are the templates used to generate those files.
|
||||
|
||||
## Installation
|
||||
|
||||
## Instalation
|
||||
`yarn add -g @0xproject/abi-gen`
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
abi-gen
|
||||
Options:
|
||||
@@ -19,8 +22,10 @@ Options:
|
||||
--templates Folder where to search for templates [string] [required]
|
||||
--output Folder where to put the output files [string] [required]
|
||||
```
|
||||
|
||||
## ABI files
|
||||
You're required to pass a [glob](https://en.wikipedia.org/wiki/Glob_(programming)) template where your abi files are located.
|
||||
|
||||
You're required to pass a [glob](<https://en.wikipedia.org/wiki/Glob_(programming)>) template where your abi files are located.
|
||||
TL;DR - here is the example from 0x.js.
|
||||
|
||||
`--abiGlob 'src/artifacts/@(Exchange|Token|TokenTransferProxy|EtherToken|TokenRegistry).json`
|
||||
@@ -28,12 +33,18 @@ TL;DR - here is the example from 0x.js.
|
||||
We could've just used `--abiGlob 'src/artifacts/*.json` but we wanted to exclude some of the abi files.
|
||||
|
||||
The abi file should be either a [Truffle](http://truffleframework.com/) contract artifact (a JSON object with an abi key) or a JSON abi array.
|
||||
|
||||
## How to write custom templates?
|
||||
The best way to get started is to copy [0x.js templates](https://github.com/0xProject/0x.js/tree/development/packages/0x.js/src/contract_templates) and start adjusting them for your needs.
|
||||
We use [handlebars](handlebarsjs.com) template engine under the hood.
|
||||
|
||||
The best way to get started is to copy [0x.js templates](https://github.com/0xProject/0x.js/tree/development/packages/0x.js/contract_templates) and start adjusting them for your needs.
|
||||
We use [handlebars](http://handlebarsjs.com/) template engine under the hood.
|
||||
You need to have a master template called `contract.mustache`. it will be used to generate each contract wrapper. Although - you don't need and probably shouldn't write all your logic in a single template file. You can write [partial templates](http://handlebarsjs.com/partials.html) and as long as they are within a partials folder - they will be registered and available.
|
||||
|
||||
## Which data/context do I get in my templates?
|
||||
|
||||
For now you don't get much on top of methods abi, some useful helpers and a contract name because it was enough for our use-case, but if you need something else - create a PR.
|
||||
See the [type definition](https://github.com/0xProject/0x.js/tree/development/packages/abi-gen/src/types.ts) of what we pass to the render method.
|
||||
|
||||
## Output files
|
||||
|
||||
Output files will be generated within an output folder with names converted to camel case and taken from abi file names. If you already have some files in that folder they will be overwritten.
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/abi-gen",
|
||||
"version": "0.0.2",
|
||||
"version": "0.1.1",
|
||||
"description": "Generate contract wrappers from ABI and handlebars templates",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
@@ -22,7 +22,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x.js/packages/abi-gen/README.md",
|
||||
"dependencies": {
|
||||
"bignumber.js": "~4.1.0",
|
||||
"@0xproject/utils": "^0.1.3",
|
||||
"chalk": "^2.3.0",
|
||||
"glob": "^7.1.2",
|
||||
"handlebars": "^4.0.11",
|
||||
@@ -33,7 +33,7 @@
|
||||
"yargs": "^10.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^0.2.1",
|
||||
"@0xproject/tslint-config": "^0.4.1",
|
||||
"@types/glob": "^5.0.33",
|
||||
"@types/handlebars": "^4.0.36",
|
||||
"@types/mkdirp": "^0.5.1",
|
||||
@@ -43,6 +43,6 @@
|
||||
"shx": "^0.2.2",
|
||||
"tslint": "5.8.0",
|
||||
"typescript": "~2.6.1",
|
||||
"web3-typescript-typings": "^0.7.2"
|
||||
"web3-typescript-typings": "^0.9.3"
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,8 @@ const packageJSON = require('../package.json');
|
||||
|
||||
const subPackageName = packageJSON.name;
|
||||
|
||||
postpublish_utils.getLatestTagAndVersionAsync(subPackageName)
|
||||
postpublish_utils
|
||||
.getLatestTagAndVersionAsync(subPackageName)
|
||||
.then(function(result) {
|
||||
const releaseName = postpublish_utils.getReleaseName(subPackageName, result.version);
|
||||
const assets = [];
|
||||
|
@@ -14,7 +14,9 @@ import * as Web3 from 'web3';
|
||||
import { ContextData, ParamKind } from './types';
|
||||
import { utils } from './utils';
|
||||
|
||||
const ABI_TYPE_CONSTRUCTOR = 'constructor';
|
||||
const ABI_TYPE_METHOD = 'function';
|
||||
const ABI_TYPE_EVENT = 'event';
|
||||
const MAIN_TEMPLATE_NAME = 'contract.mustache';
|
||||
|
||||
const args = yargs
|
||||
@@ -32,8 +34,7 @@ const args = yargs
|
||||
describe: 'Folder where to put the output files',
|
||||
type: 'string',
|
||||
demand: true,
|
||||
})
|
||||
.argv;
|
||||
}).argv;
|
||||
|
||||
function writeOutputFile(name: string, renderedTsCode: string): void {
|
||||
const fileName = toSnakeCase(name);
|
||||
@@ -66,14 +67,20 @@ for (const abiFileName of abiFileNames) {
|
||||
const namedContent = utils.getNamedContent(abiFileName);
|
||||
utils.log(`Processing: ${chalk.bold(namedContent.name)}...`);
|
||||
const parsedContent = JSON.parse(namedContent.content);
|
||||
const ABI = _.isArray(parsedContent) ?
|
||||
parsedContent : // ABI file
|
||||
parsedContent.abi; // Truffle contracts file
|
||||
const ABI = _.isArray(parsedContent)
|
||||
? parsedContent // ABI file
|
||||
: parsedContent.abi; // Truffle contracts file
|
||||
if (_.isUndefined(ABI)) {
|
||||
utils.log(`${chalk.red(`ABI not found in ${abiFileName}.`)}`);
|
||||
utils.log(`Please make sure your ABI file is either an array with ABI entries or an object with the abi key`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let ctor = ABI.find((abi: Web3.AbiDefinition) => abi.type === ABI_TYPE_CONSTRUCTOR) as Web3.ConstructorAbi;
|
||||
if (_.isUndefined(ctor)) {
|
||||
ctor = utils.getEmptyConstructor(); // The constructor exists, but it's implicit in JSON's ABI definition
|
||||
}
|
||||
|
||||
const methodAbis = ABI.filter((abi: Web3.AbiDefinition) => abi.type === ABI_TYPE_METHOD) as Web3.MethodAbi[];
|
||||
const methodsData = _.map(methodAbis, methodAbi => {
|
||||
_.map(methodAbi.inputs, input => {
|
||||
@@ -89,9 +96,14 @@ for (const abiFileName of abiFileNames) {
|
||||
};
|
||||
return methodData;
|
||||
});
|
||||
|
||||
const eventAbis = ABI.filter((abi: Web3.AbiDefinition) => abi.type === ABI_TYPE_EVENT) as Web3.EventAbi[];
|
||||
|
||||
const contextData = {
|
||||
contractName: namedContent.name,
|
||||
ctor,
|
||||
methods: methodsData,
|
||||
events: eventAbis,
|
||||
};
|
||||
const renderedTsCode = template(contextData);
|
||||
writeOutputFile(namedContent.name, renderedTsCode);
|
||||
|
@@ -5,6 +5,13 @@ export enum ParamKind {
|
||||
Output = 'output',
|
||||
}
|
||||
|
||||
export enum AbiType {
|
||||
Function = 'function',
|
||||
Constructor = 'constructor',
|
||||
Event = 'event',
|
||||
Fallback = 'fallback',
|
||||
}
|
||||
|
||||
export interface Method extends Web3.MethodAbi {
|
||||
singleReturnValue: boolean;
|
||||
}
|
||||
@@ -12,4 +19,5 @@ export interface Method extends Web3.MethodAbi {
|
||||
export interface ContextData {
|
||||
contractName: string;
|
||||
methods: Method[];
|
||||
events: Web3.EventAbi[];
|
||||
}
|
||||
|
@@ -1,8 +1,9 @@
|
||||
import * as fs from 'fs';
|
||||
import * as _ from 'lodash';
|
||||
import * as path from 'path';
|
||||
import * as Web3 from 'web3';
|
||||
|
||||
import {ParamKind} from './types';
|
||||
import { AbiType, ParamKind } from './types';
|
||||
|
||||
export const utils = {
|
||||
solTypeToTsType(paramKind: ParamKind, solType: string): string {
|
||||
@@ -10,7 +11,9 @@ export const utils = {
|
||||
if (solType.match(trailingArrayRegex)) {
|
||||
const arrayItemSolType = solType.replace(trailingArrayRegex, '');
|
||||
const arrayItemTsType = utils.solTypeToTsType(paramKind, arrayItemSolType);
|
||||
const arrayTsType = `${arrayItemTsType}[]`;
|
||||
const arrayTsType = utils.isUnionType(arrayItemTsType)
|
||||
? `Array<${arrayItemTsType}>`
|
||||
: `${arrayItemTsType}[]`;
|
||||
return arrayTsType;
|
||||
} else {
|
||||
const solTypeRegexToTsType = [
|
||||
@@ -23,7 +26,10 @@ export const utils = {
|
||||
if (paramKind === ParamKind.Input) {
|
||||
// web3 allows to pass those an non-bignumbers and that's nice
|
||||
// but it always returns stuff as BigNumbers
|
||||
solTypeRegexToTsType.unshift({regex: '^u?int(8|16|32)?$', tsType: 'number|BigNumber'});
|
||||
solTypeRegexToTsType.unshift({
|
||||
regex: '^u?int(8|16|32)?$',
|
||||
tsType: 'number|BigNumber',
|
||||
});
|
||||
}
|
||||
for (const regexAndTxType of solTypeRegexToTsType) {
|
||||
const { regex, tsType } = regexAndTxType;
|
||||
@@ -34,6 +40,9 @@ export const utils = {
|
||||
throw new Error(`Unknown Solidity type found: ${solType}`);
|
||||
}
|
||||
},
|
||||
isUnionType(tsType: string): boolean {
|
||||
return tsType === 'number|BigNumber';
|
||||
},
|
||||
log(...args: any[]): void {
|
||||
console.log(...args); // tslint:disable-line:no-console
|
||||
},
|
||||
@@ -53,4 +62,12 @@ export const utils = {
|
||||
throw new Error(`Failed to read ${filename}: ${err}`);
|
||||
}
|
||||
},
|
||||
getEmptyConstructor(): Web3.ConstructorAbi {
|
||||
return {
|
||||
type: AbiType.Constructor,
|
||||
stateMutability: 'nonpayable',
|
||||
payable: false,
|
||||
inputs: [],
|
||||
};
|
||||
},
|
||||
};
|
||||
|
@@ -1,17 +1,7 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"lib": ["es2015", "dom"],
|
||||
"outDir": "lib",
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": true
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*",
|
||||
"./test/**/*",
|
||||
"../../node_modules/web3-typescript-typings/index.d.ts"
|
||||
]
|
||||
"include": ["./src/**/*", "./test/**/*", "../../node_modules/web3-typescript-typings/index.d.ts"]
|
||||
}
|
||||
|
@@ -1,5 +1,3 @@
|
||||
{
|
||||
"extends": [
|
||||
"@0xproject/tslint-config"
|
||||
]
|
||||
"extends": ["@0xproject/tslint-config"]
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
# CHANGELOG
|
||||
|
||||
v0.0.4 - _Nov. 14, 2017_
|
||||
------------------------
|
||||
## v0.0.4 - _Nov. 14, 2017_
|
||||
|
||||
* Re-publish Assert previously published under NPM package @0xproject/0x-assert
|
||||
* Added assertion isValidBaseUnitAmount which checks both that the value is a valid bigNumber and that it does not contain decimals.
|
||||
|
@@ -1,5 +1,4 @@
|
||||
@0xproject/assert
|
||||
------
|
||||
## @0xproject/assert
|
||||
|
||||
Standard type and schema assertions to be used across all 0x projects and packages
|
||||
|
||||
@@ -26,11 +25,13 @@ Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting
|
||||
### 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
|
||||
```
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@0xproject/assert",
|
||||
"version": "0.0.7",
|
||||
"version": "0.0.10",
|
||||
"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",
|
||||
@@ -23,7 +23,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x.js/packages/assert/README.md",
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^0.2.1",
|
||||
"@0xproject/tslint-config": "^0.4.1",
|
||||
"@types/lodash": "^4.14.86",
|
||||
"@types/mocha": "^2.2.42",
|
||||
"@types/valid-url": "^1.0.2",
|
||||
@@ -37,9 +37,8 @@
|
||||
"typescript": "~2.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@0xproject/json-schemas": "^0.6.10",
|
||||
"@0xproject/utils": "^0.1.0",
|
||||
"bignumber.js": "~4.1.0",
|
||||
"@0xproject/json-schemas": "^0.7.2",
|
||||
"@0xproject/utils": "^0.1.3",
|
||||
"lodash": "^4.17.4",
|
||||
"valid-url": "^1.0.9"
|
||||
}
|
||||
|
@@ -3,7 +3,8 @@ const packageJSON = require('../package.json');
|
||||
|
||||
const subPackageName = packageJSON.name;
|
||||
|
||||
postpublish_utils.getLatestTagAndVersionAsync(subPackageName)
|
||||
postpublish_utils
|
||||
.getLatestTagAndVersionAsync(subPackageName)
|
||||
.then(function(result) {
|
||||
const releaseName = postpublish_utils.getReleaseName(subPackageName, result.version);
|
||||
const assets = [];
|
||||
|
@@ -1,9 +1,5 @@
|
||||
import {
|
||||
Schema,
|
||||
SchemaValidator,
|
||||
} from '@0xproject/json-schemas';
|
||||
import {addressUtils} from '@0xproject/utils';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { Schema, SchemaValidator } from '@0xproject/json-schemas';
|
||||
import { addressUtils, BigNumber } from '@0xproject/utils';
|
||||
import * as _ from 'lodash';
|
||||
import * as validUrl from 'valid-url';
|
||||
|
||||
@@ -18,12 +14,10 @@ export const assert = {
|
||||
assert.isBigNumber(variableName, value);
|
||||
const hasDecimals = value.decimalPlaces() !== 0;
|
||||
this.assert(
|
||||
!hasDecimals, `${variableName} should be in baseUnits (no decimals), found value: ${value.toNumber()}`,
|
||||
!hasDecimals,
|
||||
`${variableName} should be in baseUnits (no decimals), found value: ${value.toNumber()}`,
|
||||
);
|
||||
},
|
||||
isUndefined(value: any, variableName?: string): void {
|
||||
this.assert(_.isUndefined(value), this.typeAssertionMessage(variableName, 'undefined', value));
|
||||
},
|
||||
isString(variableName: string, value: string): void {
|
||||
this.assert(_.isString(value), this.typeAssertionMessage(variableName, 'string', value));
|
||||
},
|
||||
@@ -31,8 +25,10 @@ export const assert = {
|
||||
this.assert(_.isFunction(value), this.typeAssertionMessage(variableName, 'function', value));
|
||||
},
|
||||
isHexString(variableName: string, value: string): void {
|
||||
this.assert(_.isString(value) && HEX_REGEX.test(value),
|
||||
this.typeAssertionMessage(variableName, 'HexString', value));
|
||||
this.assert(
|
||||
_.isString(value) && HEX_REGEX.test(value),
|
||||
this.typeAssertionMessage(variableName, 'HexString', value),
|
||||
);
|
||||
},
|
||||
isETHAddressHex(variableName: string, value: string): void {
|
||||
this.assert(addressUtils.isAddress(value), this.typeAssertionMessage(variableName, 'ETHAddressHex', value));
|
||||
@@ -41,8 +37,11 @@ export const assert = {
|
||||
`Checksummed addresses are not supported. Convert ${variableName} to lower case before passing`,
|
||||
);
|
||||
},
|
||||
doesBelongToStringEnum(variableName: string, value: string,
|
||||
stringEnum: any /* There is no base type for every string enum */): void {
|
||||
doesBelongToStringEnum(
|
||||
variableName: string,
|
||||
value: string,
|
||||
stringEnum: any /* There is no base type for every string enum */,
|
||||
): void {
|
||||
const doesBelongToStringEnum = !_.isUndefined(stringEnum[value]);
|
||||
const enumValues = _.keys(stringEnum);
|
||||
const enumValuesAsStrings = _.map(enumValues, enumValue => `'${enumValue}'`);
|
||||
@@ -62,7 +61,7 @@ export const assert = {
|
||||
this.assert(_.isBoolean(value), this.typeAssertionMessage(variableName, 'boolean', value));
|
||||
},
|
||||
isWeb3Provider(variableName: string, value: any): void {
|
||||
const isWeb3Provider = _.isFunction((value).send) || _.isFunction((value).sendAsync);
|
||||
const isWeb3Provider = _.isFunction(value.send) || _.isFunction(value.sendAsync);
|
||||
this.assert(isWeb3Provider, this.typeAssertionMessage(variableName, 'Web3.Provider', value));
|
||||
},
|
||||
doesConformToSchema(variableName: string, value: any, schema: Schema): void {
|
||||
@@ -75,11 +74,11 @@ Validation errors: ${validationResult.errors.join(', ')}`;
|
||||
this.assert(!hasValidationErrors, msg);
|
||||
},
|
||||
isHttpUrl(variableName: string, value: any): void {
|
||||
const isValidUrl = validUrl.isWebUri(value);
|
||||
const isValidUrl = !_.isUndefined(validUrl.isWebUri(value));
|
||||
this.assert(isValidUrl, this.typeAssertionMessage(variableName, 'http url', value));
|
||||
},
|
||||
isUri(variableName: string, value: any): void {
|
||||
const isValidUri = validUrl.isUri(value);
|
||||
const isValidUri = !_.isUndefined(validUrl.isUri(value));
|
||||
this.assert(isValidUri, this.typeAssertionMessage(variableName, 'uri', value));
|
||||
},
|
||||
assert(condition: boolean, message: string): void {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { schemas } from '@0xproject/json-schemas';
|
||||
import {BigNumber} from 'bignumber.js';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as dirtyChai from 'dirty-chai';
|
||||
import 'mocha';
|
||||
@@ -14,75 +14,31 @@ describe('Assertions', () => {
|
||||
const variableName = 'variable';
|
||||
describe('#isBigNumber', () => {
|
||||
it('should not throw for valid input', () => {
|
||||
const validInputs = [
|
||||
new BigNumber(23),
|
||||
new BigNumber('45'),
|
||||
];
|
||||
const validInputs = [new BigNumber(23), new BigNumber('45')];
|
||||
validInputs.forEach(input => expect(assert.isBigNumber.bind(assert, variableName, input)).to.not.throw());
|
||||
});
|
||||
it('should throw for invalid input', () => {
|
||||
const invalidInputs = [
|
||||
'test',
|
||||
42,
|
||||
false,
|
||||
{random: 'test'},
|
||||
undefined,
|
||||
];
|
||||
const invalidInputs = ['test', 42, false, { random: 'test' }, undefined];
|
||||
invalidInputs.forEach(input => expect(assert.isBigNumber.bind(assert, variableName, input)).to.throw());
|
||||
});
|
||||
});
|
||||
describe('#isUndefined', () => {
|
||||
it('should not throw for valid input', () => {
|
||||
const validInputs = [
|
||||
undefined,
|
||||
];
|
||||
validInputs.forEach(input => expect(assert.isUndefined.bind(assert, input, variableName)).to.not.throw());
|
||||
});
|
||||
it('should throw for invalid input', () => {
|
||||
const invalidInputs = [
|
||||
'test',
|
||||
42,
|
||||
false,
|
||||
{random: 'test'},
|
||||
];
|
||||
invalidInputs.forEach(input => expect(assert.isUndefined.bind(assert, input, variableName)).to.throw());
|
||||
});
|
||||
});
|
||||
describe('#isString', () => {
|
||||
it('should not throw for valid input', () => {
|
||||
const validInputs = [
|
||||
'hello',
|
||||
'goodbye',
|
||||
];
|
||||
const validInputs = ['hello', 'goodbye'];
|
||||
validInputs.forEach(input => expect(assert.isString.bind(assert, variableName, input)).to.not.throw());
|
||||
});
|
||||
it('should throw for invalid input', () => {
|
||||
const invalidInputs = [
|
||||
42,
|
||||
false,
|
||||
{random: 'test'},
|
||||
undefined,
|
||||
new BigNumber(45),
|
||||
];
|
||||
const invalidInputs = [42, false, { random: 'test' }, undefined, new BigNumber(45)];
|
||||
invalidInputs.forEach(input => expect(assert.isString.bind(assert, variableName, input)).to.throw());
|
||||
});
|
||||
});
|
||||
describe('#isFunction', () => {
|
||||
it('should not throw for valid input', () => {
|
||||
const validInputs = [
|
||||
BigNumber,
|
||||
assert.isString.bind(this),
|
||||
];
|
||||
const validInputs = [BigNumber, assert.isString];
|
||||
validInputs.forEach(input => expect(assert.isFunction.bind(assert, variableName, input)).to.not.throw());
|
||||
});
|
||||
it('should throw for invalid input', () => {
|
||||
const invalidInputs = [
|
||||
42,
|
||||
false,
|
||||
{random: 'test'},
|
||||
undefined,
|
||||
new BigNumber(45),
|
||||
];
|
||||
const invalidInputs = [42, false, { random: 'test' }, undefined, new BigNumber(45)];
|
||||
invalidInputs.forEach(input => expect(assert.isFunction.bind(assert, variableName, input)).to.throw());
|
||||
});
|
||||
});
|
||||
@@ -127,9 +83,7 @@ describe('Assertions', () => {
|
||||
'0x6FFFd0ae3f7d88c9b4925323f54c6e4b2918c5fd',
|
||||
'0x6FFFd0ae3f7d88c9b4925323f54c6e4',
|
||||
];
|
||||
invalidInputs.forEach(input =>
|
||||
expect(assert.isETHAddressHex.bind(assert, variableName, input)).to.throw(),
|
||||
);
|
||||
invalidInputs.forEach(input => expect(assert.isETHAddressHex.bind(assert, variableName, input)).to.throw());
|
||||
});
|
||||
});
|
||||
describe('#doesBelongToStringEnum', () => {
|
||||
@@ -138,22 +92,13 @@ describe('Assertions', () => {
|
||||
Test2 = 'Test2',
|
||||
}
|
||||
it('should not throw for valid input', () => {
|
||||
const validInputs = [
|
||||
TestEnums.Test1,
|
||||
TestEnums.Test2,
|
||||
];
|
||||
const validInputs = [TestEnums.Test1, TestEnums.Test2];
|
||||
validInputs.forEach(input =>
|
||||
expect(assert.doesBelongToStringEnum.bind(assert, variableName, input, TestEnums)).to.not.throw(),
|
||||
);
|
||||
});
|
||||
it('should throw for invalid input', () => {
|
||||
const invalidInputs = [
|
||||
42,
|
||||
false,
|
||||
{random: 'test'},
|
||||
undefined,
|
||||
new BigNumber(45),
|
||||
];
|
||||
const invalidInputs = [42, false, { random: 'test' }, undefined, new BigNumber(45)];
|
||||
invalidInputs.forEach(input =>
|
||||
expect(assert.doesBelongToStringEnum.bind(assert, variableName, input, TestEnums)).to.throw(),
|
||||
);
|
||||
@@ -162,19 +107,13 @@ describe('Assertions', () => {
|
||||
describe('#hasAtMostOneUniqueValue', () => {
|
||||
const errorMsg = 'more than one unique value';
|
||||
it('should not throw for valid input', () => {
|
||||
const validInputs = [
|
||||
['hello'],
|
||||
['goodbye', 'goodbye', 'goodbye'],
|
||||
];
|
||||
const validInputs = [['hello'], ['goodbye', 'goodbye', 'goodbye']];
|
||||
validInputs.forEach(input =>
|
||||
expect(assert.hasAtMostOneUniqueValue.bind(assert, input, errorMsg)).to.not.throw(),
|
||||
);
|
||||
});
|
||||
it('should throw for invalid input', () => {
|
||||
const invalidInputs = [
|
||||
['hello', 'goodbye'],
|
||||
['goodbye', 42, false, false],
|
||||
];
|
||||
const invalidInputs = [['hello', 'goodbye'], ['goodbye', 42, false, false]];
|
||||
invalidInputs.forEach(input =>
|
||||
expect(assert.hasAtMostOneUniqueValue.bind(assert, input, errorMsg)).to.throw(),
|
||||
);
|
||||
@@ -182,61 +121,34 @@ describe('Assertions', () => {
|
||||
});
|
||||
describe('#isNumber', () => {
|
||||
it('should not throw for valid input', () => {
|
||||
const validInputs = [
|
||||
42,
|
||||
0,
|
||||
21e+42,
|
||||
];
|
||||
const validInputs = [42, 0, 21e42];
|
||||
validInputs.forEach(input => expect(assert.isNumber.bind(assert, variableName, input)).to.not.throw());
|
||||
});
|
||||
it('should throw for invalid input', () => {
|
||||
const invalidInputs = [
|
||||
false,
|
||||
{random: 'test'},
|
||||
undefined,
|
||||
new BigNumber(45),
|
||||
];
|
||||
const invalidInputs = [false, { random: 'test' }, undefined, new BigNumber(45)];
|
||||
invalidInputs.forEach(input => expect(assert.isNumber.bind(assert, variableName, input)).to.throw());
|
||||
});
|
||||
});
|
||||
describe('#isBoolean', () => {
|
||||
it('should not throw for valid input', () => {
|
||||
const validInputs = [
|
||||
true,
|
||||
false,
|
||||
];
|
||||
const validInputs = [true, false];
|
||||
validInputs.forEach(input => expect(assert.isBoolean.bind(assert, variableName, input)).to.not.throw());
|
||||
});
|
||||
it('should throw for invalid input', () => {
|
||||
const invalidInputs = [
|
||||
42,
|
||||
{random: 'test'},
|
||||
undefined,
|
||||
new BigNumber(45),
|
||||
];
|
||||
const invalidInputs = [42, { random: 'test' }, undefined, new BigNumber(45)];
|
||||
invalidInputs.forEach(input => expect(assert.isBoolean.bind(assert, variableName, input)).to.throw());
|
||||
});
|
||||
});
|
||||
describe('#isWeb3Provider', () => {
|
||||
it('should not throw for valid input', () => {
|
||||
const validInputs = [
|
||||
{send: () => 45},
|
||||
{sendAsync: () => 45},
|
||||
];
|
||||
const validInputs = [{ send: () => 45 }, { sendAsync: () => 45 }];
|
||||
validInputs.forEach(input =>
|
||||
expect(assert.isWeb3Provider.bind(assert, variableName, input)).to.not.throw(),
|
||||
);
|
||||
});
|
||||
it('should throw for invalid input', () => {
|
||||
const invalidInputs = [
|
||||
42,
|
||||
{random: 'test'},
|
||||
undefined,
|
||||
new BigNumber(45),
|
||||
];
|
||||
invalidInputs.forEach(input =>
|
||||
expect(assert.isWeb3Provider.bind(assert, variableName, input)).to.throw(),
|
||||
);
|
||||
const invalidInputs = [42, { random: 'test' }, undefined, new BigNumber(45)];
|
||||
invalidInputs.forEach(input => expect(assert.isWeb3Provider.bind(assert, variableName, input)).to.throw());
|
||||
});
|
||||
});
|
||||
describe('#doesConformToSchema', () => {
|
||||
@@ -251,12 +163,7 @@ describe('Assertions', () => {
|
||||
);
|
||||
});
|
||||
it('should throw for invalid input', () => {
|
||||
const invalidInputs = [
|
||||
42,
|
||||
{random: 'test'},
|
||||
undefined,
|
||||
new BigNumber(45),
|
||||
];
|
||||
const invalidInputs = [42, { random: 'test' }, undefined, new BigNumber(45)];
|
||||
invalidInputs.forEach(input =>
|
||||
expect(assert.doesConformToSchema.bind(assert, variableName, input, schema)).to.throw(),
|
||||
);
|
||||
@@ -270,9 +177,7 @@ describe('Assertions', () => {
|
||||
'https://api.radarrelay.com/0x/v0/',
|
||||
'https://zeroex.beta.radarrelay.com:8000/0x/v0/',
|
||||
];
|
||||
validInputs.forEach(input =>
|
||||
expect(assert.isHttpUrl.bind(assert, variableName, input)).to.not.throw(),
|
||||
);
|
||||
validInputs.forEach(input => expect(assert.isHttpUrl.bind(assert, variableName, input)).to.not.throw());
|
||||
});
|
||||
it('should throw for invalid input', () => {
|
||||
const invalidInputs = [
|
||||
@@ -286,9 +191,7 @@ describe('Assertions', () => {
|
||||
'user:password@api.example-relayer.net',
|
||||
'//api.example-relayer.net',
|
||||
];
|
||||
invalidInputs.forEach(input =>
|
||||
expect(assert.isHttpUrl.bind(assert, variableName, input)).to.throw(),
|
||||
);
|
||||
invalidInputs.forEach(input => expect(assert.isHttpUrl.bind(assert, variableName, input)).to.throw());
|
||||
});
|
||||
});
|
||||
describe('#isUri', () => {
|
||||
@@ -302,9 +205,7 @@ describe('Assertions', () => {
|
||||
'wss://www.api.example-relayer.net',
|
||||
'user:password@api.example-relayer.net',
|
||||
];
|
||||
validInputs.forEach(input =>
|
||||
expect(assert.isUri.bind(assert, variableName, input)).to.not.throw(),
|
||||
);
|
||||
validInputs.forEach(input => expect(assert.isUri.bind(assert, variableName, input)).to.not.throw());
|
||||
});
|
||||
it('should throw for invalid input', () => {
|
||||
const invalidInputs = [
|
||||
@@ -316,9 +217,7 @@ describe('Assertions', () => {
|
||||
'api.example-relayer.net',
|
||||
'//api.example-relayer.net',
|
||||
];
|
||||
invalidInputs.forEach(input =>
|
||||
expect(assert.isUri.bind(assert, variableName, input)).to.throw(),
|
||||
);
|
||||
invalidInputs.forEach(input => expect(assert.isUri.bind(assert, variableName, input)).to.throw());
|
||||
});
|
||||
});
|
||||
describe('#assert', () => {
|
||||
@@ -332,8 +231,9 @@ describe('Assertions', () => {
|
||||
});
|
||||
describe('#typeAssertionMessage', () => {
|
||||
it('should render correct message', () => {
|
||||
expect(assert.typeAssertionMessage('variable', 'string', 'number'))
|
||||
.to.equal(`Expected variable to be of type string, encountered: number`);
|
||||
expect(assert.typeAssertionMessage('variable', 'string', 'number')).to.equal(
|
||||
`Expected variable to be of type string, encountered: number`,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -1,18 +1,7 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"lib": [ "es2017", "dom"],
|
||||
"outDir": "lib",
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": true
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*",
|
||||
"./test/**/*",
|
||||
"../../node_modules/chai-typescript-typings/index.d.ts",
|
||||
"../../node_modules/web3-typescript-typings/index.d.ts"
|
||||
]
|
||||
"include": ["./src/**/*", "./test/**/*", "../../node_modules/chai-typescript-typings/index.d.ts"]
|
||||
}
|
||||
|
@@ -1,5 +1,3 @@
|
||||
{
|
||||
"extends": [
|
||||
"@0xproject/tslint-config"
|
||||
]
|
||||
"extends": ["@0xproject/tslint-config"]
|
||||
}
|
||||
|
@@ -0,0 +1,3 @@
|
||||
# CHANGELOG
|
||||
|
||||
## v0.x.x - _TBD, 2018_
|
43
packages/chai-as-promised-typescript-typings/README.md
Normal file
43
packages/chai-as-promised-typescript-typings/README.md
Normal file
@@ -0,0 +1,43 @@
|
||||
## chai-as-promised-typescript-typings
|
||||
|
||||
Fork of type definitions for chai-as-promised that includes changes made by dirty-chai
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
yarn add -D chai-as-promised-typescript-typings
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Add the following line within an `include` section of your `tsconfig.json`
|
||||
|
||||
```json
|
||||
"./node_modules/chai-as-promised-typescript-typings/index.d.ts"
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
We strongly encourage that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
|
||||
|
||||
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
|
||||
|
||||
### Install Dependencies
|
||||
|
||||
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
|
||||
|
||||
```bash
|
||||
yarn config set workspaces-experimental true
|
||||
```
|
||||
|
||||
Then install dependencies
|
||||
|
||||
```bash
|
||||
yarn install
|
||||
```
|
||||
|
||||
### Lint
|
||||
|
||||
```bash
|
||||
yarn lint
|
||||
```
|
268
packages/chai-as-promised-typescript-typings/index.d.ts
vendored
Normal file
268
packages/chai-as-promised-typescript-typings/index.d.ts
vendored
Normal file
@@ -0,0 +1,268 @@
|
||||
// Type definitions for chai-as-promised
|
||||
// Project: https://github.com/domenic/chai-as-promised/
|
||||
// Definitions by: jt000 <https://github.com/jt000>, Yuki Kokubun <https://github.com/Kuniwak>
|
||||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
||||
|
||||
declare module 'chai-as-promised' {
|
||||
function chaiAsPromised(chai: any, utils: any): void;
|
||||
namespace chaiAsPromised {
|
||||
|
||||
}
|
||||
export = chaiAsPromised;
|
||||
}
|
||||
|
||||
// tslint:disable:no-namespace ban-types member-ordering
|
||||
declare namespace Chai {
|
||||
// For BDD API
|
||||
interface Assertion extends LanguageChains, NumericComparison, TypeComparison {
|
||||
eventually: PromisedAssertion;
|
||||
fulfilled: PromisedAssertion;
|
||||
become(expected: any): PromisedAssertion;
|
||||
rejected(): PromisedAssertion;
|
||||
rejectedWith(expected: any, message?: string | RegExp): PromisedAssertion;
|
||||
notify(fn: Function): PromisedAssertion;
|
||||
}
|
||||
|
||||
// Eventually does not have .then(), but PromisedAssertion have.
|
||||
interface Eventually extends PromisedLanguageChains, PromisedNumericComparison, PromisedTypeComparison {
|
||||
// From chai-as-promised
|
||||
become(expected: PromiseLike<any>): PromisedAssertion;
|
||||
fulfilled: PromisedAssertion;
|
||||
rejected: () => PromisedAssertion;
|
||||
rejectedWith(expected: any, message?: string | RegExp): PromisedAssertion;
|
||||
notify(fn: Function): PromisedAssertion;
|
||||
|
||||
// From chai
|
||||
not: PromisedAssertion;
|
||||
deep: PromisedDeep;
|
||||
all: PromisedKeyFilter;
|
||||
a: PromisedTypeComparison;
|
||||
an: PromisedTypeComparison;
|
||||
include: PromisedInclude;
|
||||
contain: PromisedInclude;
|
||||
ok: PromisedAssertion;
|
||||
true: () => PromisedAssertion;
|
||||
false: () => PromisedAssertion;
|
||||
null: PromisedAssertion;
|
||||
undefined: PromisedAssertion;
|
||||
exist: PromisedAssertion;
|
||||
empty: PromisedAssertion;
|
||||
arguments: PromisedAssertion;
|
||||
Arguments: PromisedAssertion;
|
||||
equal: PromisedEqual;
|
||||
equals: PromisedEqual;
|
||||
eq: PromisedEqual;
|
||||
eql: PromisedEqual;
|
||||
eqls: PromisedEqual;
|
||||
property: PromisedProperty;
|
||||
ownProperty: PromisedOwnProperty;
|
||||
haveOwnProperty: PromisedOwnProperty;
|
||||
length: PromisedLength;
|
||||
lengthOf: PromisedLength;
|
||||
match(regexp: RegExp | string, message?: string): PromisedAssertion;
|
||||
string(string: string, message?: string): PromisedAssertion;
|
||||
keys: PromisedKeys;
|
||||
key(string: string): PromisedAssertion;
|
||||
throw: PromisedThrow;
|
||||
throws: PromisedThrow;
|
||||
Throw: PromisedThrow;
|
||||
respondTo(method: string, message?: string): PromisedAssertion;
|
||||
itself: PromisedAssertion;
|
||||
satisfy(matcher: Function, message?: string): PromisedAssertion;
|
||||
closeTo(expected: number, delta: number, message?: string): PromisedAssertion;
|
||||
members: PromisedMembers;
|
||||
}
|
||||
|
||||
interface PromisedAssertion extends Eventually, PromiseLike<any> {}
|
||||
|
||||
interface PromisedLanguageChains {
|
||||
eventually: Eventually;
|
||||
|
||||
// From chai
|
||||
to: PromisedAssertion;
|
||||
be: PromisedAssertion;
|
||||
been: PromisedAssertion;
|
||||
is: PromisedAssertion;
|
||||
that: PromisedAssertion;
|
||||
which: PromisedAssertion;
|
||||
and: PromisedAssertion;
|
||||
has: PromisedAssertion;
|
||||
have: PromisedAssertion;
|
||||
with: PromisedAssertion;
|
||||
at: PromisedAssertion;
|
||||
of: PromisedAssertion;
|
||||
same: PromisedAssertion;
|
||||
}
|
||||
|
||||
interface PromisedNumericComparison {
|
||||
above: PromisedNumberComparer;
|
||||
gt: PromisedNumberComparer;
|
||||
greaterThan: PromisedNumberComparer;
|
||||
least: PromisedNumberComparer;
|
||||
gte: PromisedNumberComparer;
|
||||
below: PromisedNumberComparer;
|
||||
lt: PromisedNumberComparer;
|
||||
lessThan: PromisedNumberComparer;
|
||||
most: PromisedNumberComparer;
|
||||
lte: PromisedNumberComparer;
|
||||
within(start: number, finish: number, message?: string): PromisedAssertion;
|
||||
}
|
||||
|
||||
type PromisedNumberComparer = (value: number, message?: string) => PromisedAssertion;
|
||||
|
||||
interface PromisedTypeComparison {
|
||||
(type: string, message?: string): PromisedAssertion;
|
||||
instanceof: PromisedInstanceOf;
|
||||
instanceOf: PromisedInstanceOf;
|
||||
}
|
||||
|
||||
type PromisedInstanceOf = (constructor: Object, message?: string) => PromisedAssertion;
|
||||
|
||||
interface PromisedDeep {
|
||||
equal: PromisedEqual;
|
||||
include: PromisedInclude;
|
||||
property: PromisedProperty;
|
||||
}
|
||||
|
||||
interface PromisedKeyFilter {
|
||||
keys: PromisedKeys;
|
||||
}
|
||||
|
||||
type PromisedEqual = (value: any, message?: string) => PromisedAssertion;
|
||||
|
||||
type PromisedProperty = (name: string, value?: any, message?: string) => PromisedAssertion;
|
||||
|
||||
type PromisedOwnProperty = (name: string, message?: string) => PromisedAssertion;
|
||||
|
||||
interface PromisedLength extends PromisedLanguageChains, PromisedNumericComparison {
|
||||
(length: number, message?: string): PromisedAssertion;
|
||||
}
|
||||
|
||||
interface PromisedInclude {
|
||||
(value: Object | string | number, message?: string): PromisedAssertion;
|
||||
keys: PromisedKeys;
|
||||
members: PromisedMembers;
|
||||
all: PromisedKeyFilter;
|
||||
}
|
||||
|
||||
interface PromisedKeys {
|
||||
(...keys: string[]): PromisedAssertion;
|
||||
(keys: any[]): PromisedAssertion;
|
||||
}
|
||||
|
||||
interface PromisedThrow {
|
||||
(): PromisedAssertion;
|
||||
(expected: string | RegExp, message?: string): PromisedAssertion;
|
||||
(constructor: Error | Function, expected?: string | RegExp, message?: string): PromisedAssertion;
|
||||
}
|
||||
|
||||
type PromisedMembers = (set: any[], message?: string) => PromisedAssertion;
|
||||
|
||||
// For Assert API
|
||||
interface Assert {
|
||||
eventually: PromisedAssert;
|
||||
isFulfilled(promise: PromiseLike<any>, message?: string): PromiseLike<void>;
|
||||
becomes(promise: PromiseLike<any>, expected: any, message?: string): PromiseLike<void>;
|
||||
doesNotBecome(promise: PromiseLike<any>, expected: any, message?: string): PromiseLike<void>;
|
||||
isRejected(promise: PromiseLike<any>, message?: string): PromiseLike<void>;
|
||||
isRejected(promise: PromiseLike<any>, expected: any | RegExp, message?: string): PromiseLike<void>;
|
||||
notify(fn: Function): PromiseLike<void>;
|
||||
}
|
||||
|
||||
export interface PromisedAssert {
|
||||
fail(actual?: any, expected?: any, msg?: string, operator?: string): PromiseLike<void>;
|
||||
|
||||
ok(val: any, msg?: string): PromiseLike<void>;
|
||||
notOk(val: any, msg?: string): PromiseLike<void>;
|
||||
|
||||
equal(act: any, exp: any, msg?: string): PromiseLike<void>;
|
||||
notEqual(act: any, exp: any, msg?: string): PromiseLike<void>;
|
||||
|
||||
strictEqual(act: any, exp: any, msg?: string): PromiseLike<void>;
|
||||
notStrictEqual(act: any, exp: any, msg?: string): PromiseLike<void>;
|
||||
|
||||
deepEqual(act: any, exp: any, msg?: string): PromiseLike<void>;
|
||||
notDeepEqual(act: any, exp: any, msg?: string): PromiseLike<void>;
|
||||
|
||||
isTrue(val: any, msg?: string): PromiseLike<void>;
|
||||
isFalse(val: any, msg?: string): PromiseLike<void>;
|
||||
|
||||
isNull(val: any, msg?: string): PromiseLike<void>;
|
||||
isNotNull(val: any, msg?: string): PromiseLike<void>;
|
||||
|
||||
isUndefined(val: any, msg?: string): PromiseLike<void>;
|
||||
isDefined(val: any, msg?: string): PromiseLike<void>;
|
||||
|
||||
isFunction(val: any, msg?: string): PromiseLike<void>;
|
||||
isNotFunction(val: any, msg?: string): PromiseLike<void>;
|
||||
|
||||
isObject(val: any, msg?: string): PromiseLike<void>;
|
||||
isNotObject(val: any, msg?: string): PromiseLike<void>;
|
||||
|
||||
isArray(val: any, msg?: string): PromiseLike<void>;
|
||||
isNotArray(val: any, msg?: string): PromiseLike<void>;
|
||||
|
||||
isString(val: any, msg?: string): PromiseLike<void>;
|
||||
isNotString(val: any, msg?: string): PromiseLike<void>;
|
||||
|
||||
isNumber(val: any, msg?: string): PromiseLike<void>;
|
||||
isNotNumber(val: any, msg?: string): PromiseLike<void>;
|
||||
|
||||
isBoolean(val: any, msg?: string): PromiseLike<void>;
|
||||
isNotBoolean(val: any, msg?: string): PromiseLike<void>;
|
||||
|
||||
typeOf(val: any, type: string, msg?: string): PromiseLike<void>;
|
||||
notTypeOf(val: any, type: string, msg?: string): PromiseLike<void>;
|
||||
|
||||
instanceOf(val: any, type: Function, msg?: string): PromiseLike<void>;
|
||||
notInstanceOf(val: any, type: Function, msg?: string): PromiseLike<void>;
|
||||
|
||||
include(exp: string | any[], inc: any, msg?: string): PromiseLike<void>;
|
||||
|
||||
notInclude(exp: string | any[], inc: any, msg?: string): PromiseLike<void>;
|
||||
|
||||
match(exp: any, re: RegExp, msg?: string): PromiseLike<void>;
|
||||
notMatch(exp: any, re: RegExp, msg?: string): PromiseLike<void>;
|
||||
|
||||
property(obj: Object, prop: string, msg?: string): PromiseLike<void>;
|
||||
notProperty(obj: Object, prop: string, msg?: string): PromiseLike<void>;
|
||||
deepProperty(obj: Object, prop: string, msg?: string): PromiseLike<void>;
|
||||
notDeepProperty(obj: Object, prop: string, msg?: string): PromiseLike<void>;
|
||||
|
||||
propertyVal(obj: Object, prop: string, val: any, msg?: string): PromiseLike<void>;
|
||||
propertyNotVal(obj: Object, prop: string, val: any, msg?: string): PromiseLike<void>;
|
||||
|
||||
deepPropertyVal(obj: Object, prop: string, val: any, msg?: string): PromiseLike<void>;
|
||||
deepPropertyNotVal(obj: Object, prop: string, val: any, msg?: string): PromiseLike<void>;
|
||||
|
||||
lengthOf(exp: any, len: number, msg?: string): PromiseLike<void>;
|
||||
// alias frenzy
|
||||
throw(fn: Function, msg?: string): PromiseLike<void>;
|
||||
throw(fn: Function, regExp: RegExp): PromiseLike<void>;
|
||||
throw(fn: Function, errType: Function, msg?: string): PromiseLike<void>;
|
||||
throw(fn: Function, errType: Function, regExp: RegExp): PromiseLike<void>;
|
||||
|
||||
throws(fn: Function, msg?: string): PromiseLike<void>;
|
||||
throws(fn: Function, regExp: RegExp): PromiseLike<void>;
|
||||
throws(fn: Function, errType: Function, msg?: string): PromiseLike<void>;
|
||||
throws(fn: Function, errType: Function, regExp: RegExp): PromiseLike<void>;
|
||||
|
||||
Throw(fn: Function, msg?: string): PromiseLike<void>;
|
||||
Throw(fn: Function, regExp: RegExp): PromiseLike<void>;
|
||||
Throw(fn: Function, errType: Function, msg?: string): PromiseLike<void>;
|
||||
Throw(fn: Function, errType: Function, regExp: RegExp): PromiseLike<void>;
|
||||
|
||||
doesNotThrow(fn: Function, msg?: string): PromiseLike<void>;
|
||||
doesNotThrow(fn: Function, regExp: RegExp): PromiseLike<void>;
|
||||
doesNotThrow(fn: Function, errType: Function, msg?: string): PromiseLike<void>;
|
||||
doesNotThrow(fn: Function, errType: Function, regExp: RegExp): PromiseLike<void>;
|
||||
|
||||
operator(val: any, operator: string, val2: any, msg?: string): PromiseLike<void>;
|
||||
closeTo(act: number, exp: number, delta: number, msg?: string): PromiseLike<void>;
|
||||
|
||||
sameMembers(set1: any[], set2: any[], msg?: string): PromiseLike<void>;
|
||||
includeMembers(set1: any[], set2: any[], msg?: string): PromiseLike<void>;
|
||||
|
||||
ifError(val: any, msg?: string): PromiseLike<void>;
|
||||
}
|
||||
}
|
21
packages/chai-as-promised-typescript-typings/package.json
Normal file
21
packages/chai-as-promised-typescript-typings/package.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "chai-as-promised-typescript-typings",
|
||||
"version": "0.0.3",
|
||||
"description": "Typescript type definitions for chai-as-promised",
|
||||
"main": "index.d.ts",
|
||||
"types": "index.d.ts",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/0xProject/0x.js.git"
|
||||
},
|
||||
"author": "Fabio Berger",
|
||||
"contributors": ["Leonid Logvinov <logvinov.leon@gmail.com>"],
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/0xProject/0x.js/issues"
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x.js/packages/chai-as-promised-typescript-typings#readme",
|
||||
"dependencies": {
|
||||
"chai-typescript-typings": "^0.0.0"
|
||||
}
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
const postpublish_utils = require('../../../scripts/postpublish_utils');
|
||||
const packageJSON = require('../package.json');
|
||||
|
||||
const subPackageName = packageJSON.name;
|
||||
|
||||
postpublish_utils
|
||||
.getLatestTagAndVersionAsync(subPackageName)
|
||||
.then(function(result) {
|
||||
const releaseName = postpublish_utils.getReleaseName(subPackageName, result.version);
|
||||
const assets = [];
|
||||
return postpublish_utils.publishReleaseNotes(result.tag, releaseName, assets);
|
||||
})
|
||||
.catch(function(err) {
|
||||
throw err;
|
||||
});
|
3
packages/chai-as-promised-typescript-typings/tslint.json
Normal file
3
packages/chai-as-promised-typescript-typings/tslint.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": ["tslint-config-0xproject"]
|
||||
}
|
3
packages/chai-typescript-typings/CHANGELOG.md
Normal file
3
packages/chai-typescript-typings/CHANGELOG.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# CHANGELOG
|
||||
|
||||
## v0.x.x - _TBD, 2018_
|
43
packages/chai-typescript-typings/README.md
Normal file
43
packages/chai-typescript-typings/README.md
Normal file
@@ -0,0 +1,43 @@
|
||||
## chai-typescript-typings
|
||||
|
||||
Fork of type definitions for chai that includes changes made by dirty-chai
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
yarn add -D chai-typescript-typings
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Add the following line within an `include` section of your `tsconfig.json`
|
||||
|
||||
```json
|
||||
"./node_modules/chai-typescript-typings/index.d.ts"
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
We strongly encourage that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
|
||||
|
||||
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
|
||||
|
||||
### Install Dependencies
|
||||
|
||||
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
|
||||
|
||||
```bash
|
||||
yarn config set workspaces-experimental true
|
||||
```
|
||||
|
||||
Then install dependencies
|
||||
|
||||
```bash
|
||||
yarn install
|
||||
```
|
||||
|
||||
### Lint
|
||||
|
||||
```bash
|
||||
yarn lint
|
||||
```
|
1254
packages/chai-typescript-typings/index.d.ts
vendored
Normal file
1254
packages/chai-typescript-typings/index.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
16
packages/chai-typescript-typings/package.json
Normal file
16
packages/chai-typescript-typings/package.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "chai-typescript-typings",
|
||||
"version": "0.0.1",
|
||||
"description": "Typescript type definitions for chai",
|
||||
"main": "index.d.ts",
|
||||
"types": "index.d.ts",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/0xProject/0x.js.git"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/0xProject/0x.js/issues"
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x.js/packages/chai-typescript-typings#readme"
|
||||
}
|
15
packages/chai-typescript-typings/scripts/postpublish.js
Normal file
15
packages/chai-typescript-typings/scripts/postpublish.js
Normal file
@@ -0,0 +1,15 @@
|
||||
const postpublish_utils = require('../../../scripts/postpublish_utils');
|
||||
const packageJSON = require('../package.json');
|
||||
|
||||
const subPackageName = packageJSON.name;
|
||||
|
||||
postpublish_utils
|
||||
.getLatestTagAndVersionAsync(subPackageName)
|
||||
.then(function(result) {
|
||||
const releaseName = postpublish_utils.getReleaseName(subPackageName, result.version);
|
||||
const assets = [];
|
||||
return postpublish_utils.publishReleaseNotes(result.tag, releaseName, assets);
|
||||
})
|
||||
.catch(function(err) {
|
||||
throw err;
|
||||
});
|
3
packages/chai-typescript-typings/tslint.json
Normal file
3
packages/chai-typescript-typings/tslint.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": ["tslint-config-0xproject"]
|
||||
}
|
@@ -1,16 +1,26 @@
|
||||
# CHANGELOG
|
||||
|
||||
v0.3.0 - _December 8, 2017_
|
||||
------------------------
|
||||
## v0.5.0 - _January 17, 2018_
|
||||
|
||||
* Sanitize api endpoint url and remove trailing slashes (#318)
|
||||
* Improve error message text in HttpClient (#318)
|
||||
* Stop appending '/v0' to api endpoint url in HttpClient (#318)
|
||||
|
||||
## v0.4.0 - _January 11, 2018_
|
||||
|
||||
* Prevent getFeesAsync method on HttpClient from mutating input (#296)
|
||||
|
||||
## v0.3.0 - _December 8, 2017_
|
||||
|
||||
* Expose WebSocketOrderbookChannel and associated types to public interface (#251)
|
||||
* Remove tokenA and tokenB fields from OrdersRequest (#256)
|
||||
|
||||
v0.2.0 - _November 29, 2017_
|
||||
------------------------
|
||||
## v0.2.0 - _November 29, 2017_
|
||||
|
||||
* Add SignedOrder and TokenTradeInfo to the public interface
|
||||
* Add ECSignature and Order to the public interface
|
||||
* Remove dependency on 0x.js
|
||||
|
||||
v0.1.0 - _November 22, 2017_
|
||||
------------------------
|
||||
## v0.1.0 - _November 22, 2017_
|
||||
|
||||
* Provide a HttpClient class for interacting with standard relayer api compliant HTTP urls
|
||||
|
@@ -1,5 +1,4 @@
|
||||
@0xproject/connect
|
||||
------
|
||||
## @0xproject/connect
|
||||
|
||||
This repository contains a Javascript library that makes it easy to interact with Relayers that conform to the [Standard Relayer API](https://github.com/0xProject/standard-relayer-api)
|
||||
|
||||
@@ -23,11 +22,13 @@ Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting
|
||||
### 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
|
||||
```
|
||||
|
@@ -1,21 +1,16 @@
|
||||
{
|
||||
"name": "@0xproject/connect",
|
||||
"version": "0.3.0",
|
||||
"version": "0.4.1",
|
||||
"description": "A javascript library for interacting with the standard relayer api",
|
||||
"keywords": [
|
||||
"connect",
|
||||
"0xproject",
|
||||
"ethereum",
|
||||
"tokens",
|
||||
"exchange"
|
||||
],
|
||||
"keywords": ["connect", "0xproject", "ethereum", "tokens", "exchange"],
|
||||
"main": "lib/src/index.js",
|
||||
"types": "lib/src/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"clean": "shx rm -rf _bundles lib test_temp",
|
||||
"docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_DIR",
|
||||
"upload_docs_json": "aws s3 cp generated_docs/index.json $S3_URL --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type application/json",
|
||||
"upload_docs_json":
|
||||
"aws s3 cp generated_docs/index.json $S3_URL --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type application/json",
|
||||
"copy_test_fixtures": "copyfiles -u 2 './test/fixtures/**/*.json' ./lib/test/fixtures",
|
||||
"lint": "tslint --project . 'src/**/*.ts' 'test/**/*.ts'",
|
||||
"run_mocha": "mocha lib/test/**/*_test.js",
|
||||
@@ -36,16 +31,16 @@
|
||||
},
|
||||
"homepage": "https://github.com/0xProject/0x.js/packages/connect/README.md",
|
||||
"dependencies": {
|
||||
"@0xproject/assert": "^0.0.7",
|
||||
"@0xproject/json-schemas": "^0.6.10",
|
||||
"bignumber.js": "~4.1.0",
|
||||
"@0xproject/assert": "^0.0.10",
|
||||
"@0xproject/json-schemas": "^0.7.2",
|
||||
"@0xproject/utils": "^0.1.3",
|
||||
"isomorphic-fetch": "^2.2.1",
|
||||
"lodash": "^4.17.4",
|
||||
"query-string": "^5.0.1",
|
||||
"websocket": "^1.0.25"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0xproject/tslint-config": "^0.2.1",
|
||||
"@0xproject/tslint-config": "^0.4.1",
|
||||
"@types/fetch-mock": "^5.12.1",
|
||||
"@types/lodash": "^4.14.86",
|
||||
"@types/mocha": "^2.2.42",
|
||||
@@ -64,6 +59,6 @@
|
||||
"tslint": "5.8.0",
|
||||
"typedoc": "~0.8.0",
|
||||
"typescript": "~2.6.1",
|
||||
"web3-typescript-typings": "^0.7.2"
|
||||
"web3-typescript-typings": "^0.9.3"
|
||||
}
|
||||
}
|
||||
|
@@ -8,7 +8,8 @@ const S3BucketPath = 's3://connect-docs-jsons/';
|
||||
|
||||
let tag;
|
||||
let version;
|
||||
postpublish_utils.getLatestTagAndVersionAsync(subPackageName)
|
||||
postpublish_utils
|
||||
.getLatestTagAndVersionAsync(subPackageName)
|
||||
.then(function(result) {
|
||||
tag = result.tag;
|
||||
version = result.version;
|
||||
@@ -18,12 +19,9 @@ postpublish_utils.getLatestTagAndVersionAsync(subPackageName)
|
||||
.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',
|
||||
{
|
||||
return execAsync('JSON_FILE_PATH=' + jsonFilePath + ' PROJECT_DIR=' + __dirname + '/.. yarn docs:json', {
|
||||
cwd,
|
||||
}
|
||||
);
|
||||
});
|
||||
})
|
||||
.then(function(result) {
|
||||
if (result.stderr !== '') {
|
||||
@@ -35,6 +33,7 @@ postpublish_utils.getLatestTagAndVersionAsync(subPackageName)
|
||||
return execAsync('S3_URL=' + s3Url + ' yarn upload_docs_json', {
|
||||
cwd,
|
||||
});
|
||||
}).catch (function(err) {
|
||||
})
|
||||
.catch(function(err) {
|
||||
throw err;
|
||||
});
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import { assert } from '@0xproject/assert';
|
||||
import { schemas } from '@0xproject/json-schemas';
|
||||
import {BigNumber} from 'bignumber.js';
|
||||
import 'isomorphic-fetch';
|
||||
import * as _ from 'lodash';
|
||||
import * as queryString from 'query-string';
|
||||
@@ -19,19 +18,15 @@ import {
|
||||
TokenPairsItem,
|
||||
TokenPairsRequest,
|
||||
} from './types';
|
||||
import {typeConverters} from './utils/type_converters';
|
||||
|
||||
// TODO: move this and bigNumberConfigs in the 0x.js package into one place
|
||||
BigNumber.config({
|
||||
EXPONENTIAL_AT: 1000,
|
||||
});
|
||||
import { relayerResponseJsonParsers } from './utils/relayer_response_json_parsers';
|
||||
|
||||
const TRAILING_SLASHES_REGEX = /\/+$/;
|
||||
/**
|
||||
* This class includes all the functionality related to interacting with a set of HTTP endpoints
|
||||
* that implement the standard relayer API v0
|
||||
*/
|
||||
export class HttpClient implements Client {
|
||||
private apiEndpointUrl: string;
|
||||
private _apiEndpointUrl: string;
|
||||
/**
|
||||
* Instantiates a new HttpClient instance
|
||||
* @param url The relayer API base HTTP url you would like to interact with
|
||||
@@ -39,7 +34,7 @@ export class HttpClient implements Client {
|
||||
*/
|
||||
constructor(url: string) {
|
||||
assert.isHttpUrl('url', url);
|
||||
this.apiEndpointUrl = url;
|
||||
this._apiEndpointUrl = url.replace(TRAILING_SLASHES_REGEX, ''); // remove trailing slashes
|
||||
}
|
||||
/**
|
||||
* Retrieve token pair info from the API
|
||||
@@ -54,17 +49,8 @@ export class HttpClient implements Client {
|
||||
const requestOpts = {
|
||||
params: request,
|
||||
};
|
||||
const tokenPairs = await this._requestAsync('/token_pairs', HttpRequestType.Get, requestOpts);
|
||||
assert.doesConformToSchema(
|
||||
'tokenPairs', tokenPairs, schemas.relayerApiTokenPairsResponseSchema);
|
||||
_.each(tokenPairs, (tokenPair: object) => {
|
||||
typeConverters.convertStringsFieldsToBigNumbers(tokenPair, [
|
||||
'tokenA.minAmount',
|
||||
'tokenA.maxAmount',
|
||||
'tokenB.minAmount',
|
||||
'tokenB.maxAmount',
|
||||
]);
|
||||
});
|
||||
const responseJson = await this._requestAsync('/token_pairs', HttpRequestType.Get, requestOpts);
|
||||
const tokenPairs = relayerResponseJsonParsers.parseTokenPairsJson(responseJson);
|
||||
return tokenPairs;
|
||||
}
|
||||
/**
|
||||
@@ -79,9 +65,8 @@ export class HttpClient implements Client {
|
||||
const requestOpts = {
|
||||
params: request,
|
||||
};
|
||||
const orders = await this._requestAsync(`/orders`, HttpRequestType.Get, requestOpts);
|
||||
assert.doesConformToSchema('orders', orders, schemas.signedOrdersSchema);
|
||||
_.each(orders, (order: object) => typeConverters.convertOrderStringFieldsToBigNumber(order));
|
||||
const responseJson = await this._requestAsync(`/orders`, HttpRequestType.Get, requestOpts);
|
||||
const orders = relayerResponseJsonParsers.parseOrdersJson(responseJson);
|
||||
return orders;
|
||||
}
|
||||
/**
|
||||
@@ -91,9 +76,8 @@ export class HttpClient implements Client {
|
||||
*/
|
||||
public async getOrderAsync(orderHash: string): Promise<SignedOrder> {
|
||||
assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
|
||||
const order = await this._requestAsync(`/order/${orderHash}`, HttpRequestType.Get);
|
||||
assert.doesConformToSchema('order', order, schemas.signedOrderSchema);
|
||||
typeConverters.convertOrderStringFieldsToBigNumber(order);
|
||||
const responseJson = await this._requestAsync(`/order/${orderHash}`, HttpRequestType.Get);
|
||||
const order = relayerResponseJsonParsers.parseOrderJson(responseJson);
|
||||
return order;
|
||||
}
|
||||
/**
|
||||
@@ -106,10 +90,9 @@ export class HttpClient implements Client {
|
||||
const requestOpts = {
|
||||
params: request,
|
||||
};
|
||||
const orderBook = await this._requestAsync('/orderbook', HttpRequestType.Get, requestOpts);
|
||||
assert.doesConformToSchema('orderBook', orderBook, schemas.relayerApiOrderBookResponseSchema);
|
||||
typeConverters.convertOrderbookStringFieldsToBigNumber(orderBook);
|
||||
return orderBook;
|
||||
const responseJson = await this._requestAsync('/orderbook', HttpRequestType.Get, requestOpts);
|
||||
const orderbook = relayerResponseJsonParsers.parseOrderbookResponseJson(responseJson);
|
||||
return orderbook;
|
||||
}
|
||||
/**
|
||||
* Retrieve fee information from the API
|
||||
@@ -118,18 +101,11 @@ export class HttpClient implements Client {
|
||||
*/
|
||||
public async getFeesAsync(request: FeesRequest): Promise<FeesResponse> {
|
||||
assert.doesConformToSchema('request', request, schemas.relayerApiFeesPayloadSchema);
|
||||
typeConverters.convertBigNumberFieldsToStrings(request, [
|
||||
'makerTokenAmount',
|
||||
'takerTokenAmount',
|
||||
'expirationUnixTimestampSec',
|
||||
'salt',
|
||||
]);
|
||||
const requestOpts = {
|
||||
payload: request,
|
||||
};
|
||||
const fees = await this._requestAsync('/fees', HttpRequestType.Post, requestOpts);
|
||||
assert.doesConformToSchema('fees', fees, schemas.relayerApiFeesResponseSchema);
|
||||
typeConverters.convertStringsFieldsToBigNumbers(fees, ['makerFee', 'takerFee']);
|
||||
const responseJson = await this._requestAsync('/fees', HttpRequestType.Post, requestOpts);
|
||||
const fees = relayerResponseJsonParsers.parseFeesResponseJson(responseJson);
|
||||
return fees;
|
||||
}
|
||||
/**
|
||||
@@ -143,8 +119,11 @@ export class HttpClient implements Client {
|
||||
};
|
||||
await this._requestAsync('/order', HttpRequestType.Post, requestOpts);
|
||||
}
|
||||
private async _requestAsync(path: string, requestType: HttpRequestType,
|
||||
requestOptions?: HttpRequestOptions): Promise<any> {
|
||||
private async _requestAsync(
|
||||
path: string,
|
||||
requestType: HttpRequestType,
|
||||
requestOptions?: HttpRequestOptions,
|
||||
): Promise<any> {
|
||||
const params = _.get(requestOptions, 'params');
|
||||
const payload = _.get(requestOptions, 'payload');
|
||||
let query = '';
|
||||
@@ -152,20 +131,22 @@ export class HttpClient implements Client {
|
||||
const stringifiedParams = queryString.stringify(params);
|
||||
query = `?${stringifiedParams}`;
|
||||
}
|
||||
const url = `${this.apiEndpointUrl}/v0${path}${query}`;
|
||||
const url = `${this._apiEndpointUrl}${path}${query}`;
|
||||
const headers = new Headers({
|
||||
'content-type': 'application/json',
|
||||
});
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: requestType,
|
||||
body: JSON.stringify(payload),
|
||||
headers,
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw Error(response.statusText);
|
||||
}
|
||||
const json = await response.json();
|
||||
if (!response.ok) {
|
||||
const errorString = `${response.status} - ${response.statusText}\n${requestType} ${url}\n${JSON.stringify(
|
||||
json,
|
||||
)}`;
|
||||
throw Error(errorString);
|
||||
}
|
||||
return json;
|
||||
}
|
||||
}
|
||||
|
@@ -1,12 +1,6 @@
|
||||
import {
|
||||
relayerOrderBookRequestSchema,
|
||||
} from './relayer_orderbook_request_schema';
|
||||
import {
|
||||
relayerOrdersRequestSchema,
|
||||
} from './relayer_orders_request_schema';
|
||||
import {
|
||||
relayerTokenPairsRequestSchema,
|
||||
} from './relayer_token_pairs_request_schema';
|
||||
import { relayerOrderBookRequestSchema } from './relayer_orderbook_request_schema';
|
||||
import { relayerOrdersRequestSchema } from './relayer_orders_request_schema';
|
||||
import { relayerTokenPairsRequestSchema } from './relayer_token_pairs_request_schema';
|
||||
|
||||
export const schemas = {
|
||||
relayerOrderBookRequestSchema,
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import {BigNumber} from 'bignumber.js';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
|
||||
// TODO: Consolidate Order, SignedOrder and ECSignature into a shared package instead of duplicating them from 0x.js
|
||||
export interface Order {
|
||||
@@ -57,19 +57,24 @@ export interface OrderbookChannelSubscriptionOpts {
|
||||
}
|
||||
|
||||
export interface OrderbookChannelHandler {
|
||||
onSnapshot: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts,
|
||||
snapshot: OrderbookResponse) => void;
|
||||
onUpdate: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts,
|
||||
order: SignedOrder) => void;
|
||||
onError: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts,
|
||||
err: Error) => void;
|
||||
onSnapshot: (
|
||||
channel: OrderbookChannel,
|
||||
subscriptionOpts: OrderbookChannelSubscriptionOpts,
|
||||
snapshot: OrderbookResponse,
|
||||
) => void;
|
||||
onUpdate: (
|
||||
channel: OrderbookChannel,
|
||||
subscriptionOpts: OrderbookChannelSubscriptionOpts,
|
||||
order: SignedOrder,
|
||||
) => void;
|
||||
onError: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts, err: Error) => void;
|
||||
onClose: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts) => void;
|
||||
}
|
||||
|
||||
export type OrderbookChannelMessage =
|
||||
SnapshotOrderbookChannelMessage |
|
||||
UpdateOrderbookChannelMessage |
|
||||
UnknownOrderbookChannelMessage;
|
||||
| SnapshotOrderbookChannelMessage
|
||||
| UpdateOrderbookChannelMessage
|
||||
| UnknownOrderbookChannelMessage;
|
||||
|
||||
export enum OrderbookChannelMessageTypes {
|
||||
Snapshot = 'snapshot',
|
||||
|
@@ -0,0 +1,37 @@
|
||||
import { assert } from '@0xproject/assert';
|
||||
import { schemas } from '@0xproject/json-schemas';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { OrderbookChannelMessage, OrderbookChannelMessageTypes } from '../types';
|
||||
|
||||
import { relayerResponseJsonParsers } from './relayer_response_json_parsers';
|
||||
|
||||
export const orderbookChannelMessageParser = {
|
||||
parse(utf8Data: string): OrderbookChannelMessage {
|
||||
const messageObj = JSON.parse(utf8Data);
|
||||
const type: string = _.get(messageObj, 'type');
|
||||
assert.assert(!_.isUndefined(type), `Message is missing a type parameter: ${utf8Data}`);
|
||||
assert.isString('type', type);
|
||||
switch (type) {
|
||||
case OrderbookChannelMessageTypes.Snapshot: {
|
||||
assert.doesConformToSchema('message', messageObj, schemas.relayerApiOrderbookChannelSnapshotSchema);
|
||||
const orderbookJson = messageObj.payload;
|
||||
const orderbook = relayerResponseJsonParsers.parseOrderbookResponseJson(orderbookJson);
|
||||
return _.assign(messageObj, { payload: orderbook });
|
||||
}
|
||||
case OrderbookChannelMessageTypes.Update: {
|
||||
assert.doesConformToSchema('message', messageObj, schemas.relayerApiOrderbookChannelUpdateSchema);
|
||||
const orderJson = messageObj.payload;
|
||||
const order = relayerResponseJsonParsers.parseOrderJson(orderJson);
|
||||
return _.assign(messageObj, { payload: order });
|
||||
}
|
||||
default: {
|
||||
return {
|
||||
type: OrderbookChannelMessageTypes.Unknown,
|
||||
requestId: 0,
|
||||
payload: undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user