Merge branch 'development' into fix/mutatedInput
* development: Changes to abi-gen after code review Added constructor ABIs to abi-gen Describe #295 in a CHANGELOG Add #302 description to changelog Fix formatting Apply prettier config Install prettier Remove formatting esilnt rules sendTransactionAsync should return txHash string Added Event generation to abi-gen Publish Add dates to CHANGELOG entries Update subproviders CHANGELOG Support both personal_sign and eth_sign Fix Ledger tests given change from `personal_sign` to `eth_sign` Update subprovider to catch correct RPC method Rename guide Update contribution guide Fix broken links in the abi-gen README Fix typing generation for arrays in which types separated by |s
This commit is contained in:
commit
734cf5819a
@ -26,3 +26,4 @@ jobs:
|
|||||||
background: true
|
background: true
|
||||||
- run: yarn lerna:run test:circleci
|
- run: yarn lerna:run test:circleci
|
||||||
- run: yarn lerna:run lint
|
- run: yarn lerna:run lint
|
||||||
|
- run: yarn prettier:ci
|
||||||
|
2
.prettierignore
Normal file
2
.prettierignore
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
lib
|
||||||
|
generated
|
6
.prettierrc
Normal file
6
.prettierrc
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"tabWidth": 4,
|
||||||
|
"printWidth": 120,
|
||||||
|
"trailingComma": all,
|
||||||
|
"singleQuote": true
|
||||||
|
}
|
@ -1,62 +1,47 @@
|
|||||||
# 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 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:
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
* Pull requests adding features or refactoring should be opened against the `development` branch
|
* 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
|
* 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/)
|
* 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 functionality, please also add tests and make sure they pass. We have an automatic coverage reporting tool, so we'll see it if they are missing ;)
|
||||||
If you're adding a new public function/member, make sure you document it with Java doc-style comments. We use typedoc to generate [awesome documentation](https://0xproject.com/docs/0xjs) from the comments within our source code.
|
If 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.
|
### Styleguide
|
||||||
We assume that you have `npm` and `yarn` installed.
|
|
||||||
|
|
||||||
To do that:
|
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.
|
||||||
|
|
||||||
* 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.
|
|
||||||
|
|
||||||
To lint your code just run: `yarn lint`
|
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:
|
If using the Atom text editor, we recommend you install the following packages:
|
||||||
|
|
||||||
* [atom-typescript](https://atom.io/packages/atom-typescript)
|
* [atom-typescript](https://atom.io/packages/atom-typescript)
|
||||||
* [linter-tslint](https://atom.io/packages/linter-tslint)
|
* [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 a package reaches 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 we reach v1.0.0 all breaking changes as well as new features will be minor version bumps.
|
|
||||||
|
|
||||||
We have two main branches: `master` and `development`.
|
We have two main branches: `master` and `development`.
|
||||||
|
|
||||||
|
10
package.json
10
package.json
@ -1,14 +1,15 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"name": "0x.js",
|
"name": "0x.js",
|
||||||
"workspaces": [
|
"workspaces": ["packages/*"],
|
||||||
"packages/*"
|
|
||||||
],
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"testrpc": "testrpc -p 8545 --networkId 50 -m \"${npm_package_config_mnemonic}\"",
|
"testrpc": "testrpc -p 8545 --networkId 50 -m \"${npm_package_config_mnemonic}\"",
|
||||||
|
"prettier": "prettier --write '**/*.{ts,tsx}'",
|
||||||
|
"prettier:ci": "prettier --list-different '**/*.{ts,tsx}'",
|
||||||
"lerna:run": "lerna run",
|
"lerna:run": "lerna run",
|
||||||
"lerna:rebuild": "lerna run clean; lerna run build;",
|
"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": {
|
"config": {
|
||||||
"mnemonic": "concert load couple harbor equip island argue ramp clarify fence smart topic"
|
"mnemonic": "concert load couple harbor equip island argue ramp clarify fence smart topic"
|
||||||
@ -18,6 +19,7 @@
|
|||||||
"async-child-process": "^1.1.1",
|
"async-child-process": "^1.1.1",
|
||||||
"ethereumjs-testrpc": "6.0.3",
|
"ethereumjs-testrpc": "6.0.3",
|
||||||
"lerna": "^2.5.1",
|
"lerna": "^2.5.1",
|
||||||
|
"prettier": "1.9.2",
|
||||||
"publish-release": "0xproject/publish-release",
|
"publish-release": "0xproject/publish-release",
|
||||||
"semver-sort": "^0.0.4"
|
"semver-sort": "^0.0.4"
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
vx.x.x - _TBD_
|
v0.29.0 - _December 28, 2017_
|
||||||
------------------------
|
------------------------
|
||||||
* Assert baseUnit amount supplied to `toUnitAmount` is integer amount. (#287)
|
* Assert baseUnit amount supplied to `toUnitAmount` is integer amount. (#287)
|
||||||
* `toBaseUnitAmount` throws if amount supplied has too many decimals (#287)
|
* `toBaseUnitAmount` throws if amount supplied has too many decimals (#287)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "0x.js",
|
"name": "0x.js",
|
||||||
"version": "0.28.0",
|
"version": "0.29.0",
|
||||||
"description": "A javascript library for interacting with the 0x protocol",
|
"description": "A javascript library for interacting with the 0x protocol",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"0x.js",
|
"0x.js",
|
||||||
@ -45,10 +45,10 @@
|
|||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0xproject/abi-gen": "^0.0.3",
|
"@0xproject/abi-gen": "^0.0.4",
|
||||||
"@0xproject/dev-utils": "^0.0.2",
|
"@0xproject/dev-utils": "^0.0.3",
|
||||||
"@0xproject/tslint-config": "^0.3.0",
|
"@0xproject/tslint-config": "^0.4.0",
|
||||||
"@0xproject/types": "^0.1.1",
|
"@0xproject/types": "^0.1.2",
|
||||||
"@types/bintrees": "^1.0.2",
|
"@types/bintrees": "^1.0.2",
|
||||||
"@types/jsonschema": "^1.1.1",
|
"@types/jsonschema": "^1.1.1",
|
||||||
"@types/lodash": "^4.14.86",
|
"@types/lodash": "^4.14.86",
|
||||||
@ -84,10 +84,10 @@
|
|||||||
"webpack": "^3.1.0"
|
"webpack": "^3.1.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0xproject/assert": "^0.0.8",
|
"@0xproject/assert": "^0.0.9",
|
||||||
"@0xproject/json-schemas": "^0.7.0",
|
"@0xproject/json-schemas": "^0.7.1",
|
||||||
"@0xproject/utils": "^0.1.1",
|
"@0xproject/utils": "^0.1.2",
|
||||||
"@0xproject/web3-wrapper": "^0.1.1",
|
"@0xproject/web3-wrapper": "^0.1.2",
|
||||||
"bignumber.js": "~4.1.0",
|
"bignumber.js": "~4.1.0",
|
||||||
"bintrees": "^1.0.2",
|
"bintrees": "^1.0.2",
|
||||||
"bn.js": "^4.11.8",
|
"bn.js": "^4.11.8",
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
import {schemas, SchemaValidator} from '@0xproject/json-schemas';
|
import { schemas, SchemaValidator } from '@0xproject/json-schemas';
|
||||||
import {bigNumberConfigs, intervalUtils} from '@0xproject/utils';
|
import { bigNumberConfigs, intervalUtils } from '@0xproject/utils';
|
||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import * as ethUtil from 'ethereumjs-util';
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {artifacts} from './artifacts';
|
import { artifacts } from './artifacts';
|
||||||
import {EtherTokenWrapper} from './contract_wrappers/ether_token_wrapper';
|
import { EtherTokenWrapper } from './contract_wrappers/ether_token_wrapper';
|
||||||
import {ExchangeWrapper} from './contract_wrappers/exchange_wrapper';
|
import { ExchangeWrapper } from './contract_wrappers/exchange_wrapper';
|
||||||
import {TokenRegistryWrapper} from './contract_wrappers/token_registry_wrapper';
|
import { TokenRegistryWrapper } from './contract_wrappers/token_registry_wrapper';
|
||||||
import {TokenTransferProxyWrapper} from './contract_wrappers/token_transfer_proxy_wrapper';
|
import { TokenTransferProxyWrapper } from './contract_wrappers/token_transfer_proxy_wrapper';
|
||||||
import {TokenWrapper} from './contract_wrappers/token_wrapper';
|
import { TokenWrapper } from './contract_wrappers/token_wrapper';
|
||||||
import {OrderStateWatcher} from './order_watcher/order_state_watcher';
|
import { OrderStateWatcher } from './order_watcher/order_state_watcher';
|
||||||
import {zeroExConfigSchema} from './schemas/zero_ex_config_schema';
|
import { zeroExConfigSchema } from './schemas/zero_ex_config_schema';
|
||||||
import {
|
import {
|
||||||
ECSignature,
|
ECSignature,
|
||||||
Order,
|
Order,
|
||||||
@ -22,12 +22,12 @@ import {
|
|||||||
ZeroExConfig,
|
ZeroExConfig,
|
||||||
ZeroExError,
|
ZeroExError,
|
||||||
} from './types';
|
} from './types';
|
||||||
import {AbiDecoder} from './utils/abi_decoder';
|
import { AbiDecoder } from './utils/abi_decoder';
|
||||||
import {assert} from './utils/assert';
|
import { assert } from './utils/assert';
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
import {decorators} from './utils/decorators';
|
import { decorators } from './utils/decorators';
|
||||||
import {signatureUtils} from './utils/signature_utils';
|
import { signatureUtils } from './utils/signature_utils';
|
||||||
import {utils} from './utils/utils';
|
import { utils } from './utils/utils';
|
||||||
|
|
||||||
// Customize our BigNumber instances
|
// Customize our BigNumber instances
|
||||||
bigNumberConfigs.configure();
|
bigNumberConfigs.configure();
|
||||||
@ -161,7 +161,7 @@ export class ZeroEx {
|
|||||||
* @return The resulting orderHash from hashing the supplied order.
|
* @return The resulting orderHash from hashing the supplied order.
|
||||||
*/
|
*/
|
||||||
@decorators.syncZeroExErrorHandler
|
@decorators.syncZeroExErrorHandler
|
||||||
public static getOrderHashHex(order: Order|SignedOrder): string {
|
public static getOrderHashHex(order: Order | SignedOrder): string {
|
||||||
assert.doesConformToSchema('order', order, schemas.orderSchema);
|
assert.doesConformToSchema('order', order, schemas.orderSchema);
|
||||||
const orderHashHex = utils.getOrderHashHex(order);
|
const orderHashHex = utils.getOrderHashHex(order);
|
||||||
return orderHashHex;
|
return orderHashHex;
|
||||||
@ -188,12 +188,7 @@ export class ZeroEx {
|
|||||||
config.networkId,
|
config.networkId,
|
||||||
config.tokenTransferProxyContractAddress,
|
config.tokenTransferProxyContractAddress,
|
||||||
);
|
);
|
||||||
this.token = new TokenWrapper(
|
this.token = new TokenWrapper(this._web3Wrapper, config.networkId, this._abiDecoder, this.proxy);
|
||||||
this._web3Wrapper,
|
|
||||||
config.networkId,
|
|
||||||
this._abiDecoder,
|
|
||||||
this.proxy,
|
|
||||||
);
|
|
||||||
this.exchange = new ExchangeWrapper(
|
this.exchange = new ExchangeWrapper(
|
||||||
this._web3Wrapper,
|
this._web3Wrapper,
|
||||||
config.networkId,
|
config.networkId,
|
||||||
@ -202,13 +197,17 @@ export class ZeroEx {
|
|||||||
config.exchangeContractAddress,
|
config.exchangeContractAddress,
|
||||||
);
|
);
|
||||||
this.tokenRegistry = new TokenRegistryWrapper(
|
this.tokenRegistry = new TokenRegistryWrapper(
|
||||||
this._web3Wrapper, config.networkId, config.tokenRegistryContractAddress,
|
this._web3Wrapper,
|
||||||
);
|
config.networkId,
|
||||||
this.etherToken = new EtherTokenWrapper(
|
config.tokenRegistryContractAddress,
|
||||||
this._web3Wrapper, config.networkId, this._abiDecoder, this.token,
|
|
||||||
);
|
);
|
||||||
|
this.etherToken = new EtherTokenWrapper(this._web3Wrapper, config.networkId, this._abiDecoder, this.token);
|
||||||
this.orderStateWatcher = new OrderStateWatcher(
|
this.orderStateWatcher = new OrderStateWatcher(
|
||||||
this._web3Wrapper, this._abiDecoder, this.token, this.exchange, config.orderWatcherConfig,
|
this._web3Wrapper,
|
||||||
|
this._abiDecoder,
|
||||||
|
this.token,
|
||||||
|
this.exchange,
|
||||||
|
config.orderWatcherConfig,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -291,35 +290,39 @@ export class ZeroEx {
|
|||||||
* @return Transaction receipt with decoded log args.
|
* @return Transaction receipt with decoded log args.
|
||||||
*/
|
*/
|
||||||
public async awaitTransactionMinedAsync(
|
public async awaitTransactionMinedAsync(
|
||||||
txHash: string, pollingIntervalMs = 1000, timeoutMs?: number): Promise<TransactionReceiptWithDecodedLogs> {
|
txHash: string,
|
||||||
|
pollingIntervalMs = 1000,
|
||||||
|
timeoutMs?: number,
|
||||||
|
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
let timeoutExceeded = false;
|
let timeoutExceeded = false;
|
||||||
if (timeoutMs) {
|
if (timeoutMs) {
|
||||||
setTimeout(() => timeoutExceeded = true, timeoutMs);
|
setTimeout(() => (timeoutExceeded = true), timeoutMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
const txReceiptPromise = new Promise(
|
const txReceiptPromise = new Promise(
|
||||||
(resolve: (receipt: TransactionReceiptWithDecodedLogs) => void, reject) => {
|
(resolve: (receipt: TransactionReceiptWithDecodedLogs) => void, reject) => {
|
||||||
const intervalId = intervalUtils.setAsyncExcludingInterval(async () => {
|
const intervalId = intervalUtils.setAsyncExcludingInterval(async () => {
|
||||||
if (timeoutExceeded) {
|
if (timeoutExceeded) {
|
||||||
intervalUtils.clearAsyncExcludingInterval(intervalId);
|
intervalUtils.clearAsyncExcludingInterval(intervalId);
|
||||||
return reject(ZeroExError.TransactionMiningTimeout);
|
return reject(ZeroExError.TransactionMiningTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
const transactionReceipt = await this._web3Wrapper.getTransactionReceiptAsync(txHash);
|
const transactionReceipt = await this._web3Wrapper.getTransactionReceiptAsync(txHash);
|
||||||
if (!_.isNull(transactionReceipt)) {
|
if (!_.isNull(transactionReceipt)) {
|
||||||
intervalUtils.clearAsyncExcludingInterval(intervalId);
|
intervalUtils.clearAsyncExcludingInterval(intervalId);
|
||||||
const logsWithDecodedArgs = _.map(
|
const logsWithDecodedArgs = _.map(
|
||||||
transactionReceipt.logs,
|
transactionReceipt.logs,
|
||||||
this._abiDecoder.tryToDecodeLogOrNoop.bind(this._abiDecoder),
|
this._abiDecoder.tryToDecodeLogOrNoop.bind(this._abiDecoder),
|
||||||
);
|
);
|
||||||
const transactionReceiptWithDecodedLogArgs: TransactionReceiptWithDecodedLogs = {
|
const transactionReceiptWithDecodedLogArgs: TransactionReceiptWithDecodedLogs = {
|
||||||
...transactionReceipt,
|
...transactionReceipt,
|
||||||
logs: logsWithDecodedArgs,
|
logs: logsWithDecodedArgs,
|
||||||
};
|
};
|
||||||
resolve(transactionReceiptWithDecodedLogArgs);
|
resolve(transactionReceiptWithDecodedLogArgs);
|
||||||
}
|
}
|
||||||
}, pollingIntervalMs);
|
}, pollingIntervalMs);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
return txReceiptPromise;
|
return txReceiptPromise;
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,14 @@ import * as TokenArtifact from './artifacts/Token.json';
|
|||||||
import * as TokenRegistryArtifact from './artifacts/TokenRegistry.json';
|
import * as TokenRegistryArtifact from './artifacts/TokenRegistry.json';
|
||||||
import * as TokenTransferProxyArtifact from './artifacts/TokenTransferProxy.json';
|
import * as TokenTransferProxyArtifact from './artifacts/TokenTransferProxy.json';
|
||||||
import * as ZRXArtifact from './artifacts/ZRX.json';
|
import * as ZRXArtifact from './artifacts/ZRX.json';
|
||||||
import {Artifact} from './types';
|
import { Artifact } from './types';
|
||||||
|
|
||||||
export const artifacts = {
|
export const artifacts = {
|
||||||
ZRXArtifact: ZRXArtifact as any as Artifact,
|
ZRXArtifact: (ZRXArtifact as any) as Artifact,
|
||||||
DummyTokenArtifact: DummyTokenArtifact as any as Artifact,
|
DummyTokenArtifact: (DummyTokenArtifact as any) as Artifact,
|
||||||
TokenArtifact: TokenArtifact as any as Artifact,
|
TokenArtifact: (TokenArtifact as any) as Artifact,
|
||||||
ExchangeArtifact: ExchangeArtifact as any as Artifact,
|
ExchangeArtifact: (ExchangeArtifact as any) as Artifact,
|
||||||
EtherTokenArtifact: EtherTokenArtifact as any as Artifact,
|
EtherTokenArtifact: (EtherTokenArtifact as any) as Artifact,
|
||||||
TokenRegistryArtifact: TokenRegistryArtifact as any as Artifact,
|
TokenRegistryArtifact: (TokenRegistryArtifact as any) as Artifact,
|
||||||
TokenTransferProxyArtifact: TokenTransferProxyArtifact as any as Artifact,
|
TokenTransferProxyArtifact: (TokenTransferProxyArtifact as any) as Artifact,
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import {intervalUtils} from '@0xproject/utils';
|
import { intervalUtils } from '@0xproject/utils';
|
||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import {Block, BlockAndLogStreamer} from 'ethereumjs-blockstream';
|
import { Block, BlockAndLogStreamer } from 'ethereumjs-blockstream';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
@ -17,11 +17,13 @@ import {
|
|||||||
RawLog,
|
RawLog,
|
||||||
ZeroExError,
|
ZeroExError,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import {AbiDecoder} from '../utils/abi_decoder';
|
import { AbiDecoder } from '../utils/abi_decoder';
|
||||||
import {constants} from '../utils/constants';
|
import { constants } from '../utils/constants';
|
||||||
import {filterUtils} from '../utils/filter_utils';
|
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,
|
ZRX: ZeroExError.ZRXContractDoesNotExist,
|
||||||
EtherToken: ZeroExError.EtherTokenContractDoesNotExist,
|
EtherToken: ZeroExError.EtherTokenContractDoesNotExist,
|
||||||
Token: ZeroExError.TokenContractDoesNotExist,
|
Token: ZeroExError.TokenContractDoesNotExist,
|
||||||
@ -34,12 +36,14 @@ export class ContractWrapper {
|
|||||||
protected _web3Wrapper: Web3Wrapper;
|
protected _web3Wrapper: Web3Wrapper;
|
||||||
private _networkId: number;
|
private _networkId: number;
|
||||||
private _abiDecoder?: AbiDecoder;
|
private _abiDecoder?: AbiDecoder;
|
||||||
private _blockAndLogStreamerIfExists: BlockAndLogStreamer|undefined;
|
private _blockAndLogStreamerIfExists: BlockAndLogStreamer | undefined;
|
||||||
private _blockAndLogStreamInterval: NodeJS.Timer;
|
private _blockAndLogStreamInterval: NodeJS.Timer;
|
||||||
private _filters: {[filterToken: string]: Web3.FilterObject};
|
private _filters: { [filterToken: string]: Web3.FilterObject };
|
||||||
private _filterCallbacks: {[filterToken: string]: EventCallback<ContractEventArgs>};
|
private _filterCallbacks: {
|
||||||
private _onLogAddedSubscriptionToken: string|undefined;
|
[filterToken: string]: EventCallback<ContractEventArgs>;
|
||||||
private _onLogRemovedSubscriptionToken: string|undefined;
|
};
|
||||||
|
private _onLogAddedSubscriptionToken: string | undefined;
|
||||||
|
private _onLogRemovedSubscriptionToken: string | undefined;
|
||||||
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder?: AbiDecoder) {
|
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder?: AbiDecoder) {
|
||||||
this._web3Wrapper = web3Wrapper;
|
this._web3Wrapper = web3Wrapper;
|
||||||
this._networkId = networkId;
|
this._networkId = networkId;
|
||||||
@ -71,8 +75,12 @@ export class ContractWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
protected _subscribe<ArgsType extends ContractEventArgs>(
|
protected _subscribe<ArgsType extends ContractEventArgs>(
|
||||||
address: string, eventName: ContractEvents, indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi,
|
address: string,
|
||||||
callback: EventCallback<ArgsType>): string {
|
eventName: ContractEvents,
|
||||||
|
indexFilterValues: IndexedFilterValues,
|
||||||
|
abi: Web3.ContractAbi,
|
||||||
|
callback: EventCallback<ArgsType>,
|
||||||
|
): string {
|
||||||
const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi);
|
const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi);
|
||||||
if (_.isUndefined(this._blockAndLogStreamerIfExists)) {
|
if (_.isUndefined(this._blockAndLogStreamerIfExists)) {
|
||||||
this._startBlockAndLogStream();
|
this._startBlockAndLogStream();
|
||||||
@ -83,15 +91,20 @@ export class ContractWrapper {
|
|||||||
return filterToken;
|
return filterToken;
|
||||||
}
|
}
|
||||||
protected async _getLogsAsync<ArgsType extends ContractEventArgs>(
|
protected async _getLogsAsync<ArgsType extends ContractEventArgs>(
|
||||||
address: string, eventName: ContractEvents, blockRange: BlockRange,
|
address: string,
|
||||||
indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
|
eventName: ContractEvents,
|
||||||
|
blockRange: BlockRange,
|
||||||
|
indexFilterValues: IndexedFilterValues,
|
||||||
|
abi: Web3.ContractAbi,
|
||||||
|
): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
|
||||||
const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi, blockRange);
|
const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi, blockRange);
|
||||||
const logs = await this._web3Wrapper.getLogsAsync(filter);
|
const logs = await this._web3Wrapper.getLogsAsync(filter);
|
||||||
const logsWithDecodedArguments = _.map(logs, this._tryToDecodeLogOrNoop.bind(this));
|
const logsWithDecodedArguments = _.map(logs, this._tryToDecodeLogOrNoop.bind(this));
|
||||||
return logsWithDecodedArguments;
|
return logsWithDecodedArguments;
|
||||||
}
|
}
|
||||||
protected _tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>(
|
protected _tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>(
|
||||||
log: Web3.LogEntry): LogWithDecodedArgs<ArgsType>|RawLog {
|
log: Web3.LogEntry,
|
||||||
|
): LogWithDecodedArgs<ArgsType> | RawLog {
|
||||||
if (_.isUndefined(this._abiDecoder)) {
|
if (_.isUndefined(this._abiDecoder)) {
|
||||||
throw new Error(InternalZeroExError.NoAbiDecoder);
|
throw new Error(InternalZeroExError.NoAbiDecoder);
|
||||||
}
|
}
|
||||||
@ -99,7 +112,8 @@ export class ContractWrapper {
|
|||||||
return logWithDecodedArgs;
|
return logWithDecodedArgs;
|
||||||
}
|
}
|
||||||
protected async _instantiateContractIfExistsAsync(
|
protected async _instantiateContractIfExistsAsync(
|
||||||
artifact: Artifact, addressIfExists?: string,
|
artifact: Artifact,
|
||||||
|
addressIfExists?: string,
|
||||||
): Promise<Web3.ContractInstance> {
|
): Promise<Web3.ContractInstance> {
|
||||||
let contractAddress: string;
|
let contractAddress: string;
|
||||||
if (_.isUndefined(addressIfExists)) {
|
if (_.isUndefined(addressIfExists)) {
|
||||||
@ -114,9 +128,7 @@ export class ContractWrapper {
|
|||||||
if (!doesContractExist) {
|
if (!doesContractExist) {
|
||||||
throw new Error(CONTRACT_NAME_TO_NOT_FOUND_ERROR[artifact.contract_name]);
|
throw new Error(CONTRACT_NAME_TO_NOT_FOUND_ERROR[artifact.contract_name]);
|
||||||
}
|
}
|
||||||
const contractInstance = this._web3Wrapper.getContractInstance(
|
const contractInstance = this._web3Wrapper.getContractInstance(artifact.abi, contractAddress);
|
||||||
artifact.abi, contractAddress,
|
|
||||||
);
|
|
||||||
return contractInstance;
|
return contractInstance;
|
||||||
}
|
}
|
||||||
protected _getContractAddress(artifact: Artifact, addressIfExists?: string): string {
|
protected _getContractAddress(artifact: Artifact, addressIfExists?: string): string {
|
||||||
@ -153,7 +165,8 @@ export class ContractWrapper {
|
|||||||
const catchAllLogFilter = {};
|
const catchAllLogFilter = {};
|
||||||
this._blockAndLogStreamerIfExists.addLogFilter(catchAllLogFilter);
|
this._blockAndLogStreamerIfExists.addLogFilter(catchAllLogFilter);
|
||||||
this._blockAndLogStreamInterval = intervalUtils.setAsyncExcludingInterval(
|
this._blockAndLogStreamInterval = intervalUtils.setAsyncExcludingInterval(
|
||||||
this._reconcileBlockAsync.bind(this), constants.DEFAULT_BLOCK_POLLING_INTERVAL,
|
this._reconcileBlockAsync.bind(this),
|
||||||
|
constants.DEFAULT_BLOCK_POLLING_INTERVAL,
|
||||||
);
|
);
|
||||||
let isRemoved = false;
|
let isRemoved = false;
|
||||||
this._onLogAddedSubscriptionToken = this._blockAndLogStreamerIfExists.subscribeToOnLogAdded(
|
this._onLogAddedSubscriptionToken = this._blockAndLogStreamerIfExists.subscribeToOnLogAdded(
|
||||||
@ -179,7 +192,7 @@ export class ContractWrapper {
|
|||||||
// We need to coerce to Block type cause Web3.Block includes types for mempool blocks
|
// We need to coerce to Block type cause Web3.Block includes types for mempool blocks
|
||||||
if (!_.isUndefined(this._blockAndLogStreamerIfExists)) {
|
if (!_.isUndefined(this._blockAndLogStreamerIfExists)) {
|
||||||
// If we clear the interval while fetching the block - this._blockAndLogStreamer will be undefined
|
// If we clear the interval while fetching the block - this._blockAndLogStreamer will be undefined
|
||||||
await this._blockAndLogStreamerIfExists.reconcileNewBlock(latestBlock as any as Block);
|
await this._blockAndLogStreamerIfExists.reconcileNewBlock((latestBlock as any) as Block);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const filterTokens = _.keys(this._filterCallbacks);
|
const filterTokens = _.keys(this._filterCallbacks);
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import {schemas} from '@0xproject/json-schemas';
|
import { schemas } from '@0xproject/json-schemas';
|
||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {artifacts} from '../artifacts';
|
import { artifacts } from '../artifacts';
|
||||||
import {
|
import {
|
||||||
BlockRange,
|
BlockRange,
|
||||||
EtherTokenContractEventArgs,
|
EtherTokenContractEventArgs,
|
||||||
@ -14,19 +14,21 @@ import {
|
|||||||
TransactionOpts,
|
TransactionOpts,
|
||||||
ZeroExError,
|
ZeroExError,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import {AbiDecoder} from '../utils/abi_decoder';
|
import { AbiDecoder } from '../utils/abi_decoder';
|
||||||
import {assert} from '../utils/assert';
|
import { assert } from '../utils/assert';
|
||||||
|
|
||||||
import {ContractWrapper} from './contract_wrapper';
|
import { ContractWrapper } from './contract_wrapper';
|
||||||
import {EtherTokenContract} from './generated/ether_token';
|
import { EtherTokenContract } from './generated/ether_token';
|
||||||
import {TokenWrapper} from './token_wrapper';
|
import { TokenWrapper } from './token_wrapper';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class includes all the functionality related to interacting with a wrapped Ether ERC20 token contract.
|
* This class includes all the functionality related to interacting with a wrapped Ether ERC20 token contract.
|
||||||
* The caller can convert ETH into the equivalent number of wrapped ETH ERC20 tokens and back.
|
* The caller can convert ETH into the equivalent number of wrapped ETH ERC20 tokens and back.
|
||||||
*/
|
*/
|
||||||
export class EtherTokenWrapper extends ContractWrapper {
|
export class EtherTokenWrapper extends ContractWrapper {
|
||||||
private _etherTokenContractsByAddress: {[address: string]: EtherTokenContract} = {};
|
private _etherTokenContractsByAddress: {
|
||||||
|
[address: string]: EtherTokenContract;
|
||||||
|
} = {};
|
||||||
private _tokenWrapper: TokenWrapper;
|
private _tokenWrapper: TokenWrapper;
|
||||||
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder: AbiDecoder, tokenWrapper: TokenWrapper) {
|
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder: AbiDecoder, tokenWrapper: TokenWrapper) {
|
||||||
super(web3Wrapper, networkId, abiDecoder);
|
super(web3Wrapper, networkId, abiDecoder);
|
||||||
@ -43,7 +45,10 @@ export class EtherTokenWrapper extends ContractWrapper {
|
|||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
public async depositAsync(
|
public async depositAsync(
|
||||||
etherTokenAddress: string, amountInWei: BigNumber, depositor: string, txOpts: TransactionOpts = {},
|
etherTokenAddress: string,
|
||||||
|
amountInWei: BigNumber,
|
||||||
|
depositor: string,
|
||||||
|
txOpts: TransactionOpts = {},
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
assert.isValidBaseUnitAmount('amountInWei', amountInWei);
|
assert.isValidBaseUnitAmount('amountInWei', amountInWei);
|
||||||
await assert.isSenderAddressAsync('depositor', depositor, this._web3Wrapper);
|
await assert.isSenderAddressAsync('depositor', depositor, this._web3Wrapper);
|
||||||
@ -70,7 +75,10 @@ export class EtherTokenWrapper extends ContractWrapper {
|
|||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
public async withdrawAsync(
|
public async withdrawAsync(
|
||||||
etherTokenAddress: string, amountInWei: BigNumber, withdrawer: string, txOpts: TransactionOpts = {},
|
etherTokenAddress: string,
|
||||||
|
amountInWei: BigNumber,
|
||||||
|
withdrawer: string,
|
||||||
|
txOpts: TransactionOpts = {},
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
assert.isValidBaseUnitAmount('amountInWei', amountInWei);
|
assert.isValidBaseUnitAmount('amountInWei', amountInWei);
|
||||||
await assert.isSenderAddressAsync('withdrawer', withdrawer, this._web3Wrapper);
|
await assert.isSenderAddressAsync('withdrawer', withdrawer, this._web3Wrapper);
|
||||||
@ -96,14 +104,21 @@ export class EtherTokenWrapper extends ContractWrapper {
|
|||||||
* @return Array of logs that match the parameters
|
* @return Array of logs that match the parameters
|
||||||
*/
|
*/
|
||||||
public async getLogsAsync<ArgsType extends EtherTokenContractEventArgs>(
|
public async getLogsAsync<ArgsType extends EtherTokenContractEventArgs>(
|
||||||
etherTokenAddress: string, eventName: EtherTokenEvents, blockRange: BlockRange,
|
etherTokenAddress: string,
|
||||||
indexFilterValues: IndexedFilterValues): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
|
eventName: EtherTokenEvents,
|
||||||
|
blockRange: BlockRange,
|
||||||
|
indexFilterValues: IndexedFilterValues,
|
||||||
|
): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
|
||||||
assert.isETHAddressHex('etherTokenAddress', etherTokenAddress);
|
assert.isETHAddressHex('etherTokenAddress', etherTokenAddress);
|
||||||
assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents);
|
assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents);
|
||||||
assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
|
assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
|
||||||
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
||||||
const logs = await this._getLogsAsync<ArgsType>(
|
const logs = await this._getLogsAsync<ArgsType>(
|
||||||
etherTokenAddress, eventName, blockRange, indexFilterValues, artifacts.EtherTokenArtifact.abi,
|
etherTokenAddress,
|
||||||
|
eventName,
|
||||||
|
blockRange,
|
||||||
|
indexFilterValues,
|
||||||
|
artifacts.EtherTokenArtifact.abi,
|
||||||
);
|
);
|
||||||
return logs;
|
return logs;
|
||||||
}
|
}
|
||||||
@ -117,14 +132,21 @@ export class EtherTokenWrapper extends ContractWrapper {
|
|||||||
* @return Subscription token used later to unsubscribe
|
* @return Subscription token used later to unsubscribe
|
||||||
*/
|
*/
|
||||||
public subscribe<ArgsType extends EtherTokenContractEventArgs>(
|
public subscribe<ArgsType extends EtherTokenContractEventArgs>(
|
||||||
etherTokenAddress: string, eventName: EtherTokenEvents, indexFilterValues: IndexedFilterValues,
|
etherTokenAddress: string,
|
||||||
callback: EventCallback<ArgsType>): string {
|
eventName: EtherTokenEvents,
|
||||||
|
indexFilterValues: IndexedFilterValues,
|
||||||
|
callback: EventCallback<ArgsType>,
|
||||||
|
): string {
|
||||||
assert.isETHAddressHex('etherTokenAddress', etherTokenAddress);
|
assert.isETHAddressHex('etherTokenAddress', etherTokenAddress);
|
||||||
assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents);
|
assert.doesBelongToStringEnum('eventName', eventName, EtherTokenEvents);
|
||||||
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
||||||
assert.isFunction('callback', callback);
|
assert.isFunction('callback', callback);
|
||||||
const subscriptionToken = this._subscribe<ArgsType>(
|
const subscriptionToken = this._subscribe<ArgsType>(
|
||||||
etherTokenAddress, eventName, indexFilterValues, artifacts.EtherTokenArtifact.abi, callback,
|
etherTokenAddress,
|
||||||
|
eventName,
|
||||||
|
indexFilterValues,
|
||||||
|
artifacts.EtherTokenArtifact.abi,
|
||||||
|
callback,
|
||||||
);
|
);
|
||||||
return subscriptionToken;
|
return subscriptionToken;
|
||||||
}
|
}
|
||||||
@ -151,7 +173,8 @@ export class EtherTokenWrapper extends ContractWrapper {
|
|||||||
return etherTokenContract;
|
return etherTokenContract;
|
||||||
}
|
}
|
||||||
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
||||||
artifacts.EtherTokenArtifact, etherTokenAddress,
|
artifacts.EtherTokenArtifact,
|
||||||
|
etherTokenAddress,
|
||||||
);
|
);
|
||||||
const contractInstance = new EtherTokenContract(web3ContractInstance, this._web3Wrapper.getContractDefaults());
|
const contractInstance = new EtherTokenContract(web3ContractInstance, this._web3Wrapper.getContractDefaults());
|
||||||
etherTokenContract = contractInstance;
|
etherTokenContract = contractInstance;
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import {schemas} from '@0xproject/json-schemas';
|
import { schemas } from '@0xproject/json-schemas';
|
||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import {artifacts} from '../artifacts';
|
import { artifacts } from '../artifacts';
|
||||||
import {
|
import {
|
||||||
BlockParamLiteral,
|
BlockParamLiteral,
|
||||||
BlockRange,
|
BlockRange,
|
||||||
@ -28,16 +28,16 @@ import {
|
|||||||
SignedOrder,
|
SignedOrder,
|
||||||
ValidateOrderFillableOpts,
|
ValidateOrderFillableOpts,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import {AbiDecoder} from '../utils/abi_decoder';
|
import { AbiDecoder } from '../utils/abi_decoder';
|
||||||
import {assert} from '../utils/assert';
|
import { assert } from '../utils/assert';
|
||||||
import {decorators} from '../utils/decorators';
|
import { decorators } from '../utils/decorators';
|
||||||
import {ExchangeTransferSimulator} from '../utils/exchange_transfer_simulator';
|
import { ExchangeTransferSimulator } from '../utils/exchange_transfer_simulator';
|
||||||
import {OrderValidationUtils} from '../utils/order_validation_utils';
|
import { OrderValidationUtils } from '../utils/order_validation_utils';
|
||||||
import {utils} from '../utils/utils';
|
import { utils } from '../utils/utils';
|
||||||
|
|
||||||
import {ContractWrapper} from './contract_wrapper';
|
import { ContractWrapper } from './contract_wrapper';
|
||||||
import {ExchangeContract} from './generated/exchange';
|
import { ExchangeContract } from './generated/exchange';
|
||||||
import {TokenWrapper} from './token_wrapper';
|
import { TokenWrapper } from './token_wrapper';
|
||||||
|
|
||||||
const SHOULD_VALIDATE_BY_DEFAULT = true;
|
const SHOULD_VALIDATE_BY_DEFAULT = true;
|
||||||
|
|
||||||
@ -81,8 +81,13 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
];
|
];
|
||||||
return [orderAddresses, orderValues];
|
return [orderAddresses, orderValues];
|
||||||
}
|
}
|
||||||
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder: AbiDecoder,
|
constructor(
|
||||||
tokenWrapper: TokenWrapper, contractAddressIfExists?: string) {
|
web3Wrapper: Web3Wrapper,
|
||||||
|
networkId: number,
|
||||||
|
abiDecoder: AbiDecoder,
|
||||||
|
tokenWrapper: TokenWrapper,
|
||||||
|
contractAddressIfExists?: string,
|
||||||
|
) {
|
||||||
super(web3Wrapper, networkId, abiDecoder);
|
super(web3Wrapper, networkId, abiDecoder);
|
||||||
this._tokenWrapper = tokenWrapper;
|
this._tokenWrapper = tokenWrapper;
|
||||||
this._orderValidationUtils = new OrderValidationUtils(this);
|
this._orderValidationUtils = new OrderValidationUtils(this);
|
||||||
@ -97,14 +102,14 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @param methodOpts Optional arguments this method accepts.
|
* @param methodOpts Optional arguments this method accepts.
|
||||||
* @return The amount of the order (in taker tokens) that has either been filled or cancelled.
|
* @return The amount of the order (in taker tokens) that has either been filled or cancelled.
|
||||||
*/
|
*/
|
||||||
public async getUnavailableTakerAmountAsync(orderHash: string,
|
public async getUnavailableTakerAmountAsync(orderHash: string, methodOpts?: MethodOpts): Promise<BigNumber> {
|
||||||
methodOpts?: MethodOpts): Promise<BigNumber> {
|
|
||||||
assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
|
assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
|
||||||
|
|
||||||
const exchangeContract = await this._getExchangeContractAsync();
|
const exchangeContract = await this._getExchangeContractAsync();
|
||||||
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
|
const defaultBlock = _.isUndefined(methodOpts) ? undefined : methodOpts.defaultBlock;
|
||||||
let unavailableTakerTokenAmount = await exchangeContract.getUnavailableTakerTokenAmount.callAsync(
|
let unavailableTakerTokenAmount = await exchangeContract.getUnavailableTakerTokenAmount.callAsync(
|
||||||
orderHash, defaultBlock,
|
orderHash,
|
||||||
|
defaultBlock,
|
||||||
);
|
);
|
||||||
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
|
// Wrap BigNumbers returned from web3 with our own (later) version of BigNumber
|
||||||
unavailableTakerTokenAmount = new BigNumber(unavailableTakerTokenAmount);
|
unavailableTakerTokenAmount = new BigNumber(unavailableTakerTokenAmount);
|
||||||
@ -163,24 +168,32 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
@decorators.asyncZeroExErrorHandler
|
@decorators.asyncZeroExErrorHandler
|
||||||
public async fillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber,
|
public async fillOrderAsync(
|
||||||
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
|
signedOrder: SignedOrder,
|
||||||
takerAddress: string,
|
fillTakerTokenAmount: BigNumber,
|
||||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
|
||||||
|
takerAddress: string,
|
||||||
|
orderTransactionOpts: OrderTransactionOpts = {},
|
||||||
|
): Promise<string> {
|
||||||
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
||||||
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
||||||
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
|
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
|
||||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||||
|
|
||||||
const exchangeInstance = await this._getExchangeContractAsync();
|
const exchangeInstance = await this._getExchangeContractAsync();
|
||||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
|
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
|
||||||
SHOULD_VALIDATE_BY_DEFAULT :
|
? SHOULD_VALIDATE_BY_DEFAULT
|
||||||
orderTransactionOpts.shouldValidate;
|
: orderTransactionOpts.shouldValidate;
|
||||||
if (shouldValidate) {
|
if (shouldValidate) {
|
||||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||||
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||||
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress);
|
exchangeTradeEmulator,
|
||||||
|
signedOrder,
|
||||||
|
fillTakerTokenAmount,
|
||||||
|
takerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder);
|
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder);
|
||||||
@ -219,30 +232,42 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
@decorators.asyncZeroExErrorHandler
|
@decorators.asyncZeroExErrorHandler
|
||||||
public async fillOrdersUpToAsync(signedOrders: SignedOrder[], fillTakerTokenAmount: BigNumber,
|
public async fillOrdersUpToAsync(
|
||||||
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
|
signedOrders: SignedOrder[],
|
||||||
takerAddress: string,
|
fillTakerTokenAmount: BigNumber,
|
||||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
|
||||||
|
takerAddress: string,
|
||||||
|
orderTransactionOpts: OrderTransactionOpts = {},
|
||||||
|
): Promise<string> {
|
||||||
assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema);
|
assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema);
|
||||||
const takerTokenAddresses = _.map(signedOrders, signedOrder => signedOrder.takerTokenAddress);
|
const takerTokenAddresses = _.map(signedOrders, signedOrder => signedOrder.takerTokenAddress);
|
||||||
assert.hasAtMostOneUniqueValue(takerTokenAddresses,
|
assert.hasAtMostOneUniqueValue(
|
||||||
ExchangeContractErrs.MultipleTakerTokensInFillUpToDisallowed);
|
takerTokenAddresses,
|
||||||
|
ExchangeContractErrs.MultipleTakerTokensInFillUpToDisallowed,
|
||||||
|
);
|
||||||
const exchangeContractAddresses = _.map(signedOrders, signedOrder => signedOrder.exchangeContractAddress);
|
const exchangeContractAddresses = _.map(signedOrders, signedOrder => signedOrder.exchangeContractAddress);
|
||||||
assert.hasAtMostOneUniqueValue(exchangeContractAddresses,
|
assert.hasAtMostOneUniqueValue(
|
||||||
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress);
|
exchangeContractAddresses,
|
||||||
|
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
|
||||||
|
);
|
||||||
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
||||||
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
|
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
|
||||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||||
|
|
||||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
|
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
|
||||||
SHOULD_VALIDATE_BY_DEFAULT :
|
? SHOULD_VALIDATE_BY_DEFAULT
|
||||||
orderTransactionOpts.shouldValidate;
|
: orderTransactionOpts.shouldValidate;
|
||||||
if (shouldValidate) {
|
if (shouldValidate) {
|
||||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||||
for (const signedOrder of signedOrders) {
|
for (const signedOrder of signedOrders) {
|
||||||
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||||
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress);
|
exchangeTradeEmulator,
|
||||||
|
signedOrder,
|
||||||
|
fillTakerTokenAmount,
|
||||||
|
takerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,29 +325,36 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
@decorators.asyncZeroExErrorHandler
|
@decorators.asyncZeroExErrorHandler
|
||||||
public async batchFillOrdersAsync(orderFillRequests: OrderFillRequest[],
|
public async batchFillOrdersAsync(
|
||||||
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
|
orderFillRequests: OrderFillRequest[],
|
||||||
takerAddress: string,
|
shouldThrowOnInsufficientBalanceOrAllowance: boolean,
|
||||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
takerAddress: string,
|
||||||
|
orderTransactionOpts: OrderTransactionOpts = {},
|
||||||
|
): Promise<string> {
|
||||||
assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema);
|
assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema);
|
||||||
const exchangeContractAddresses = _.map(
|
const exchangeContractAddresses = _.map(
|
||||||
orderFillRequests,
|
orderFillRequests,
|
||||||
orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress,
|
orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress,
|
||||||
);
|
);
|
||||||
assert.hasAtMostOneUniqueValue(exchangeContractAddresses,
|
assert.hasAtMostOneUniqueValue(
|
||||||
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress);
|
exchangeContractAddresses,
|
||||||
|
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
|
||||||
|
);
|
||||||
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
|
assert.isBoolean('shouldThrowOnInsufficientBalanceOrAllowance', shouldThrowOnInsufficientBalanceOrAllowance);
|
||||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
|
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
|
||||||
SHOULD_VALIDATE_BY_DEFAULT :
|
? SHOULD_VALIDATE_BY_DEFAULT
|
||||||
orderTransactionOpts.shouldValidate;
|
: orderTransactionOpts.shouldValidate;
|
||||||
if (shouldValidate) {
|
if (shouldValidate) {
|
||||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||||
for (const orderFillRequest of orderFillRequests) {
|
for (const orderFillRequest of orderFillRequests) {
|
||||||
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
||||||
exchangeTradeEmulator, orderFillRequest.signedOrder, orderFillRequest.takerTokenFillAmount,
|
exchangeTradeEmulator,
|
||||||
takerAddress, zrxTokenAddress,
|
orderFillRequest.signedOrder,
|
||||||
|
orderFillRequest.takerTokenFillAmount,
|
||||||
|
takerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -373,23 +405,31 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
@decorators.asyncZeroExErrorHandler
|
@decorators.asyncZeroExErrorHandler
|
||||||
public async fillOrKillOrderAsync(signedOrder: SignedOrder, fillTakerTokenAmount: BigNumber,
|
public async fillOrKillOrderAsync(
|
||||||
takerAddress: string,
|
signedOrder: SignedOrder,
|
||||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
fillTakerTokenAmount: BigNumber,
|
||||||
|
takerAddress: string,
|
||||||
|
orderTransactionOpts: OrderTransactionOpts = {},
|
||||||
|
): Promise<string> {
|
||||||
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
||||||
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
||||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||||
|
|
||||||
const exchangeInstance = await this._getExchangeContractAsync();
|
const exchangeInstance = await this._getExchangeContractAsync();
|
||||||
|
|
||||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
|
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
|
||||||
SHOULD_VALIDATE_BY_DEFAULT :
|
? SHOULD_VALIDATE_BY_DEFAULT
|
||||||
orderTransactionOpts.shouldValidate;
|
: orderTransactionOpts.shouldValidate;
|
||||||
if (shouldValidate) {
|
if (shouldValidate) {
|
||||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||||
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||||
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress);
|
exchangeTradeEmulator,
|
||||||
|
signedOrder,
|
||||||
|
fillTakerTokenAmount,
|
||||||
|
takerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder);
|
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(signedOrder);
|
||||||
@ -418,33 +458,39 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
@decorators.asyncZeroExErrorHandler
|
@decorators.asyncZeroExErrorHandler
|
||||||
public async batchFillOrKillAsync(orderFillRequests: OrderFillRequest[],
|
public async batchFillOrKillAsync(
|
||||||
takerAddress: string,
|
orderFillRequests: OrderFillRequest[],
|
||||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
takerAddress: string,
|
||||||
assert.doesConformToSchema('orderFillRequests', orderFillRequests,
|
orderTransactionOpts: OrderTransactionOpts = {},
|
||||||
schemas.orderFillRequestsSchema);
|
): Promise<string> {
|
||||||
|
assert.doesConformToSchema('orderFillRequests', orderFillRequests, schemas.orderFillRequestsSchema);
|
||||||
const exchangeContractAddresses = _.map(
|
const exchangeContractAddresses = _.map(
|
||||||
orderFillRequests,
|
orderFillRequests,
|
||||||
orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress,
|
orderFillRequest => orderFillRequest.signedOrder.exchangeContractAddress,
|
||||||
);
|
);
|
||||||
assert.hasAtMostOneUniqueValue(exchangeContractAddresses,
|
assert.hasAtMostOneUniqueValue(
|
||||||
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress);
|
exchangeContractAddresses,
|
||||||
|
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
|
||||||
|
);
|
||||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||||
if (_.isEmpty(orderFillRequests)) {
|
if (_.isEmpty(orderFillRequests)) {
|
||||||
throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
|
throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
|
||||||
}
|
}
|
||||||
const exchangeInstance = await this._getExchangeContractAsync();
|
const exchangeInstance = await this._getExchangeContractAsync();
|
||||||
|
|
||||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
|
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
|
||||||
SHOULD_VALIDATE_BY_DEFAULT :
|
? SHOULD_VALIDATE_BY_DEFAULT
|
||||||
orderTransactionOpts.shouldValidate;
|
: orderTransactionOpts.shouldValidate;
|
||||||
if (shouldValidate) {
|
if (shouldValidate) {
|
||||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||||
for (const orderFillRequest of orderFillRequests) {
|
for (const orderFillRequest of orderFillRequests) {
|
||||||
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||||
exchangeTradeEmulator, orderFillRequest.signedOrder, orderFillRequest.takerTokenFillAmount,
|
exchangeTradeEmulator,
|
||||||
takerAddress, zrxTokenAddress,
|
orderFillRequest.signedOrder,
|
||||||
|
orderFillRequest.takerTokenFillAmount,
|
||||||
|
takerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -460,8 +506,9 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// We use _.unzip<any> because _.unzip doesn't type check if values have different types :'(
|
// We use _.unzip<any> because _.unzip doesn't type check if values have different types :'(
|
||||||
const [orderAddresses, orderValues, fillTakerTokenAmounts, vParams, rParams, sParams] =
|
const [orderAddresses, orderValues, fillTakerTokenAmounts, vParams, rParams, sParams] = _.unzip<any>(
|
||||||
_.unzip<any>(orderAddressesValuesAndTakerTokenFillAmounts);
|
orderAddressesValuesAndTakerTokenFillAmounts,
|
||||||
|
);
|
||||||
const txHash = await exchangeInstance.batchFillOrKillOrders.sendTransactionAsync(
|
const txHash = await exchangeInstance.batchFillOrKillOrders.sendTransactionAsync(
|
||||||
orderAddresses,
|
orderAddresses,
|
||||||
orderValues,
|
orderValues,
|
||||||
@ -486,23 +533,28 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
@decorators.asyncZeroExErrorHandler
|
@decorators.asyncZeroExErrorHandler
|
||||||
public async cancelOrderAsync(order: Order|SignedOrder,
|
public async cancelOrderAsync(
|
||||||
cancelTakerTokenAmount: BigNumber,
|
order: Order | SignedOrder,
|
||||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
cancelTakerTokenAmount: BigNumber,
|
||||||
|
orderTransactionOpts: OrderTransactionOpts = {},
|
||||||
|
): Promise<string> {
|
||||||
assert.doesConformToSchema('order', order, schemas.orderSchema);
|
assert.doesConformToSchema('order', order, schemas.orderSchema);
|
||||||
assert.isValidBaseUnitAmount('takerTokenCancelAmount', cancelTakerTokenAmount);
|
assert.isValidBaseUnitAmount('takerTokenCancelAmount', cancelTakerTokenAmount);
|
||||||
await assert.isSenderAddressAsync('order.maker', order.maker, this._web3Wrapper);
|
await assert.isSenderAddressAsync('order.maker', order.maker, this._web3Wrapper);
|
||||||
|
|
||||||
const exchangeInstance = await this._getExchangeContractAsync();
|
const exchangeInstance = await this._getExchangeContractAsync();
|
||||||
|
|
||||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
|
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
|
||||||
SHOULD_VALIDATE_BY_DEFAULT :
|
? SHOULD_VALIDATE_BY_DEFAULT
|
||||||
orderTransactionOpts.shouldValidate;
|
: orderTransactionOpts.shouldValidate;
|
||||||
if (shouldValidate) {
|
if (shouldValidate) {
|
||||||
const orderHash = utils.getOrderHashHex(order);
|
const orderHash = utils.getOrderHashHex(order);
|
||||||
const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
|
const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
|
||||||
OrderValidationUtils.validateCancelOrderThrowIfInvalid(
|
OrderValidationUtils.validateCancelOrderThrowIfInvalid(
|
||||||
order, cancelTakerTokenAmount, unavailableTakerTokenAmount);
|
order,
|
||||||
|
cancelTakerTokenAmount,
|
||||||
|
unavailableTakerTokenAmount,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order);
|
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order);
|
||||||
@ -527,33 +579,40 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
@decorators.asyncZeroExErrorHandler
|
@decorators.asyncZeroExErrorHandler
|
||||||
public async batchCancelOrdersAsync(orderCancellationRequests: OrderCancellationRequest[],
|
public async batchCancelOrdersAsync(
|
||||||
orderTransactionOpts: OrderTransactionOpts = {}): Promise<string> {
|
orderCancellationRequests: OrderCancellationRequest[],
|
||||||
assert.doesConformToSchema('orderCancellationRequests', orderCancellationRequests,
|
orderTransactionOpts: OrderTransactionOpts = {},
|
||||||
schemas.orderCancellationRequestsSchema);
|
): Promise<string> {
|
||||||
|
assert.doesConformToSchema(
|
||||||
|
'orderCancellationRequests',
|
||||||
|
orderCancellationRequests,
|
||||||
|
schemas.orderCancellationRequestsSchema,
|
||||||
|
);
|
||||||
const exchangeContractAddresses = _.map(
|
const exchangeContractAddresses = _.map(
|
||||||
orderCancellationRequests,
|
orderCancellationRequests,
|
||||||
orderCancellationRequest => orderCancellationRequest.order.exchangeContractAddress,
|
orderCancellationRequest => orderCancellationRequest.order.exchangeContractAddress,
|
||||||
);
|
);
|
||||||
assert.hasAtMostOneUniqueValue(exchangeContractAddresses,
|
assert.hasAtMostOneUniqueValue(
|
||||||
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress);
|
exchangeContractAddresses,
|
||||||
|
ExchangeContractErrs.BatchOrdersMustHaveSameExchangeAddress,
|
||||||
|
);
|
||||||
const makers = _.map(orderCancellationRequests, cancellationRequest => cancellationRequest.order.maker);
|
const makers = _.map(orderCancellationRequests, cancellationRequest => cancellationRequest.order.maker);
|
||||||
assert.hasAtMostOneUniqueValue(makers, ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed);
|
assert.hasAtMostOneUniqueValue(makers, ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed);
|
||||||
const maker = makers[0];
|
const maker = makers[0];
|
||||||
await assert.isSenderAddressAsync('maker', maker, this._web3Wrapper);
|
await assert.isSenderAddressAsync('maker', maker, this._web3Wrapper);
|
||||||
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate) ?
|
const shouldValidate = _.isUndefined(orderTransactionOpts.shouldValidate)
|
||||||
SHOULD_VALIDATE_BY_DEFAULT :
|
? SHOULD_VALIDATE_BY_DEFAULT
|
||||||
orderTransactionOpts.shouldValidate;
|
: orderTransactionOpts.shouldValidate;
|
||||||
if (shouldValidate) {
|
if (shouldValidate) {
|
||||||
for (const orderCancellationRequest of orderCancellationRequests) {
|
for (const orderCancellationRequest of orderCancellationRequests) {
|
||||||
const orderHash = utils.getOrderHashHex(orderCancellationRequest.order);
|
const orderHash = utils.getOrderHashHex(orderCancellationRequest.order);
|
||||||
const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
|
const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
|
||||||
OrderValidationUtils.validateCancelOrderThrowIfInvalid(
|
OrderValidationUtils.validateCancelOrderThrowIfInvalid(
|
||||||
orderCancellationRequest.order, orderCancellationRequest.takerTokenCancelAmount,
|
orderCancellationRequest.order,
|
||||||
|
orderCancellationRequest.takerTokenCancelAmount,
|
||||||
unavailableTakerTokenAmount,
|
unavailableTakerTokenAmount,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (_.isEmpty(orderCancellationRequests)) {
|
if (_.isEmpty(orderCancellationRequests)) {
|
||||||
throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
|
throw new Error(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
|
||||||
@ -566,8 +625,9 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
];
|
];
|
||||||
});
|
});
|
||||||
// We use _.unzip<any> because _.unzip doesn't type check if values have different types :'(
|
// We use _.unzip<any> because _.unzip doesn't type check if values have different types :'(
|
||||||
const [orderAddresses, orderValues, cancelTakerTokenAmounts] =
|
const [orderAddresses, orderValues, cancelTakerTokenAmounts] = _.unzip<any>(
|
||||||
_.unzip<any>(orderAddressesValuesAndTakerTokenCancelAmounts);
|
orderAddressesValuesAndTakerTokenCancelAmounts,
|
||||||
|
);
|
||||||
const txHash = await exchangeInstance.batchCancelOrders.sendTransactionAsync(
|
const txHash = await exchangeInstance.batchCancelOrders.sendTransactionAsync(
|
||||||
orderAddresses,
|
orderAddresses,
|
||||||
orderValues,
|
orderValues,
|
||||||
@ -589,14 +649,20 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @return Subscription token used later to unsubscribe
|
* @return Subscription token used later to unsubscribe
|
||||||
*/
|
*/
|
||||||
public subscribe<ArgsType extends ExchangeContractEventArgs>(
|
public subscribe<ArgsType extends ExchangeContractEventArgs>(
|
||||||
eventName: ExchangeEvents, indexFilterValues: IndexedFilterValues,
|
eventName: ExchangeEvents,
|
||||||
callback: EventCallback<ArgsType>): string {
|
indexFilterValues: IndexedFilterValues,
|
||||||
|
callback: EventCallback<ArgsType>,
|
||||||
|
): string {
|
||||||
assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
|
assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
|
||||||
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
||||||
assert.isFunction('callback', callback);
|
assert.isFunction('callback', callback);
|
||||||
const exchangeContractAddress = this.getContractAddress();
|
const exchangeContractAddress = this.getContractAddress();
|
||||||
const subscriptionToken = this._subscribe<ArgsType>(
|
const subscriptionToken = this._subscribe<ArgsType>(
|
||||||
exchangeContractAddress, eventName, indexFilterValues, artifacts.ExchangeArtifact.abi, callback,
|
exchangeContractAddress,
|
||||||
|
eventName,
|
||||||
|
indexFilterValues,
|
||||||
|
artifacts.ExchangeArtifact.abi,
|
||||||
|
callback,
|
||||||
);
|
);
|
||||||
return subscriptionToken;
|
return subscriptionToken;
|
||||||
}
|
}
|
||||||
@ -622,14 +688,20 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @return Array of logs that match the parameters
|
* @return Array of logs that match the parameters
|
||||||
*/
|
*/
|
||||||
public async getLogsAsync<ArgsType extends ExchangeContractEventArgs>(
|
public async getLogsAsync<ArgsType extends ExchangeContractEventArgs>(
|
||||||
eventName: ExchangeEvents, blockRange: BlockRange, indexFilterValues: IndexedFilterValues,
|
eventName: ExchangeEvents,
|
||||||
|
blockRange: BlockRange,
|
||||||
|
indexFilterValues: IndexedFilterValues,
|
||||||
): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
|
): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
|
||||||
assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
|
assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
|
||||||
assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
|
assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
|
||||||
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
||||||
const exchangeContractAddress = this.getContractAddress();
|
const exchangeContractAddress = this.getContractAddress();
|
||||||
const logs = await this._getLogsAsync<ArgsType>(
|
const logs = await this._getLogsAsync<ArgsType>(
|
||||||
exchangeContractAddress, eventName, blockRange, indexFilterValues, artifacts.ExchangeArtifact.abi,
|
exchangeContractAddress,
|
||||||
|
eventName,
|
||||||
|
blockRange,
|
||||||
|
indexFilterValues,
|
||||||
|
artifacts.ExchangeArtifact.abi,
|
||||||
);
|
);
|
||||||
return logs;
|
return logs;
|
||||||
}
|
}
|
||||||
@ -652,14 +724,18 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* to validate for.
|
* to validate for.
|
||||||
*/
|
*/
|
||||||
public async validateOrderFillableOrThrowAsync(
|
public async validateOrderFillableOrThrowAsync(
|
||||||
signedOrder: SignedOrder, opts?: ValidateOrderFillableOpts,
|
signedOrder: SignedOrder,
|
||||||
|
opts?: ValidateOrderFillableOpts,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
||||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||||
const expectedFillTakerTokenAmount = !_.isUndefined(opts) ? opts.expectedFillTakerTokenAmount : undefined;
|
const expectedFillTakerTokenAmount = !_.isUndefined(opts) ? opts.expectedFillTakerTokenAmount : undefined;
|
||||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||||
await this._orderValidationUtils.validateOrderFillableOrThrowAsync(
|
await this._orderValidationUtils.validateOrderFillableOrThrowAsync(
|
||||||
exchangeTradeEmulator, signedOrder, zrxTokenAddress, expectedFillTakerTokenAmount,
|
exchangeTradeEmulator,
|
||||||
|
signedOrder,
|
||||||
|
zrxTokenAddress,
|
||||||
|
expectedFillTakerTokenAmount,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -670,16 +746,23 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @param takerAddress The user Ethereum address who would like to fill this order.
|
* @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.
|
* Must be available via the supplied Web3.Provider passed to 0x.js.
|
||||||
*/
|
*/
|
||||||
public async validateFillOrderThrowIfInvalidAsync(signedOrder: SignedOrder,
|
public async validateFillOrderThrowIfInvalidAsync(
|
||||||
fillTakerTokenAmount: BigNumber,
|
signedOrder: SignedOrder,
|
||||||
takerAddress: string): Promise<void> {
|
fillTakerTokenAmount: BigNumber,
|
||||||
|
takerAddress: string,
|
||||||
|
): Promise<void> {
|
||||||
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
||||||
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
||||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||||
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
|
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.
|
* Checks if cancelling a given order will succeed and throws an informative error if it won't.
|
||||||
@ -688,13 +771,18 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @param cancelTakerTokenAmount The amount (specified in taker tokens) that you would like to cancel.
|
* @param cancelTakerTokenAmount The amount (specified in taker tokens) that you would like to cancel.
|
||||||
*/
|
*/
|
||||||
public async validateCancelOrderThrowIfInvalidAsync(
|
public async validateCancelOrderThrowIfInvalidAsync(
|
||||||
order: Order, cancelTakerTokenAmount: BigNumber): Promise<void> {
|
order: Order,
|
||||||
|
cancelTakerTokenAmount: BigNumber,
|
||||||
|
): Promise<void> {
|
||||||
assert.doesConformToSchema('order', order, schemas.orderSchema);
|
assert.doesConformToSchema('order', order, schemas.orderSchema);
|
||||||
assert.isValidBaseUnitAmount('cancelTakerTokenAmount', cancelTakerTokenAmount);
|
assert.isValidBaseUnitAmount('cancelTakerTokenAmount', cancelTakerTokenAmount);
|
||||||
const orderHash = utils.getOrderHashHex(order);
|
const orderHash = utils.getOrderHashHex(order);
|
||||||
const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
|
const unavailableTakerTokenAmount = await this.getUnavailableTakerAmountAsync(orderHash);
|
||||||
OrderValidationUtils.validateCancelOrderThrowIfInvalid(
|
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.
|
* Checks if calling fillOrKill on a given order will succeed and throws an informative error if it won't.
|
||||||
@ -704,16 +792,23 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @param takerAddress The user Ethereum address who would like to fill this order.
|
* @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.
|
* Must be available via the supplied Web3.Provider passed to 0x.js.
|
||||||
*/
|
*/
|
||||||
public async validateFillOrKillOrderThrowIfInvalidAsync(signedOrder: SignedOrder,
|
public async validateFillOrKillOrderThrowIfInvalidAsync(
|
||||||
fillTakerTokenAmount: BigNumber,
|
signedOrder: SignedOrder,
|
||||||
takerAddress: string): Promise<void> {
|
fillTakerTokenAmount: BigNumber,
|
||||||
|
takerAddress: string,
|
||||||
|
): Promise<void> {
|
||||||
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
||||||
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
||||||
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper);
|
||||||
const zrxTokenAddress = this.getZRXTokenAddress();
|
const zrxTokenAddress = this.getZRXTokenAddress();
|
||||||
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
|
||||||
await this._orderValidationUtils.validateFillOrKillOrderThrowIfInvalidAsync(
|
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:
|
* Checks if rounding error will be > 0.1% when computing makerTokenAmount by doing:
|
||||||
@ -724,15 +819,19 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @param takerTokenAmount The order size on the taker side
|
* @param takerTokenAmount The order size on the taker side
|
||||||
* @param makerTokenAmount The order size on the maker side
|
* @param makerTokenAmount The order size on the maker side
|
||||||
*/
|
*/
|
||||||
public async isRoundingErrorAsync(fillTakerTokenAmount: BigNumber,
|
public async isRoundingErrorAsync(
|
||||||
takerTokenAmount: BigNumber,
|
fillTakerTokenAmount: BigNumber,
|
||||||
makerTokenAmount: BigNumber): Promise<boolean> {
|
takerTokenAmount: BigNumber,
|
||||||
|
makerTokenAmount: BigNumber,
|
||||||
|
): Promise<boolean> {
|
||||||
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
assert.isValidBaseUnitAmount('fillTakerTokenAmount', fillTakerTokenAmount);
|
||||||
assert.isValidBaseUnitAmount('takerTokenAmount', takerTokenAmount);
|
assert.isValidBaseUnitAmount('takerTokenAmount', takerTokenAmount);
|
||||||
assert.isValidBaseUnitAmount('makerTokenAmount', makerTokenAmount);
|
assert.isValidBaseUnitAmount('makerTokenAmount', makerTokenAmount);
|
||||||
const exchangeInstance = await this._getExchangeContractAsync();
|
const exchangeInstance = await this._getExchangeContractAsync();
|
||||||
const isRoundingError = await exchangeInstance.isRoundingError.callAsync(
|
const isRoundingError = await exchangeInstance.isRoundingError.callAsync(
|
||||||
fillTakerTokenAmount, takerTokenAmount, makerTokenAmount,
|
fillTakerTokenAmount,
|
||||||
|
takerTokenAmount,
|
||||||
|
makerTokenAmount,
|
||||||
);
|
);
|
||||||
return isRoundingError;
|
return isRoundingError;
|
||||||
}
|
}
|
||||||
@ -740,10 +839,10 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* Checks if logs contain LogError, which is emmited by Exchange contract on transaction failure.
|
* Checks if logs contain LogError, which is emmited by Exchange contract on transaction failure.
|
||||||
* @param logs Transaction logs as returned by `zeroEx.awaitTransactionMinedAsync`
|
* @param logs Transaction logs as returned by `zeroEx.awaitTransactionMinedAsync`
|
||||||
*/
|
*/
|
||||||
public throwLogErrorsAsErrors(logs: Array<LogWithDecodedArgs<DecodedLogArgs>|Web3.LogEntry>): void {
|
public throwLogErrorsAsErrors(logs: Array<LogWithDecodedArgs<DecodedLogArgs> | Web3.LogEntry>): void {
|
||||||
const errLog = _.find(logs, {
|
const errLog = _.find(logs, {
|
||||||
event: ExchangeEvents.LogError,
|
event: ExchangeEvents.LogError,
|
||||||
}) as LogWithDecodedArgs<LogErrorContractEventArgs>|undefined;
|
}) as LogWithDecodedArgs<LogErrorContractEventArgs> | undefined;
|
||||||
if (!_.isUndefined(errLog)) {
|
if (!_.isUndefined(errLog)) {
|
||||||
const logArgs = errLog.args;
|
const logArgs = errLog.args;
|
||||||
const errCode = logArgs.errorId.toNumber();
|
const errCode = logArgs.errorId.toNumber();
|
||||||
@ -756,17 +855,18 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
* @return Address of ZRX token
|
* @return Address of ZRX token
|
||||||
*/
|
*/
|
||||||
public getZRXTokenAddress(): string {
|
public getZRXTokenAddress(): string {
|
||||||
const contractAddress = this._getContractAddress(
|
const contractAddress = this._getContractAddress(artifacts.ZRXArtifact, this._zrxContractAddressIfExists);
|
||||||
artifacts.ZRXArtifact, this._zrxContractAddressIfExists,
|
|
||||||
);
|
|
||||||
return contractAddress;
|
return contractAddress;
|
||||||
}
|
}
|
||||||
private _invalidateContractInstances(): void {
|
private _invalidateContractInstances(): void {
|
||||||
this.unsubscribeAll();
|
this.unsubscribeAll();
|
||||||
delete this._exchangeContractIfExists;
|
delete this._exchangeContractIfExists;
|
||||||
}
|
}
|
||||||
private async _isValidSignatureUsingContractCallAsync(dataHex: string, ecSignature: ECSignature,
|
private async _isValidSignatureUsingContractCallAsync(
|
||||||
signerAddressHex: string): Promise<boolean> {
|
dataHex: string,
|
||||||
|
ecSignature: ECSignature,
|
||||||
|
signerAddressHex: string,
|
||||||
|
): Promise<boolean> {
|
||||||
assert.isHexString('dataHex', dataHex);
|
assert.isHexString('dataHex', dataHex);
|
||||||
assert.doesConformToSchema('ecSignature', ecSignature, schemas.ecSignatureSchema);
|
assert.doesConformToSchema('ecSignature', ecSignature, schemas.ecSignatureSchema);
|
||||||
assert.isETHAddressHex('signerAddressHex', signerAddressHex);
|
assert.isETHAddressHex('signerAddressHex', signerAddressHex);
|
||||||
@ -782,7 +882,7 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
);
|
);
|
||||||
return isValidSignature;
|
return isValidSignature;
|
||||||
}
|
}
|
||||||
private async _getOrderHashHexUsingContractCallAsync(order: Order|SignedOrder): Promise<string> {
|
private async _getOrderHashHexUsingContractCallAsync(order: Order | SignedOrder): Promise<string> {
|
||||||
const exchangeInstance = await this._getExchangeContractAsync();
|
const exchangeInstance = await this._getExchangeContractAsync();
|
||||||
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order);
|
const [orderAddresses, orderValues] = ExchangeWrapper._getOrderAddressesAndValues(order);
|
||||||
const orderHashHex = await exchangeInstance.getOrderHash.callAsync(orderAddresses, orderValues);
|
const orderHashHex = await exchangeInstance.getOrderHash.callAsync(orderAddresses, orderValues);
|
||||||
@ -793,7 +893,8 @@ export class ExchangeWrapper extends ContractWrapper {
|
|||||||
return this._exchangeContractIfExists;
|
return this._exchangeContractIfExists;
|
||||||
}
|
}
|
||||||
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
||||||
artifacts.ExchangeArtifact, this._contractAddressIfExists,
|
artifacts.ExchangeArtifact,
|
||||||
|
this._contractAddressIfExists,
|
||||||
);
|
);
|
||||||
const contractInstance = new ExchangeContract(web3ContractInstance, this._web3Wrapper.getContractDefaults());
|
const contractInstance = new ExchangeContract(web3ContractInstance, this._web3Wrapper.getContractDefaults());
|
||||||
this._exchangeContractIfExists = contractInstance;
|
this._exchangeContractIfExists = contractInstance;
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {artifacts} from '../artifacts';
|
import { artifacts } from '../artifacts';
|
||||||
import {Token, TokenMetadata} from '../types';
|
import { Token, TokenMetadata } from '../types';
|
||||||
import {assert} from '../utils/assert';
|
import { assert } from '../utils/assert';
|
||||||
import {constants} from '../utils/constants';
|
import { constants } from '../utils/constants';
|
||||||
|
|
||||||
import {ContractWrapper} from './contract_wrapper';
|
import { ContractWrapper } from './contract_wrapper';
|
||||||
import {TokenRegistryContract} from './generated/token_registry';
|
import { TokenRegistryContract } from './generated/token_registry';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class includes all the functionality related to interacting with the 0x Token Registry smart contract.
|
* This class includes all the functionality related to interacting with the 0x Token Registry smart contract.
|
||||||
@ -15,7 +15,7 @@ import {TokenRegistryContract} from './generated/token_registry';
|
|||||||
export class TokenRegistryWrapper extends ContractWrapper {
|
export class TokenRegistryWrapper extends ContractWrapper {
|
||||||
private _tokenRegistryContractIfExists?: TokenRegistryContract;
|
private _tokenRegistryContractIfExists?: TokenRegistryContract;
|
||||||
private _contractAddressIfExists?: string;
|
private _contractAddressIfExists?: string;
|
||||||
private static _createTokenFromMetadata(metadata: TokenMetadata): Token|undefined {
|
private static _createTokenFromMetadata(metadata: TokenMetadata): Token | undefined {
|
||||||
if (metadata[0] === constants.NULL_ADDRESS) {
|
if (metadata[0] === constants.NULL_ADDRESS) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@ -37,9 +37,8 @@ export class TokenRegistryWrapper extends ContractWrapper {
|
|||||||
*/
|
*/
|
||||||
public async getTokensAsync(): Promise<Token[]> {
|
public async getTokensAsync(): Promise<Token[]> {
|
||||||
const addresses = await this.getTokenAddressesAsync();
|
const addresses = await this.getTokenAddressesAsync();
|
||||||
const tokenPromises: Array<Promise<Token|undefined>> = _.map(
|
const tokenPromises: Array<Promise<Token | undefined>> = _.map(addresses, async (address: string) =>
|
||||||
addresses,
|
this.getTokenIfExistsAsync(address),
|
||||||
async (address: string) => this.getTokenIfExistsAsync(address),
|
|
||||||
);
|
);
|
||||||
const tokens = await Promise.all(tokenPromises);
|
const tokens = await Promise.all(tokenPromises);
|
||||||
return tokens as Token[];
|
return tokens as Token[];
|
||||||
@ -57,7 +56,7 @@ export class TokenRegistryWrapper extends ContractWrapper {
|
|||||||
* Retrieves a token by address currently listed in the Token Registry smart contract
|
* Retrieves a token by address currently listed in the Token Registry smart contract
|
||||||
* @return An object that conforms to the Token interface or undefined if token not found.
|
* @return An object that conforms to the Token interface or undefined if token not found.
|
||||||
*/
|
*/
|
||||||
public async getTokenIfExistsAsync(address: string): Promise<Token|undefined> {
|
public async getTokenIfExistsAsync(address: string): Promise<Token | undefined> {
|
||||||
assert.isETHAddressHex('address', address);
|
assert.isETHAddressHex('address', address);
|
||||||
|
|
||||||
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
||||||
@ -65,7 +64,7 @@ export class TokenRegistryWrapper extends ContractWrapper {
|
|||||||
const token = TokenRegistryWrapper._createTokenFromMetadata(metadata);
|
const token = TokenRegistryWrapper._createTokenFromMetadata(metadata);
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
public async getTokenAddressBySymbolIfExistsAsync(symbol: string): Promise<string|undefined> {
|
public async getTokenAddressBySymbolIfExistsAsync(symbol: string): Promise<string | undefined> {
|
||||||
assert.isString('symbol', symbol);
|
assert.isString('symbol', symbol);
|
||||||
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
||||||
const addressIfExists = await tokenRegistryContract.getTokenAddressBySymbol.callAsync(symbol);
|
const addressIfExists = await tokenRegistryContract.getTokenAddressBySymbol.callAsync(symbol);
|
||||||
@ -74,7 +73,7 @@ export class TokenRegistryWrapper extends ContractWrapper {
|
|||||||
}
|
}
|
||||||
return addressIfExists;
|
return addressIfExists;
|
||||||
}
|
}
|
||||||
public async getTokenAddressByNameIfExistsAsync(name: string): Promise<string|undefined> {
|
public async getTokenAddressByNameIfExistsAsync(name: string): Promise<string | undefined> {
|
||||||
assert.isString('name', name);
|
assert.isString('name', name);
|
||||||
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
||||||
const addressIfExists = await tokenRegistryContract.getTokenAddressByName.callAsync(name);
|
const addressIfExists = await tokenRegistryContract.getTokenAddressByName.callAsync(name);
|
||||||
@ -83,14 +82,14 @@ export class TokenRegistryWrapper extends ContractWrapper {
|
|||||||
}
|
}
|
||||||
return addressIfExists;
|
return addressIfExists;
|
||||||
}
|
}
|
||||||
public async getTokenBySymbolIfExistsAsync(symbol: string): Promise<Token|undefined> {
|
public async getTokenBySymbolIfExistsAsync(symbol: string): Promise<Token | undefined> {
|
||||||
assert.isString('symbol', symbol);
|
assert.isString('symbol', symbol);
|
||||||
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
||||||
const metadata = await tokenRegistryContract.getTokenBySymbol.callAsync(symbol);
|
const metadata = await tokenRegistryContract.getTokenBySymbol.callAsync(symbol);
|
||||||
const token = TokenRegistryWrapper._createTokenFromMetadata(metadata);
|
const token = TokenRegistryWrapper._createTokenFromMetadata(metadata);
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
public async getTokenByNameIfExistsAsync(name: string): Promise<Token|undefined> {
|
public async getTokenByNameIfExistsAsync(name: string): Promise<Token | undefined> {
|
||||||
assert.isString('name', name);
|
assert.isString('name', name);
|
||||||
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
const tokenRegistryContract = await this._getTokenRegistryContractAsync();
|
||||||
const metadata = await tokenRegistryContract.getTokenByName.callAsync(name);
|
const metadata = await tokenRegistryContract.getTokenByName.callAsync(name);
|
||||||
@ -104,7 +103,8 @@ export class TokenRegistryWrapper extends ContractWrapper {
|
|||||||
*/
|
*/
|
||||||
public getContractAddress(): string {
|
public getContractAddress(): string {
|
||||||
const contractAddress = this._getContractAddress(
|
const contractAddress = this._getContractAddress(
|
||||||
artifacts.TokenRegistryArtifact, this._contractAddressIfExists,
|
artifacts.TokenRegistryArtifact,
|
||||||
|
this._contractAddressIfExists,
|
||||||
);
|
);
|
||||||
return contractAddress;
|
return contractAddress;
|
||||||
}
|
}
|
||||||
@ -116,10 +116,12 @@ export class TokenRegistryWrapper extends ContractWrapper {
|
|||||||
return this._tokenRegistryContractIfExists;
|
return this._tokenRegistryContractIfExists;
|
||||||
}
|
}
|
||||||
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
||||||
artifacts.TokenRegistryArtifact, this._contractAddressIfExists,
|
artifacts.TokenRegistryArtifact,
|
||||||
|
this._contractAddressIfExists,
|
||||||
);
|
);
|
||||||
const contractInstance = new TokenRegistryContract(
|
const contractInstance = new TokenRegistryContract(
|
||||||
web3ContractInstance, this._web3Wrapper.getContractDefaults(),
|
web3ContractInstance,
|
||||||
|
this._web3Wrapper.getContractDefaults(),
|
||||||
);
|
);
|
||||||
this._tokenRegistryContractIfExists = contractInstance;
|
this._tokenRegistryContractIfExists = contractInstance;
|
||||||
return this._tokenRegistryContractIfExists;
|
return this._tokenRegistryContractIfExists;
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {artifacts} from '../artifacts';
|
import { artifacts } from '../artifacts';
|
||||||
|
|
||||||
import {ContractWrapper} from './contract_wrapper';
|
import { ContractWrapper } from './contract_wrapper';
|
||||||
import {TokenTransferProxyContract} from './generated/token_transfer_proxy';
|
import { TokenTransferProxyContract } from './generated/token_transfer_proxy';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class includes the functionality related to interacting with the TokenTransferProxy contract.
|
* This class includes the functionality related to interacting with the TokenTransferProxy contract.
|
||||||
@ -42,7 +42,8 @@ export class TokenTransferProxyWrapper extends ContractWrapper {
|
|||||||
*/
|
*/
|
||||||
public getContractAddress(): string {
|
public getContractAddress(): string {
|
||||||
const contractAddress = this._getContractAddress(
|
const contractAddress = this._getContractAddress(
|
||||||
artifacts.TokenTransferProxyArtifact, this._contractAddressIfExists,
|
artifacts.TokenTransferProxyArtifact,
|
||||||
|
this._contractAddressIfExists,
|
||||||
);
|
);
|
||||||
return contractAddress;
|
return contractAddress;
|
||||||
}
|
}
|
||||||
@ -54,10 +55,12 @@ export class TokenTransferProxyWrapper extends ContractWrapper {
|
|||||||
return this._tokenTransferProxyContractIfExists;
|
return this._tokenTransferProxyContractIfExists;
|
||||||
}
|
}
|
||||||
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
||||||
artifacts.TokenTransferProxyArtifact, this._contractAddressIfExists,
|
artifacts.TokenTransferProxyArtifact,
|
||||||
|
this._contractAddressIfExists,
|
||||||
);
|
);
|
||||||
const contractInstance = new TokenTransferProxyContract(
|
const contractInstance = new TokenTransferProxyContract(
|
||||||
web3ContractInstance, this._web3Wrapper.getContractDefaults(),
|
web3ContractInstance,
|
||||||
|
this._web3Wrapper.getContractDefaults(),
|
||||||
);
|
);
|
||||||
this._tokenTransferProxyContractIfExists = contractInstance;
|
this._tokenTransferProxyContractIfExists = contractInstance;
|
||||||
return this._tokenTransferProxyContractIfExists;
|
return this._tokenTransferProxyContractIfExists;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import {schemas} from '@0xproject/json-schemas';
|
import { schemas } from '@0xproject/json-schemas';
|
||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {artifacts} from '../artifacts';
|
import { artifacts } from '../artifacts';
|
||||||
import {
|
import {
|
||||||
BlockRange,
|
BlockRange,
|
||||||
EventCallback,
|
EventCallback,
|
||||||
@ -15,13 +15,13 @@ import {
|
|||||||
TransactionOpts,
|
TransactionOpts,
|
||||||
ZeroExError,
|
ZeroExError,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import {AbiDecoder} from '../utils/abi_decoder';
|
import { AbiDecoder } from '../utils/abi_decoder';
|
||||||
import {assert} from '../utils/assert';
|
import { assert } from '../utils/assert';
|
||||||
import {constants} from '../utils/constants';
|
import { constants } from '../utils/constants';
|
||||||
|
|
||||||
import {ContractWrapper} from './contract_wrapper';
|
import { ContractWrapper } from './contract_wrapper';
|
||||||
import {TokenContract} from './generated/token';
|
import { TokenContract } from './generated/token';
|
||||||
import {TokenTransferProxyWrapper} from './token_transfer_proxy_wrapper';
|
import { TokenTransferProxyWrapper } from './token_transfer_proxy_wrapper';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class includes all the functionality related to interacting with ERC20 token contracts.
|
* This class includes all the functionality related to interacting with ERC20 token contracts.
|
||||||
@ -30,10 +30,14 @@ import {TokenTransferProxyWrapper} from './token_transfer_proxy_wrapper';
|
|||||||
*/
|
*/
|
||||||
export class TokenWrapper extends ContractWrapper {
|
export class TokenWrapper extends ContractWrapper {
|
||||||
public UNLIMITED_ALLOWANCE_IN_BASE_UNITS = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
|
public UNLIMITED_ALLOWANCE_IN_BASE_UNITS = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
|
||||||
private _tokenContractsByAddress: {[address: string]: TokenContract};
|
private _tokenContractsByAddress: { [address: string]: TokenContract };
|
||||||
private _tokenTransferProxyWrapper: TokenTransferProxyWrapper;
|
private _tokenTransferProxyWrapper: TokenTransferProxyWrapper;
|
||||||
constructor(web3Wrapper: Web3Wrapper, networkId: number, abiDecoder: AbiDecoder,
|
constructor(
|
||||||
tokenTransferProxyWrapper: TokenTransferProxyWrapper) {
|
web3Wrapper: Web3Wrapper,
|
||||||
|
networkId: number,
|
||||||
|
abiDecoder: AbiDecoder,
|
||||||
|
tokenTransferProxyWrapper: TokenTransferProxyWrapper,
|
||||||
|
) {
|
||||||
super(web3Wrapper, networkId, abiDecoder);
|
super(web3Wrapper, networkId, abiDecoder);
|
||||||
this._tokenContractsByAddress = {};
|
this._tokenContractsByAddress = {};
|
||||||
this._tokenTransferProxyWrapper = tokenTransferProxyWrapper;
|
this._tokenTransferProxyWrapper = tokenTransferProxyWrapper;
|
||||||
@ -45,8 +49,11 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
* @param methodOpts Optional arguments this method accepts.
|
* @param methodOpts Optional arguments this method accepts.
|
||||||
* @return The owner's ERC20 token balance in base units.
|
* @return The owner's ERC20 token balance in base units.
|
||||||
*/
|
*/
|
||||||
public async getBalanceAsync(tokenAddress: string, ownerAddress: string,
|
public async getBalanceAsync(
|
||||||
methodOpts?: MethodOpts): Promise<BigNumber> {
|
tokenAddress: string,
|
||||||
|
ownerAddress: string,
|
||||||
|
methodOpts?: MethodOpts,
|
||||||
|
): Promise<BigNumber> {
|
||||||
assert.isETHAddressHex('ownerAddress', ownerAddress);
|
assert.isETHAddressHex('ownerAddress', ownerAddress);
|
||||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||||
|
|
||||||
@ -68,8 +75,13 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
* @param txOpts Transaction parameters.
|
* @param txOpts Transaction parameters.
|
||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
public async setAllowanceAsync(tokenAddress: string, ownerAddress: string, spenderAddress: string,
|
public async setAllowanceAsync(
|
||||||
amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise<string> {
|
tokenAddress: string,
|
||||||
|
ownerAddress: string,
|
||||||
|
spenderAddress: string,
|
||||||
|
amountInBaseUnits: BigNumber,
|
||||||
|
txOpts: TransactionOpts = {},
|
||||||
|
): Promise<string> {
|
||||||
await assert.isSenderAddressAsync('ownerAddress', ownerAddress, this._web3Wrapper);
|
await assert.isSenderAddressAsync('ownerAddress', ownerAddress, this._web3Wrapper);
|
||||||
assert.isETHAddressHex('spenderAddress', spenderAddress);
|
assert.isETHAddressHex('spenderAddress', spenderAddress);
|
||||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||||
@ -95,10 +107,18 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
* @param txOpts Transaction parameters.
|
* @param txOpts Transaction parameters.
|
||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
public async setUnlimitedAllowanceAsync(tokenAddress: string, ownerAddress: string,
|
public async setUnlimitedAllowanceAsync(
|
||||||
spenderAddress: string, txOpts: TransactionOpts = {}): Promise<string> {
|
tokenAddress: string,
|
||||||
|
ownerAddress: string,
|
||||||
|
spenderAddress: string,
|
||||||
|
txOpts: TransactionOpts = {},
|
||||||
|
): Promise<string> {
|
||||||
const txHash = await this.setAllowanceAsync(
|
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;
|
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 spenderAddress The hex encoded user Ethereum address who can spend the allowance you are fetching.
|
||||||
* @param methodOpts Optional arguments this method accepts.
|
* @param methodOpts Optional arguments this method accepts.
|
||||||
*/
|
*/
|
||||||
public async getAllowanceAsync(tokenAddress: string, ownerAddress: string,
|
public async getAllowanceAsync(
|
||||||
spenderAddress: string, methodOpts?: MethodOpts): Promise<BigNumber> {
|
tokenAddress: string,
|
||||||
|
ownerAddress: string,
|
||||||
|
spenderAddress: string,
|
||||||
|
methodOpts?: MethodOpts,
|
||||||
|
): Promise<BigNumber> {
|
||||||
assert.isETHAddressHex('ownerAddress', ownerAddress);
|
assert.isETHAddressHex('ownerAddress', ownerAddress);
|
||||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
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 ownerAddress The hex encoded user Ethereum address whose proxy contract allowance we are retrieving.
|
||||||
* @param methodOpts Optional arguments this method accepts.
|
* @param methodOpts Optional arguments this method accepts.
|
||||||
*/
|
*/
|
||||||
public async getProxyAllowanceAsync(tokenAddress: string, ownerAddress: string,
|
public async getProxyAllowanceAsync(
|
||||||
methodOpts?: MethodOpts): Promise<BigNumber> {
|
tokenAddress: string,
|
||||||
|
ownerAddress: string,
|
||||||
|
methodOpts?: MethodOpts,
|
||||||
|
): Promise<BigNumber> {
|
||||||
assert.isETHAddressHex('ownerAddress', ownerAddress);
|
assert.isETHAddressHex('ownerAddress', ownerAddress);
|
||||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||||
|
|
||||||
@ -147,15 +174,23 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
* @param txOpts Transaction parameters.
|
* @param txOpts Transaction parameters.
|
||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
public async setProxyAllowanceAsync(tokenAddress: string, ownerAddress: string,
|
public async setProxyAllowanceAsync(
|
||||||
amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise<string> {
|
tokenAddress: string,
|
||||||
|
ownerAddress: string,
|
||||||
|
amountInBaseUnits: BigNumber,
|
||||||
|
txOpts: TransactionOpts = {},
|
||||||
|
): Promise<string> {
|
||||||
assert.isETHAddressHex('ownerAddress', ownerAddress);
|
assert.isETHAddressHex('ownerAddress', ownerAddress);
|
||||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||||
assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
|
assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits);
|
||||||
|
|
||||||
const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress();
|
const proxyAddress = this._tokenTransferProxyWrapper.getContractAddress();
|
||||||
const txHash = await this.setAllowanceAsync(
|
const txHash = await this.setAllowanceAsync(
|
||||||
tokenAddress, ownerAddress, proxyAddress, amountInBaseUnits, txOpts,
|
tokenAddress,
|
||||||
|
ownerAddress,
|
||||||
|
proxyAddress,
|
||||||
|
amountInBaseUnits,
|
||||||
|
txOpts,
|
||||||
);
|
);
|
||||||
return txHash;
|
return txHash;
|
||||||
}
|
}
|
||||||
@ -171,10 +206,15 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
public async setUnlimitedProxyAllowanceAsync(
|
public async setUnlimitedProxyAllowanceAsync(
|
||||||
tokenAddress: string, ownerAddress: string, txOpts: TransactionOpts = {},
|
tokenAddress: string,
|
||||||
|
ownerAddress: string,
|
||||||
|
txOpts: TransactionOpts = {},
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const txHash = await this.setProxyAllowanceAsync(
|
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;
|
return txHash;
|
||||||
}
|
}
|
||||||
@ -187,8 +227,13 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
* @param txOpts Transaction parameters.
|
* @param txOpts Transaction parameters.
|
||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
public async transferAsync(tokenAddress: string, fromAddress: string, toAddress: string,
|
public async transferAsync(
|
||||||
amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}): Promise<string> {
|
tokenAddress: string,
|
||||||
|
fromAddress: string,
|
||||||
|
toAddress: string,
|
||||||
|
amountInBaseUnits: BigNumber,
|
||||||
|
txOpts: TransactionOpts = {},
|
||||||
|
): Promise<string> {
|
||||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||||
await assert.isSenderAddressAsync('fromAddress', fromAddress, this._web3Wrapper);
|
await assert.isSenderAddressAsync('fromAddress', fromAddress, this._web3Wrapper);
|
||||||
assert.isETHAddressHex('toAddress', toAddress);
|
assert.isETHAddressHex('toAddress', toAddress);
|
||||||
@ -222,9 +267,14 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
* @param txOpts Transaction parameters.
|
* @param txOpts Transaction parameters.
|
||||||
* @return Transaction hash.
|
* @return Transaction hash.
|
||||||
*/
|
*/
|
||||||
public async transferFromAsync(tokenAddress: string, fromAddress: string, toAddress: string,
|
public async transferFromAsync(
|
||||||
senderAddress: string, amountInBaseUnits: BigNumber, txOpts: TransactionOpts = {}):
|
tokenAddress: string,
|
||||||
Promise<string> {
|
fromAddress: string,
|
||||||
|
toAddress: string,
|
||||||
|
senderAddress: string,
|
||||||
|
amountInBaseUnits: BigNumber,
|
||||||
|
txOpts: TransactionOpts = {},
|
||||||
|
): Promise<string> {
|
||||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||||
assert.isETHAddressHex('fromAddress', fromAddress);
|
assert.isETHAddressHex('fromAddress', fromAddress);
|
||||||
assert.isETHAddressHex('toAddress', toAddress);
|
assert.isETHAddressHex('toAddress', toAddress);
|
||||||
@ -244,7 +294,9 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const txHash = await tokenContract.transferFrom.sendTransactionAsync(
|
const txHash = await tokenContract.transferFrom.sendTransactionAsync(
|
||||||
fromAddress, toAddress, amountInBaseUnits,
|
fromAddress,
|
||||||
|
toAddress,
|
||||||
|
amountInBaseUnits,
|
||||||
{
|
{
|
||||||
from: senderAddress,
|
from: senderAddress,
|
||||||
gas: txOpts.gasLimit,
|
gas: txOpts.gasLimit,
|
||||||
@ -263,14 +315,21 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
* @return Subscription token used later to unsubscribe
|
* @return Subscription token used later to unsubscribe
|
||||||
*/
|
*/
|
||||||
public subscribe<ArgsType extends TokenContractEventArgs>(
|
public subscribe<ArgsType extends TokenContractEventArgs>(
|
||||||
tokenAddress: string, eventName: TokenEvents, indexFilterValues: IndexedFilterValues,
|
tokenAddress: string,
|
||||||
callback: EventCallback<ArgsType>): string {
|
eventName: TokenEvents,
|
||||||
|
indexFilterValues: IndexedFilterValues,
|
||||||
|
callback: EventCallback<ArgsType>,
|
||||||
|
): string {
|
||||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||||
assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
|
assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
|
||||||
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
||||||
assert.isFunction('callback', callback);
|
assert.isFunction('callback', callback);
|
||||||
const subscriptionToken = this._subscribe<ArgsType>(
|
const subscriptionToken = this._subscribe<ArgsType>(
|
||||||
tokenAddress, eventName, indexFilterValues, artifacts.TokenArtifact.abi, callback,
|
tokenAddress,
|
||||||
|
eventName,
|
||||||
|
indexFilterValues,
|
||||||
|
artifacts.TokenArtifact.abi,
|
||||||
|
callback,
|
||||||
);
|
);
|
||||||
return subscriptionToken;
|
return subscriptionToken;
|
||||||
}
|
}
|
||||||
@ -297,14 +356,21 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
* @return Array of logs that match the parameters
|
* @return Array of logs that match the parameters
|
||||||
*/
|
*/
|
||||||
public async getLogsAsync<ArgsType extends TokenContractEventArgs>(
|
public async getLogsAsync<ArgsType extends TokenContractEventArgs>(
|
||||||
tokenAddress: string, eventName: TokenEvents, blockRange: BlockRange,
|
tokenAddress: string,
|
||||||
indexFilterValues: IndexedFilterValues): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
|
eventName: TokenEvents,
|
||||||
|
blockRange: BlockRange,
|
||||||
|
indexFilterValues: IndexedFilterValues,
|
||||||
|
): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
|
||||||
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
assert.isETHAddressHex('tokenAddress', tokenAddress);
|
||||||
assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
|
assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
|
||||||
assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
|
assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
|
||||||
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
||||||
const logs = await this._getLogsAsync<ArgsType>(
|
const logs = await this._getLogsAsync<ArgsType>(
|
||||||
tokenAddress, eventName, blockRange, indexFilterValues, artifacts.TokenArtifact.abi,
|
tokenAddress,
|
||||||
|
eventName,
|
||||||
|
blockRange,
|
||||||
|
indexFilterValues,
|
||||||
|
artifacts.TokenArtifact.abi,
|
||||||
);
|
);
|
||||||
return logs;
|
return logs;
|
||||||
}
|
}
|
||||||
@ -318,11 +384,10 @@ export class TokenWrapper extends ContractWrapper {
|
|||||||
return tokenContract;
|
return tokenContract;
|
||||||
}
|
}
|
||||||
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
const web3ContractInstance = await this._instantiateContractIfExistsAsync(
|
||||||
artifacts.TokenArtifact, tokenAddress,
|
artifacts.TokenArtifact,
|
||||||
);
|
tokenAddress,
|
||||||
const contractInstance = new TokenContract(
|
|
||||||
web3ContractInstance, this._web3Wrapper.getContractDefaults(),
|
|
||||||
);
|
);
|
||||||
|
const contractInstance = new TokenContract(web3ContractInstance, this._web3Wrapper.getContractDefaults());
|
||||||
tokenContract = contractInstance;
|
tokenContract = contractInstance;
|
||||||
this._tokenContractsByAddress[tokenAddress] = tokenContract;
|
this._tokenContractsByAddress[tokenAddress] = tokenContract;
|
||||||
return tokenContract;
|
return tokenContract;
|
||||||
|
3
packages/0x.js/src/globals.d.ts
vendored
3
packages/0x.js/src/globals.d.ts
vendored
@ -57,8 +57,7 @@ declare module 'truffle-hdwallet-provider' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// abi-decoder declarations
|
// abi-decoder declarations
|
||||||
interface DecodedLogArg {
|
interface DecodedLogArg {}
|
||||||
}
|
|
||||||
interface DecodedLog {
|
interface DecodedLog {
|
||||||
name: string;
|
name: string;
|
||||||
events: DecodedLogArg[];
|
events: DecodedLogArg[];
|
||||||
|
4
packages/0x.js/src/globalsAugment.d.ts
vendored
4
packages/0x.js/src/globalsAugment.d.ts
vendored
@ -9,7 +9,7 @@ declare global {
|
|||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
namespace Chai {
|
namespace Chai {
|
||||||
interface NumberComparer {
|
interface NumberComparer {
|
||||||
(value: number|BigNumber, message?: string): Assertion;
|
(value: number | BigNumber, message?: string): Assertion;
|
||||||
}
|
}
|
||||||
interface NumericComparison {
|
interface NumericComparison {
|
||||||
greaterThan: NumberComparer;
|
greaterThan: NumberComparer;
|
||||||
@ -18,6 +18,6 @@ declare global {
|
|||||||
/* tslint:enable */
|
/* tslint:enable */
|
||||||
interface DecodedLogArg {
|
interface DecodedLogArg {
|
||||||
name: string;
|
name: string;
|
||||||
value: string|BigNumber;
|
value: string | BigNumber;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export {ZeroEx} from './0x';
|
export { ZeroEx } from './0x';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Order,
|
Order,
|
||||||
@ -47,6 +47,4 @@ export {
|
|||||||
OrderState,
|
OrderState,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
export {
|
export { TransactionReceipt } from '@0xproject/types';
|
||||||
TransactionReceipt,
|
|
||||||
} from '@0xproject/types';
|
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
import {intervalUtils} from '@0xproject/utils';
|
import { intervalUtils } from '@0xproject/utils';
|
||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import {
|
import { BlockParamLiteral, EventWatcherCallback, ZeroExError } from '../types';
|
||||||
BlockParamLiteral,
|
import { assert } from '../utils/assert';
|
||||||
EventWatcherCallback,
|
|
||||||
ZeroExError,
|
|
||||||
} from '../types';
|
|
||||||
import {assert} from '../utils/assert';
|
|
||||||
|
|
||||||
const DEFAULT_EVENT_POLLING_INTERVAL_MS = 200;
|
const DEFAULT_EVENT_POLLING_INTERVAL_MS = 200;
|
||||||
|
|
||||||
@ -26,11 +22,11 @@ export class EventWatcher {
|
|||||||
private _pollingIntervalMs: number;
|
private _pollingIntervalMs: number;
|
||||||
private _intervalIdIfExists?: NodeJS.Timer;
|
private _intervalIdIfExists?: NodeJS.Timer;
|
||||||
private _lastEvents: Web3.LogEntry[] = [];
|
private _lastEvents: Web3.LogEntry[] = [];
|
||||||
constructor(web3Wrapper: Web3Wrapper, pollingIntervalIfExistsMs: undefined|number) {
|
constructor(web3Wrapper: Web3Wrapper, pollingIntervalIfExistsMs: undefined | number) {
|
||||||
this._web3Wrapper = web3Wrapper;
|
this._web3Wrapper = web3Wrapper;
|
||||||
this._pollingIntervalMs = _.isUndefined(pollingIntervalIfExistsMs) ?
|
this._pollingIntervalMs = _.isUndefined(pollingIntervalIfExistsMs)
|
||||||
DEFAULT_EVENT_POLLING_INTERVAL_MS :
|
? DEFAULT_EVENT_POLLING_INTERVAL_MS
|
||||||
pollingIntervalIfExistsMs;
|
: pollingIntervalIfExistsMs;
|
||||||
}
|
}
|
||||||
public subscribe(callback: EventWatcherCallback): void {
|
public subscribe(callback: EventWatcherCallback): void {
|
||||||
assert.isFunction('callback', callback);
|
assert.isFunction('callback', callback);
|
||||||
@ -38,7 +34,8 @@ export class EventWatcher {
|
|||||||
throw new Error(ZeroExError.SubscriptionAlreadyPresent);
|
throw new Error(ZeroExError.SubscriptionAlreadyPresent);
|
||||||
}
|
}
|
||||||
this._intervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
|
this._intervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
|
||||||
this._pollForBlockchainEventsAsync.bind(this, callback), this._pollingIntervalMs,
|
this._pollForBlockchainEventsAsync.bind(this, callback),
|
||||||
|
this._pollingIntervalMs,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public unsubscribe(): void {
|
public unsubscribe(): void {
|
||||||
@ -71,7 +68,9 @@ export class EventWatcher {
|
|||||||
return events;
|
return events;
|
||||||
}
|
}
|
||||||
private async _emitDifferencesAsync(
|
private async _emitDifferencesAsync(
|
||||||
logs: Web3.LogEntry[], logEventState: LogEventState, callback: EventWatcherCallback,
|
logs: Web3.LogEntry[],
|
||||||
|
logEventState: LogEventState,
|
||||||
|
callback: EventWatcherCallback,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
for (const log of logs) {
|
for (const log of logs) {
|
||||||
const logEvent = {
|
const logEvent = {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import {intervalUtils} from '@0xproject/utils';
|
import { intervalUtils } from '@0xproject/utils';
|
||||||
import {BigNumber} from 'bignumber.js';
|
import { BigNumber } from 'bignumber.js';
|
||||||
import {RBTree} from 'bintrees';
|
import { RBTree } from 'bintrees';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {ZeroExError} from '../types';
|
import { ZeroExError } from '../types';
|
||||||
import {utils} from '../utils/utils';
|
import { utils } from '../utils/utils';
|
||||||
|
|
||||||
const DEFAULT_EXPIRATION_MARGIN_MS = 0;
|
const DEFAULT_EXPIRATION_MARGIN_MS = 0;
|
||||||
const DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS = 50;
|
const DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS = 50;
|
||||||
@ -15,16 +15,14 @@ const DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS = 50;
|
|||||||
*/
|
*/
|
||||||
export class ExpirationWatcher {
|
export class ExpirationWatcher {
|
||||||
private _orderHashByExpirationRBTree: RBTree<string>;
|
private _orderHashByExpirationRBTree: RBTree<string>;
|
||||||
private _expiration: {[orderHash: string]: BigNumber} = {};
|
private _expiration: { [orderHash: string]: BigNumber } = {};
|
||||||
private _orderExpirationCheckingIntervalMs: number;
|
private _orderExpirationCheckingIntervalMs: number;
|
||||||
private _expirationMarginMs: number;
|
private _expirationMarginMs: number;
|
||||||
private _orderExpirationCheckingIntervalIdIfExists?: NodeJS.Timer;
|
private _orderExpirationCheckingIntervalIdIfExists?: NodeJS.Timer;
|
||||||
constructor(expirationMarginIfExistsMs?: number,
|
constructor(expirationMarginIfExistsMs?: number, orderExpirationCheckingIntervalIfExistsMs?: number) {
|
||||||
orderExpirationCheckingIntervalIfExistsMs?: number) {
|
this._expirationMarginMs = expirationMarginIfExistsMs || DEFAULT_EXPIRATION_MARGIN_MS;
|
||||||
this._expirationMarginMs = expirationMarginIfExistsMs ||
|
this._orderExpirationCheckingIntervalMs =
|
||||||
DEFAULT_EXPIRATION_MARGIN_MS;
|
expirationMarginIfExistsMs || DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS;
|
||||||
this._orderExpirationCheckingIntervalMs = expirationMarginIfExistsMs ||
|
|
||||||
DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS;
|
|
||||||
const scoreFunction = (orderHash: string) => this._expiration[orderHash].toNumber();
|
const scoreFunction = (orderHash: string) => this._expiration[orderHash].toNumber();
|
||||||
const comparator = (lhs: string, rhs: string) => scoreFunction(lhs) - scoreFunction(rhs);
|
const comparator = (lhs: string, rhs: string) => scoreFunction(lhs) - scoreFunction(rhs);
|
||||||
this._orderHashByExpirationRBTree = new RBTree(comparator);
|
this._orderHashByExpirationRBTree = new RBTree(comparator);
|
||||||
@ -34,7 +32,8 @@ export class ExpirationWatcher {
|
|||||||
throw new Error(ZeroExError.SubscriptionAlreadyPresent);
|
throw new Error(ZeroExError.SubscriptionAlreadyPresent);
|
||||||
}
|
}
|
||||||
this._orderExpirationCheckingIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
|
this._orderExpirationCheckingIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
|
||||||
this._pruneExpiredOrders.bind(this, callback), this._orderExpirationCheckingIntervalMs,
|
this._pruneExpiredOrders.bind(this, callback),
|
||||||
|
this._orderExpirationCheckingIntervalMs,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public unsubscribe(): void {
|
public unsubscribe(): void {
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import {schemas} from '@0xproject/json-schemas';
|
import { schemas } from '@0xproject/json-schemas';
|
||||||
import {intervalUtils} from '@0xproject/utils';
|
import { intervalUtils } from '@0xproject/utils';
|
||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {ZeroEx} from '../0x';
|
import { ZeroEx } from '../0x';
|
||||||
import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper';
|
import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper';
|
||||||
import {TokenWrapper} from '../contract_wrappers/token_wrapper';
|
import { TokenWrapper } from '../contract_wrappers/token_wrapper';
|
||||||
import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store';
|
import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allowance_lazy_store';
|
||||||
import {OrderFilledCancelledLazyStore} from '../stores/order_filled_cancelled_lazy_store';
|
import { OrderFilledCancelledLazyStore } from '../stores/order_filled_cancelled_lazy_store';
|
||||||
import {
|
import {
|
||||||
ApprovalContractEventArgs,
|
ApprovalContractEventArgs,
|
||||||
BlockParamLiteral,
|
BlockParamLiteral,
|
||||||
@ -29,13 +29,13 @@ import {
|
|||||||
WithdrawalContractEventArgs,
|
WithdrawalContractEventArgs,
|
||||||
ZeroExError,
|
ZeroExError,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import {AbiDecoder} from '../utils/abi_decoder';
|
import { AbiDecoder } from '../utils/abi_decoder';
|
||||||
import {assert} from '../utils/assert';
|
import { assert } from '../utils/assert';
|
||||||
import {OrderStateUtils} from '../utils/order_state_utils';
|
import { OrderStateUtils } from '../utils/order_state_utils';
|
||||||
import {utils} from '../utils/utils';
|
import { utils } from '../utils/utils';
|
||||||
|
|
||||||
import {EventWatcher} from './event_watcher';
|
import { EventWatcher } from './event_watcher';
|
||||||
import {ExpirationWatcher} from './expiration_watcher';
|
import { ExpirationWatcher } from './expiration_watcher';
|
||||||
|
|
||||||
interface DependentOrderHashes {
|
interface DependentOrderHashes {
|
||||||
[makerAddress: string]: {
|
[makerAddress: string]: {
|
||||||
@ -74,7 +74,10 @@ export class OrderStateWatcher {
|
|||||||
private _cleanupJobInterval: number;
|
private _cleanupJobInterval: number;
|
||||||
private _cleanupJobIntervalIdIfExists?: NodeJS.Timer;
|
private _cleanupJobIntervalIdIfExists?: NodeJS.Timer;
|
||||||
constructor(
|
constructor(
|
||||||
web3Wrapper: Web3Wrapper, abiDecoder: AbiDecoder, token: TokenWrapper, exchange: ExchangeWrapper,
|
web3Wrapper: Web3Wrapper,
|
||||||
|
abiDecoder: AbiDecoder,
|
||||||
|
token: TokenWrapper,
|
||||||
|
exchange: ExchangeWrapper,
|
||||||
config?: OrderStateWatcherConfig,
|
config?: OrderStateWatcherConfig,
|
||||||
) {
|
) {
|
||||||
this._abiDecoder = abiDecoder;
|
this._abiDecoder = abiDecoder;
|
||||||
@ -82,24 +85,26 @@ export class OrderStateWatcher {
|
|||||||
const pollingIntervalIfExistsMs = _.isUndefined(config) ? undefined : config.eventPollingIntervalMs;
|
const pollingIntervalIfExistsMs = _.isUndefined(config) ? undefined : config.eventPollingIntervalMs;
|
||||||
this._eventWatcher = new EventWatcher(web3Wrapper, pollingIntervalIfExistsMs);
|
this._eventWatcher = new EventWatcher(web3Wrapper, pollingIntervalIfExistsMs);
|
||||||
this._balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
this._balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
|
||||||
token, BlockParamLiteral.Pending,
|
token,
|
||||||
|
BlockParamLiteral.Pending,
|
||||||
);
|
);
|
||||||
this._orderFilledCancelledLazyStore = new OrderFilledCancelledLazyStore(exchange);
|
this._orderFilledCancelledLazyStore = new OrderFilledCancelledLazyStore(exchange);
|
||||||
this._orderStateUtils = new OrderStateUtils(
|
this._orderStateUtils = new OrderStateUtils(
|
||||||
this._balanceAndProxyAllowanceLazyStore, this._orderFilledCancelledLazyStore,
|
this._balanceAndProxyAllowanceLazyStore,
|
||||||
|
this._orderFilledCancelledLazyStore,
|
||||||
);
|
);
|
||||||
const orderExpirationCheckingIntervalMsIfExists = _.isUndefined(config) ?
|
const orderExpirationCheckingIntervalMsIfExists = _.isUndefined(config)
|
||||||
undefined :
|
? undefined
|
||||||
config.orderExpirationCheckingIntervalMs;
|
: config.orderExpirationCheckingIntervalMs;
|
||||||
const expirationMarginIfExistsMs = _.isUndefined(config) ?
|
const expirationMarginIfExistsMs = _.isUndefined(config) ? undefined : config.expirationMarginMs;
|
||||||
undefined :
|
|
||||||
config.expirationMarginMs;
|
|
||||||
this._expirationWatcher = new ExpirationWatcher(
|
this._expirationWatcher = new ExpirationWatcher(
|
||||||
expirationMarginIfExistsMs, orderExpirationCheckingIntervalMsIfExists,
|
expirationMarginIfExistsMs,
|
||||||
|
orderExpirationCheckingIntervalMsIfExists,
|
||||||
);
|
);
|
||||||
this._cleanupJobInterval = _.isUndefined(config) || _.isUndefined(config.cleanupJobIntervalMs) ?
|
this._cleanupJobInterval =
|
||||||
DEFAULT_CLEANUP_JOB_INTERVAL_MS :
|
_.isUndefined(config) || _.isUndefined(config.cleanupJobIntervalMs)
|
||||||
config.cleanupJobIntervalMs;
|
? DEFAULT_CLEANUP_JOB_INTERVAL_MS
|
||||||
|
: config.cleanupJobIntervalMs;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Add an order to the orderStateWatcher. Before the order is added, it's
|
* Add an order to the orderStateWatcher. Before the order is added, it's
|
||||||
@ -148,7 +153,8 @@ export class OrderStateWatcher {
|
|||||||
this._eventWatcher.subscribe(this._onEventWatcherCallbackAsync.bind(this));
|
this._eventWatcher.subscribe(this._onEventWatcherCallbackAsync.bind(this));
|
||||||
this._expirationWatcher.subscribe(this._onOrderExpired.bind(this));
|
this._expirationWatcher.subscribe(this._onOrderExpired.bind(this));
|
||||||
this._cleanupJobIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
|
this._cleanupJobIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
|
||||||
this._cleanupAsync.bind(this), this._cleanupJobInterval,
|
this._cleanupAsync.bind(this),
|
||||||
|
this._cleanupJobInterval,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -215,23 +221,23 @@ export class OrderStateWatcher {
|
|||||||
let makerToken: string;
|
let makerToken: string;
|
||||||
let makerAddress: string;
|
let makerAddress: string;
|
||||||
switch (decodedLog.event) {
|
switch (decodedLog.event) {
|
||||||
case TokenEvents.Approval:
|
case TokenEvents.Approval: {
|
||||||
{
|
|
||||||
// Invalidate cache
|
// Invalidate cache
|
||||||
const args = decodedLog.args as ApprovalContractEventArgs;
|
const args = decodedLog.args as ApprovalContractEventArgs;
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(decodedLog.address, args._owner);
|
this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(decodedLog.address, args._owner);
|
||||||
// Revalidate orders
|
// Revalidate orders
|
||||||
makerToken = decodedLog.address;
|
makerToken = decodedLog.address;
|
||||||
makerAddress = args._owner;
|
makerAddress = args._owner;
|
||||||
if (!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
|
if (
|
||||||
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])) {
|
!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
|
||||||
|
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])
|
||||||
|
) {
|
||||||
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
|
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
|
||||||
await this._emitRevalidateOrdersAsync(orderHashes);
|
await this._emitRevalidateOrdersAsync(orderHashes);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TokenEvents.Transfer:
|
case TokenEvents.Transfer: {
|
||||||
{
|
|
||||||
// Invalidate cache
|
// Invalidate cache
|
||||||
const args = decodedLog.args as TransferContractEventArgs;
|
const args = decodedLog.args as TransferContractEventArgs;
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._from);
|
this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._from);
|
||||||
@ -239,45 +245,48 @@ export class OrderStateWatcher {
|
|||||||
// Revalidate orders
|
// Revalidate orders
|
||||||
makerToken = decodedLog.address;
|
makerToken = decodedLog.address;
|
||||||
makerAddress = args._from;
|
makerAddress = args._from;
|
||||||
if (!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
|
if (
|
||||||
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])) {
|
!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
|
||||||
|
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])
|
||||||
|
) {
|
||||||
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
|
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
|
||||||
await this._emitRevalidateOrdersAsync(orderHashes);
|
await this._emitRevalidateOrdersAsync(orderHashes);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EtherTokenEvents.Deposit:
|
case EtherTokenEvents.Deposit: {
|
||||||
{
|
|
||||||
// Invalidate cache
|
// Invalidate cache
|
||||||
const args = decodedLog.args as DepositContractEventArgs;
|
const args = decodedLog.args as DepositContractEventArgs;
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._owner);
|
this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._owner);
|
||||||
// Revalidate orders
|
// Revalidate orders
|
||||||
makerToken = decodedLog.address;
|
makerToken = decodedLog.address;
|
||||||
makerAddress = args._owner;
|
makerAddress = args._owner;
|
||||||
if (!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
|
if (
|
||||||
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])) {
|
!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
|
||||||
|
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])
|
||||||
|
) {
|
||||||
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
|
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
|
||||||
await this._emitRevalidateOrdersAsync(orderHashes);
|
await this._emitRevalidateOrdersAsync(orderHashes);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EtherTokenEvents.Withdrawal:
|
case EtherTokenEvents.Withdrawal: {
|
||||||
{
|
|
||||||
// Invalidate cache
|
// Invalidate cache
|
||||||
const args = decodedLog.args as WithdrawalContractEventArgs;
|
const args = decodedLog.args as WithdrawalContractEventArgs;
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._owner);
|
this._balanceAndProxyAllowanceLazyStore.deleteBalance(decodedLog.address, args._owner);
|
||||||
// Revalidate orders
|
// Revalidate orders
|
||||||
makerToken = decodedLog.address;
|
makerToken = decodedLog.address;
|
||||||
makerAddress = args._owner;
|
makerAddress = args._owner;
|
||||||
if (!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
|
if (
|
||||||
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])) {
|
!_.isUndefined(this._dependentOrderHashes[makerAddress]) &&
|
||||||
|
!_.isUndefined(this._dependentOrderHashes[makerAddress][makerToken])
|
||||||
|
) {
|
||||||
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
|
const orderHashes = Array.from(this._dependentOrderHashes[makerAddress][makerToken]);
|
||||||
await this._emitRevalidateOrdersAsync(orderHashes);
|
await this._emitRevalidateOrdersAsync(orderHashes);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ExchangeEvents.LogFill:
|
case ExchangeEvents.LogFill: {
|
||||||
{
|
|
||||||
// Invalidate cache
|
// Invalidate cache
|
||||||
const args = decodedLog.args as LogFillContractEventArgs;
|
const args = decodedLog.args as LogFillContractEventArgs;
|
||||||
this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(args.orderHash);
|
this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(args.orderHash);
|
||||||
@ -289,8 +298,7 @@ export class OrderStateWatcher {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ExchangeEvents.LogCancel:
|
case ExchangeEvents.LogCancel: {
|
||||||
{
|
|
||||||
// Invalidate cache
|
// Invalidate cache
|
||||||
const args = decodedLog.args as LogCancelContractEventArgs;
|
const args = decodedLog.args as LogCancelContractEventArgs;
|
||||||
this._orderFilledCancelledLazyStore.deleteCancelledTakerAmount(args.orderHash);
|
this._orderFilledCancelledLazyStore.deleteCancelledTakerAmount(args.orderHash);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import {BigNumber} from 'bignumber.js';
|
import { BigNumber } from 'bignumber.js';
|
||||||
|
|
||||||
import {SignedOrder} from '../types';
|
import { SignedOrder } from '../types';
|
||||||
|
|
||||||
export class RemainingFillableCalculator {
|
export class RemainingFillableCalculator {
|
||||||
private _signedOrder: SignedOrder;
|
private _signedOrder: SignedOrder;
|
||||||
@ -10,18 +10,21 @@ export class RemainingFillableCalculator {
|
|||||||
private _transferrableMakerFeeTokenAmount: BigNumber;
|
private _transferrableMakerFeeTokenAmount: BigNumber;
|
||||||
private _remainingMakerTokenAmount: BigNumber;
|
private _remainingMakerTokenAmount: BigNumber;
|
||||||
private _remainingMakerFeeAmount: BigNumber;
|
private _remainingMakerFeeAmount: BigNumber;
|
||||||
constructor(signedOrder: SignedOrder,
|
constructor(
|
||||||
isMakerTokenZRX: boolean,
|
signedOrder: SignedOrder,
|
||||||
transferrableMakerTokenAmount: BigNumber,
|
isMakerTokenZRX: boolean,
|
||||||
transferrableMakerFeeTokenAmount: BigNumber,
|
transferrableMakerTokenAmount: BigNumber,
|
||||||
remainingMakerTokenAmount: BigNumber) {
|
transferrableMakerFeeTokenAmount: BigNumber,
|
||||||
|
remainingMakerTokenAmount: BigNumber,
|
||||||
|
) {
|
||||||
this._signedOrder = signedOrder;
|
this._signedOrder = signedOrder;
|
||||||
this._isMakerTokenZRX = isMakerTokenZRX;
|
this._isMakerTokenZRX = isMakerTokenZRX;
|
||||||
this._transferrableMakerTokenAmount = transferrableMakerTokenAmount;
|
this._transferrableMakerTokenAmount = transferrableMakerTokenAmount;
|
||||||
this._transferrableMakerFeeTokenAmount = transferrableMakerFeeTokenAmount;
|
this._transferrableMakerFeeTokenAmount = transferrableMakerFeeTokenAmount;
|
||||||
this._remainingMakerTokenAmount = remainingMakerTokenAmount;
|
this._remainingMakerTokenAmount = remainingMakerTokenAmount;
|
||||||
this._remainingMakerFeeAmount = remainingMakerTokenAmount.times(signedOrder.makerFee)
|
this._remainingMakerFeeAmount = remainingMakerTokenAmount
|
||||||
.dividedToIntegerBy(signedOrder.makerTokenAmount);
|
.times(signedOrder.makerFee)
|
||||||
|
.dividedToIntegerBy(signedOrder.makerTokenAmount);
|
||||||
}
|
}
|
||||||
public computeRemainingMakerFillable(): BigNumber {
|
public computeRemainingMakerFillable(): BigNumber {
|
||||||
if (this._hasSufficientFundsForFeeAndTransferAmount()) {
|
if (this._hasSufficientFundsForFeeAndTransferAmount()) {
|
||||||
@ -33,20 +36,24 @@ export class RemainingFillableCalculator {
|
|||||||
return this._calculatePartiallyFillableMakerTokenAmount();
|
return this._calculatePartiallyFillableMakerTokenAmount();
|
||||||
}
|
}
|
||||||
public computeRemainingTakerFillable(): BigNumber {
|
public computeRemainingTakerFillable(): BigNumber {
|
||||||
return this.computeRemainingMakerFillable().times(this._signedOrder.takerTokenAmount)
|
return this.computeRemainingMakerFillable()
|
||||||
.dividedToIntegerBy(this._signedOrder.makerTokenAmount);
|
.times(this._signedOrder.takerTokenAmount)
|
||||||
|
.dividedToIntegerBy(this._signedOrder.makerTokenAmount);
|
||||||
}
|
}
|
||||||
private _hasSufficientFundsForFeeAndTransferAmount(): boolean {
|
private _hasSufficientFundsForFeeAndTransferAmount(): boolean {
|
||||||
if (this._isMakerTokenZRX) {
|
if (this._isMakerTokenZRX) {
|
||||||
const totalZRXTransferAmountRequired = this._remainingMakerTokenAmount.plus(this._remainingMakerFeeAmount);
|
const totalZRXTransferAmountRequired = this._remainingMakerTokenAmount.plus(this._remainingMakerFeeAmount);
|
||||||
const hasSufficientFunds = this._transferrableMakerTokenAmount.greaterThanOrEqualTo(
|
const hasSufficientFunds = this._transferrableMakerTokenAmount.greaterThanOrEqualTo(
|
||||||
totalZRXTransferAmountRequired);
|
totalZRXTransferAmountRequired,
|
||||||
|
);
|
||||||
return hasSufficientFunds;
|
return hasSufficientFunds;
|
||||||
} else {
|
} else {
|
||||||
const hasSufficientFundsForTransferAmount = this._transferrableMakerTokenAmount.greaterThanOrEqualTo(
|
const hasSufficientFundsForTransferAmount = this._transferrableMakerTokenAmount.greaterThanOrEqualTo(
|
||||||
this._remainingMakerTokenAmount);
|
this._remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
const hasSufficientFundsForFeeAmount = this._transferrableMakerFeeTokenAmount.greaterThanOrEqualTo(
|
const hasSufficientFundsForFeeAmount = this._transferrableMakerFeeTokenAmount.greaterThanOrEqualTo(
|
||||||
this._remainingMakerFeeAmount);
|
this._remainingMakerFeeAmount,
|
||||||
|
);
|
||||||
const hasSufficientFunds = hasSufficientFundsForTransferAmount && hasSufficientFundsForFeeAmount;
|
const hasSufficientFunds = hasSufficientFundsForTransferAmount && hasSufficientFundsForFeeAmount;
|
||||||
return hasSufficientFunds;
|
return hasSufficientFunds;
|
||||||
}
|
}
|
||||||
@ -57,8 +64,10 @@ export class RemainingFillableCalculator {
|
|||||||
// The number of times the maker can fill the order, if each fill only required the transfer of a single
|
// The number of times the maker can fill the order, if each fill only required the transfer of a single
|
||||||
// baseUnit of fee tokens.
|
// baseUnit of fee tokens.
|
||||||
// Given 2 ZRXwei, the maximum amount of times Maker can fill this order, in terms of fees, is 2
|
// 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,
|
const fillableTimesInFeeTokenBaseUnits = BigNumber.min(
|
||||||
this._remainingMakerFeeAmount);
|
this._transferrableMakerFeeTokenAmount,
|
||||||
|
this._remainingMakerFeeAmount,
|
||||||
|
);
|
||||||
// The number of times the Maker can fill the order, given the Maker Token Balance
|
// 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.
|
// 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);
|
let fillableTimesInMakerTokenUnits = this._transferrableMakerTokenAmount.dividedBy(orderToFeeRatio);
|
||||||
@ -68,20 +77,20 @@ export class RemainingFillableCalculator {
|
|||||||
const totalZRXTokenPooled = this._transferrableMakerTokenAmount;
|
const totalZRXTokenPooled = this._transferrableMakerTokenAmount;
|
||||||
// The purchasing power here is less as the tokens are taken from the same Pool
|
// 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
|
// For every one number of fills, we have to take an extra ZRX out of the pool
|
||||||
fillableTimesInMakerTokenUnits = totalZRXTokenPooled.dividedBy(
|
fillableTimesInMakerTokenUnits = totalZRXTokenPooled.dividedBy(orderToFeeRatio.plus(new BigNumber(1)));
|
||||||
orderToFeeRatio.plus(new BigNumber(1)));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
// When Ratio is not fully divisible there can be remainders which cannot be represented, so they are floored.
|
// 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.
|
// This can result in a RoundingError being thrown by the Exchange Contract.
|
||||||
const partiallyFillableMakerTokenAmount = fillableTimesInMakerTokenUnits
|
const partiallyFillableMakerTokenAmount = fillableTimesInMakerTokenUnits
|
||||||
.times(this._signedOrder.makerTokenAmount)
|
.times(this._signedOrder.makerTokenAmount)
|
||||||
.dividedToIntegerBy(this._signedOrder.makerFee);
|
.dividedToIntegerBy(this._signedOrder.makerFee);
|
||||||
const partiallyFillableFeeTokenAmount = fillableTimesInFeeTokenBaseUnits
|
const partiallyFillableFeeTokenAmount = fillableTimesInFeeTokenBaseUnits
|
||||||
.times(this._signedOrder.makerTokenAmount)
|
.times(this._signedOrder.makerTokenAmount)
|
||||||
.dividedToIntegerBy(this._signedOrder.makerFee);
|
.dividedToIntegerBy(this._signedOrder.makerFee);
|
||||||
const partiallyFillableAmount = BigNumber.min(partiallyFillableMakerTokenAmount,
|
const partiallyFillableAmount = BigNumber.min(
|
||||||
partiallyFillableFeeTokenAmount);
|
partiallyFillableMakerTokenAmount,
|
||||||
|
partiallyFillableFeeTokenAmount,
|
||||||
|
);
|
||||||
return partiallyFillableAmount;
|
return partiallyFillableAmount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,9 @@ export const zeroExConfigSchema = {
|
|||||||
type: 'number',
|
type: 'number',
|
||||||
minimum: 0,
|
minimum: 0,
|
||||||
},
|
},
|
||||||
gasPrice: {$ref: '/Number'},
|
gasPrice: { $ref: '/Number' },
|
||||||
exchangeContractAddress: {$ref: '/Address'},
|
exchangeContractAddress: { $ref: '/Address' },
|
||||||
tokenRegistryContractAddress: {$ref: '/Address'},
|
tokenRegistryContractAddress: { $ref: '/Address' },
|
||||||
orderWatcherConfig: {
|
orderWatcherConfig: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import {BigNumber} from 'bignumber.js';
|
import { BigNumber } from 'bignumber.js';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {TokenWrapper} from '../contract_wrappers/token_wrapper';
|
import { TokenWrapper } from '../contract_wrappers/token_wrapper';
|
||||||
import {BlockParamLiteral} from '../types';
|
import { BlockParamLiteral } from '../types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy on read store for balances/proxyAllowances of tokens/accounts
|
* Copy on read store for balances/proxyAllowances of tokens/accounts
|
||||||
@ -52,8 +52,10 @@ export class BalanceAndProxyAllowanceLazyStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> {
|
public async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise<BigNumber> {
|
||||||
if (_.isUndefined(this._proxyAllowance[tokenAddress]) ||
|
if (
|
||||||
_.isUndefined(this._proxyAllowance[tokenAddress][userAddress])) {
|
_.isUndefined(this._proxyAllowance[tokenAddress]) ||
|
||||||
|
_.isUndefined(this._proxyAllowance[tokenAddress][userAddress])
|
||||||
|
) {
|
||||||
const methodOpts = {
|
const methodOpts = {
|
||||||
defaultBlock: this._defaultBlock,
|
defaultBlock: this._defaultBlock,
|
||||||
};
|
};
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import {BigNumber} from 'bignumber.js';
|
import { BigNumber } from 'bignumber.js';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper';
|
import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper';
|
||||||
import {BlockParamLiteral} from '../types';
|
import { BlockParamLiteral } from '../types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy on read store for filled/cancelled taker amounts
|
* Copy on read store for filled/cancelled taker amounts
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {TransactionReceipt} from '@0xproject/types';
|
import { TransactionReceipt } from '@0xproject/types';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
@ -42,8 +42,7 @@ export interface ECSignature {
|
|||||||
|
|
||||||
export type OrderAddresses = [string, string, string, string, string];
|
export type OrderAddresses = [string, string, string, string, string];
|
||||||
|
|
||||||
export type OrderValues = [BigNumber, BigNumber, BigNumber,
|
export type OrderValues = [BigNumber, BigNumber, BigNumber, BigNumber, BigNumber, BigNumber];
|
||||||
BigNumber, BigNumber, BigNumber];
|
|
||||||
|
|
||||||
export type LogEvent = Web3.LogEntryEvent;
|
export type LogEvent = Web3.LogEntryEvent;
|
||||||
export interface DecodedLogEvent<ArgsType> {
|
export interface DecodedLogEvent<ArgsType> {
|
||||||
@ -51,7 +50,7 @@ export interface DecodedLogEvent<ArgsType> {
|
|||||||
log: LogWithDecodedArgs<ArgsType>;
|
log: LogWithDecodedArgs<ArgsType>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type EventCallback<ArgsType> = (err: null|Error, log?: DecodedLogEvent<ArgsType>) => void;
|
export type EventCallback<ArgsType> = (err: null | Error, log?: DecodedLogEvent<ArgsType>) => void;
|
||||||
export type EventWatcherCallback = (log: LogEvent) => void;
|
export type EventWatcherCallback = (log: LogEvent) => void;
|
||||||
|
|
||||||
export enum SolidityTypes {
|
export enum SolidityTypes {
|
||||||
@ -136,7 +135,10 @@ export interface LogErrorContractEventArgs {
|
|||||||
errorId: BigNumber;
|
errorId: BigNumber;
|
||||||
orderHash: string;
|
orderHash: string;
|
||||||
}
|
}
|
||||||
export type ExchangeContractEventArgs = LogFillContractEventArgs|LogCancelContractEventArgs|LogErrorContractEventArgs;
|
export type ExchangeContractEventArgs =
|
||||||
|
| LogFillContractEventArgs
|
||||||
|
| LogCancelContractEventArgs
|
||||||
|
| LogErrorContractEventArgs;
|
||||||
export interface TransferContractEventArgs {
|
export interface TransferContractEventArgs {
|
||||||
_from: string;
|
_from: string;
|
||||||
_to: string;
|
_to: string;
|
||||||
@ -155,10 +157,13 @@ export interface WithdrawalContractEventArgs {
|
|||||||
_owner: string;
|
_owner: string;
|
||||||
_value: BigNumber;
|
_value: BigNumber;
|
||||||
}
|
}
|
||||||
export type TokenContractEventArgs = TransferContractEventArgs|ApprovalContractEventArgs;
|
export type TokenContractEventArgs = TransferContractEventArgs | ApprovalContractEventArgs;
|
||||||
export type EtherTokenContractEventArgs = TokenContractEventArgs|DepositContractEventArgs|WithdrawalContractEventArgs;
|
export type EtherTokenContractEventArgs =
|
||||||
export type ContractEventArgs = ExchangeContractEventArgs|TokenContractEventArgs|EtherTokenContractEventArgs;
|
| TokenContractEventArgs
|
||||||
export type ContractEventArg = string|BigNumber;
|
| DepositContractEventArgs
|
||||||
|
| WithdrawalContractEventArgs;
|
||||||
|
export type ContractEventArgs = ExchangeContractEventArgs | TokenContractEventArgs | EtherTokenContractEventArgs;
|
||||||
|
export type ContractEventArg = string | BigNumber;
|
||||||
|
|
||||||
export interface Order {
|
export interface Order {
|
||||||
maker: string;
|
maker: string;
|
||||||
@ -211,14 +216,14 @@ export enum TokenEvents {
|
|||||||
Approval = 'Approval',
|
Approval = 'Approval',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum EtherTokenEvents {
|
export enum EtherTokenEvents {
|
||||||
Transfer = 'Transfer',
|
Transfer = 'Transfer',
|
||||||
Approval = 'Approval',
|
Approval = 'Approval',
|
||||||
Deposit = 'Deposit',
|
Deposit = 'Deposit',
|
||||||
Withdrawal = 'Withdrawal',
|
Withdrawal = 'Withdrawal',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ContractEvents = TokenEvents|ExchangeEvents|EtherTokenEvents;
|
export type ContractEvents = TokenEvents | ExchangeEvents | EtherTokenEvents;
|
||||||
|
|
||||||
export interface IndexedFilterValues {
|
export interface IndexedFilterValues {
|
||||||
[index: string]: ContractEventArg;
|
[index: string]: ContractEventArg;
|
||||||
@ -232,7 +237,7 @@ export enum BlockParamLiteral {
|
|||||||
Pending = 'pending',
|
Pending = 'pending',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BlockParam = BlockParamLiteral|number;
|
export type BlockParam = BlockParamLiteral | number;
|
||||||
|
|
||||||
export interface BlockRange {
|
export interface BlockRange {
|
||||||
fromBlock: BlockParam;
|
fromBlock: BlockParam;
|
||||||
@ -242,7 +247,7 @@ export interface BlockRange {
|
|||||||
export type DoneCallback = (err?: Error) => void;
|
export type DoneCallback = (err?: Error) => void;
|
||||||
|
|
||||||
export interface OrderCancellationRequest {
|
export interface OrderCancellationRequest {
|
||||||
order: Order|SignedOrder;
|
order: Order | SignedOrder;
|
||||||
takerTokenCancelAmount: BigNumber;
|
takerTokenCancelAmount: BigNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,10 +317,10 @@ export interface DecodedLogArgs {
|
|||||||
export interface LogWithDecodedArgs<ArgsType> extends Web3.DecodedLogEntry<ArgsType> {}
|
export interface LogWithDecodedArgs<ArgsType> extends Web3.DecodedLogEntry<ArgsType> {}
|
||||||
|
|
||||||
export interface TransactionReceiptWithDecodedLogs extends TransactionReceipt {
|
export interface TransactionReceiptWithDecodedLogs extends TransactionReceipt {
|
||||||
logs: Array<LogWithDecodedArgs<DecodedLogArgs>|Web3.LogEntry>;
|
logs: Array<LogWithDecodedArgs<DecodedLogArgs> | Web3.LogEntry>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ArtifactContractName = 'ZRX'|'TokenTransferProxy'|'TokenRegistry'|'Token'|'Exchange'|'EtherToken';
|
export type ArtifactContractName = 'ZRX' | 'TokenTransferProxy' | 'TokenRegistry' | 'Token' | 'Exchange' | 'EtherToken';
|
||||||
|
|
||||||
export interface Artifact {
|
export interface Artifact {
|
||||||
contract_name: ArtifactContractName;
|
contract_name: ArtifactContractName;
|
||||||
@ -399,7 +404,7 @@ export interface OrderStateInvalid {
|
|||||||
error: ExchangeContractErrs;
|
error: ExchangeContractErrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type OrderState = OrderStateValid|OrderStateInvalid;
|
export type OrderState = OrderStateValid | OrderStateInvalid;
|
||||||
|
|
||||||
export type OnOrderStateChangeCallback = (orderState: OrderState) => void;
|
export type OnOrderStateChangeCallback = (orderState: OrderState) => void;
|
||||||
// tslint:disable:max-file-line-count
|
// tslint:disable:max-file-line-count
|
||||||
|
@ -3,11 +3,11 @@ import * as _ from 'lodash';
|
|||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
import * as SolidityCoder from 'web3/lib/solidity/coder';
|
import * as SolidityCoder from 'web3/lib/solidity/coder';
|
||||||
|
|
||||||
import {AbiType, ContractEventArgs, DecodedLogArgs, LogWithDecodedArgs, RawLog, SolidityTypes} from '../types';
|
import { AbiType, ContractEventArgs, DecodedLogArgs, LogWithDecodedArgs, RawLog, SolidityTypes } from '../types';
|
||||||
|
|
||||||
export class AbiDecoder {
|
export class AbiDecoder {
|
||||||
private _savedABIs: Web3.AbiDefinition[] = [];
|
private _savedABIs: Web3.AbiDefinition[] = [];
|
||||||
private _methodIds: {[signatureHash: string]: Web3.EventAbi} = {};
|
private _methodIds: { [signatureHash: string]: Web3.EventAbi } = {};
|
||||||
private static _padZeros(address: string) {
|
private static _padZeros(address: string) {
|
||||||
let formatted = address;
|
let formatted = address;
|
||||||
if (_.startsWith(formatted, '0x')) {
|
if (_.startsWith(formatted, '0x')) {
|
||||||
@ -22,7 +22,8 @@ export class AbiDecoder {
|
|||||||
}
|
}
|
||||||
// This method can only decode logs from the 0x & ERC20 smart contracts
|
// This method can only decode logs from the 0x & ERC20 smart contracts
|
||||||
public tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>(
|
public tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>(
|
||||||
log: Web3.LogEntry): LogWithDecodedArgs<ArgsType>|RawLog {
|
log: Web3.LogEntry,
|
||||||
|
): LogWithDecodedArgs<ArgsType> | RawLog {
|
||||||
const methodId = log.topics[0];
|
const methodId = log.topics[0];
|
||||||
const event = this._methodIds[methodId];
|
const event = this._methodIds[methodId];
|
||||||
if (_.isUndefined(event)) {
|
if (_.isUndefined(event)) {
|
||||||
@ -42,9 +43,11 @@ export class AbiDecoder {
|
|||||||
let value = param.indexed ? log.topics[topicsIndex++] : decodedData[dataIndex++];
|
let value = param.indexed ? log.topics[topicsIndex++] : decodedData[dataIndex++];
|
||||||
if (param.type === SolidityTypes.Address) {
|
if (param.type === SolidityTypes.Address) {
|
||||||
value = AbiDecoder._padZeros(new BigNumber(value).toString(16));
|
value = AbiDecoder._padZeros(new BigNumber(value).toString(16));
|
||||||
} else if (param.type === SolidityTypes.Uint256 ||
|
} else if (
|
||||||
param.type === SolidityTypes.Uint8 ||
|
param.type === SolidityTypes.Uint256 ||
|
||||||
param.type === SolidityTypes.Uint) {
|
param.type === SolidityTypes.Uint8 ||
|
||||||
|
param.type === SolidityTypes.Uint
|
||||||
|
) {
|
||||||
value = new BigNumber(value);
|
value = new BigNumber(value);
|
||||||
}
|
}
|
||||||
decodedParams[param.name] = value;
|
decodedParams[param.name] = value;
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import {assert as sharedAssert} from '@0xproject/assert';
|
import { assert as sharedAssert } from '@0xproject/assert';
|
||||||
// We need those two unused imports because they're actually used by sharedAssert which gets injected here
|
// We need those two unused imports because they're actually used by sharedAssert which gets injected here
|
||||||
// tslint:disable-next-line:no-unused-variable
|
// tslint:disable-next-line:no-unused-variable
|
||||||
import {Schema} from '@0xproject/json-schemas';
|
import { Schema } from '@0xproject/json-schemas';
|
||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
// tslint:disable-next-line:no-unused-variable
|
// tslint:disable-next-line:no-unused-variable
|
||||||
import * as BigNumber from 'bignumber.js';
|
import * as BigNumber from 'bignumber.js';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {ECSignature} from '../types';
|
import { ECSignature } from '../types';
|
||||||
import {signatureUtils} from '../utils/signature_utils';
|
import { signatureUtils } from '../utils/signature_utils';
|
||||||
|
|
||||||
export const assert = {
|
export const assert = {
|
||||||
...sharedAssert,
|
...sharedAssert,
|
||||||
@ -16,11 +16,15 @@ export const assert = {
|
|||||||
const isValidSignature = signatureUtils.isValidSignature(orderHash, ecSignature, signerAddress);
|
const isValidSignature = signatureUtils.isValidSignature(orderHash, ecSignature, signerAddress);
|
||||||
this.assert(isValidSignature, `Expected order with hash '${orderHash}' to have a valid signature`);
|
this.assert(isValidSignature, `Expected order with hash '${orderHash}' to have a valid signature`);
|
||||||
},
|
},
|
||||||
async isSenderAddressAsync(variableName: string, senderAddressHex: string,
|
async isSenderAddressAsync(
|
||||||
web3Wrapper: Web3Wrapper): Promise<void> {
|
variableName: string,
|
||||||
|
senderAddressHex: string,
|
||||||
|
web3Wrapper: Web3Wrapper,
|
||||||
|
): Promise<void> {
|
||||||
sharedAssert.isETHAddressHex(variableName, senderAddressHex);
|
sharedAssert.isETHAddressHex(variableName, senderAddressHex);
|
||||||
const isSenderAddressAvailable = await web3Wrapper.isSenderAddressAvailableAsync(senderAddressHex);
|
const isSenderAddressAvailable = await web3Wrapper.isSenderAddressAvailableAsync(senderAddressHex);
|
||||||
sharedAssert.assert(isSenderAddressAvailable,
|
sharedAssert.assert(
|
||||||
|
isSenderAddressAvailable,
|
||||||
`Specified ${variableName} ${senderAddressHex} isn't available through the supplied web3 provider`,
|
`Specified ${variableName} ${senderAddressHex} isn't available through the supplied web3 provider`,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {AsyncMethod, SyncMethod, ZeroExError} from '../types';
|
import { AsyncMethod, SyncMethod, ZeroExError } from '../types';
|
||||||
|
|
||||||
import {constants} from './constants';
|
import { constants } from './constants';
|
||||||
|
|
||||||
type ErrorTransformer = (err: Error) => Error;
|
type ErrorTransformer = (err: Error) => Error;
|
||||||
|
|
||||||
@ -18,8 +18,8 @@ const contractCallErrorTransformer = (error: Error) => {
|
|||||||
|
|
||||||
const schemaErrorTransformer = (error: Error) => {
|
const schemaErrorTransformer = (error: Error) => {
|
||||||
if (_.includes(error.message, constants.INVALID_TAKER_FORMAT)) {
|
if (_.includes(error.message, constants.INVALID_TAKER_FORMAT)) {
|
||||||
// tslint:disable-next-line:max-line-length
|
const errMsg =
|
||||||
const errMsg = 'Order taker must be of type string. If you want anyone to be able to fill an order - pass ZeroEx.NULL_ADDRESS';
|
'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 new Error(errMsg);
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
@ -30,14 +30,16 @@ const schemaErrorTransformer = (error: Error) => {
|
|||||||
*/
|
*/
|
||||||
const asyncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
|
const asyncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
|
||||||
const asyncErrorHandlingDecorator = (
|
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
|
// Do not use arrow syntax here. Use a function expression in
|
||||||
// order to use the correct value of `this` in this method
|
// order to use the correct value of `this` in this method
|
||||||
// tslint:disable-next-line:only-arrow-functions
|
// tslint:disable-next-line:only-arrow-functions
|
||||||
descriptor.value = async function(...args: any[]) {
|
descriptor.value = async function(...args: any[]) {
|
||||||
try {
|
try {
|
||||||
const result = await originalMethod.apply(this, args);
|
const result = await originalMethod.apply(this, args);
|
||||||
return result;
|
return result;
|
||||||
@ -55,9 +57,11 @@ const asyncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
|
|||||||
|
|
||||||
const syncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
|
const syncErrorHandlerFactory = (errorTransformer: ErrorTransformer) => {
|
||||||
const syncErrorHandlingDecorator = (
|
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
|
// Do not use arrow syntax here. Use a function expression in
|
||||||
// order to use the correct value of `this` in this method
|
// order to use the correct value of `this` in this method
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {TokenWrapper} from '../contract_wrappers/token_wrapper';
|
import { TokenWrapper } from '../contract_wrappers/token_wrapper';
|
||||||
import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store';
|
import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allowance_lazy_store';
|
||||||
import {BlockParamLiteral, ExchangeContractErrs, TradeSide, TransferType} from '../types';
|
import { BlockParamLiteral, ExchangeContractErrs, TradeSide, TransferType } from '../types';
|
||||||
|
|
||||||
enum FailureReason {
|
enum FailureReason {
|
||||||
Balance = 'balance',
|
Balance = 'balance',
|
||||||
@ -36,8 +36,11 @@ const ERR_MSG_MAPPING = {
|
|||||||
export class ExchangeTransferSimulator {
|
export class ExchangeTransferSimulator {
|
||||||
private _store: BalanceAndProxyAllowanceLazyStore;
|
private _store: BalanceAndProxyAllowanceLazyStore;
|
||||||
private _UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber;
|
private _UNLIMITED_ALLOWANCE_IN_BASE_UNITS: BigNumber;
|
||||||
private static _throwValidationError(failureReason: FailureReason, tradeSide: TradeSide,
|
private static _throwValidationError(
|
||||||
transferType: TransferType): never {
|
failureReason: FailureReason,
|
||||||
|
tradeSide: TradeSide,
|
||||||
|
transferType: TransferType,
|
||||||
|
): never {
|
||||||
const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType];
|
const errMsg = ERR_MSG_MAPPING[failureReason][tradeSide][transferType];
|
||||||
throw new Error(errMsg);
|
throw new Error(errMsg);
|
||||||
}
|
}
|
||||||
@ -54,9 +57,14 @@ export class ExchangeTransferSimulator {
|
|||||||
* @param tradeSide Is Maker/Taker transferring
|
* @param tradeSide Is Maker/Taker transferring
|
||||||
* @param transferType Is it a fee payment or a value transfer
|
* @param transferType Is it a fee payment or a value transfer
|
||||||
*/
|
*/
|
||||||
public async transferFromAsync(tokenAddress: string, from: string, to: string,
|
public async transferFromAsync(
|
||||||
amountInBaseUnits: BigNumber, tradeSide: TradeSide,
|
tokenAddress: string,
|
||||||
transferType: TransferType): Promise<void> {
|
from: string,
|
||||||
|
to: string,
|
||||||
|
amountInBaseUnits: BigNumber,
|
||||||
|
tradeSide: TradeSide,
|
||||||
|
transferType: TransferType,
|
||||||
|
): Promise<void> {
|
||||||
const balance = await this._store.getBalanceAsync(tokenAddress, from);
|
const balance = await this._store.getBalanceAsync(tokenAddress, from);
|
||||||
const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, from);
|
const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, from);
|
||||||
if (proxyAllowance.lessThan(amountInBaseUnits)) {
|
if (proxyAllowance.lessThan(amountInBaseUnits)) {
|
||||||
@ -69,20 +77,29 @@ export class ExchangeTransferSimulator {
|
|||||||
await this._decreaseBalanceAsync(tokenAddress, from, amountInBaseUnits);
|
await this._decreaseBalanceAsync(tokenAddress, from, amountInBaseUnits);
|
||||||
await this._increaseBalanceAsync(tokenAddress, to, amountInBaseUnits);
|
await this._increaseBalanceAsync(tokenAddress, to, amountInBaseUnits);
|
||||||
}
|
}
|
||||||
private async _decreaseProxyAllowanceAsync(tokenAddress: string, userAddress: string,
|
private async _decreaseProxyAllowanceAsync(
|
||||||
amountInBaseUnits: BigNumber): Promise<void> {
|
tokenAddress: string,
|
||||||
|
userAddress: string,
|
||||||
|
amountInBaseUnits: BigNumber,
|
||||||
|
): Promise<void> {
|
||||||
const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, userAddress);
|
const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, userAddress);
|
||||||
if (!proxyAllowance.eq(this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
|
if (!proxyAllowance.eq(this._UNLIMITED_ALLOWANCE_IN_BASE_UNITS)) {
|
||||||
this._store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits));
|
this._store.setProxyAllowance(tokenAddress, userAddress, proxyAllowance.minus(amountInBaseUnits));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private async _increaseBalanceAsync(tokenAddress: string, userAddress: string,
|
private async _increaseBalanceAsync(
|
||||||
amountInBaseUnits: BigNumber): Promise<void> {
|
tokenAddress: string,
|
||||||
|
userAddress: string,
|
||||||
|
amountInBaseUnits: BigNumber,
|
||||||
|
): Promise<void> {
|
||||||
const balance = await this._store.getBalanceAsync(tokenAddress, userAddress);
|
const balance = await this._store.getBalanceAsync(tokenAddress, userAddress);
|
||||||
this._store.setBalance(tokenAddress, userAddress, balance.plus(amountInBaseUnits));
|
this._store.setBalance(tokenAddress, userAddress, balance.plus(amountInBaseUnits));
|
||||||
}
|
}
|
||||||
private async _decreaseBalanceAsync(tokenAddress: string, userAddress: string,
|
private async _decreaseBalanceAsync(
|
||||||
amountInBaseUnits: BigNumber): Promise<void> {
|
tokenAddress: string,
|
||||||
|
userAddress: string,
|
||||||
|
amountInBaseUnits: BigNumber,
|
||||||
|
): Promise<void> {
|
||||||
const balance = await this._store.getBalanceAsync(tokenAddress, userAddress);
|
const balance = await this._store.getBalanceAsync(tokenAddress, userAddress);
|
||||||
this._store.setBalance(tokenAddress, userAddress, balance.minus(amountInBaseUnits));
|
this._store.setBalance(tokenAddress, userAddress, balance.minus(amountInBaseUnits));
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import * as _ from 'lodash';
|
|||||||
import * as uuid from 'uuid/v4';
|
import * as uuid from 'uuid/v4';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import {BlockRange, ContractEvents, IndexedFilterValues} from '../types';
|
import { BlockRange, ContractEvents, IndexedFilterValues } from '../types';
|
||||||
|
|
||||||
const TOPIC_LENGTH = 32;
|
const TOPIC_LENGTH = 32;
|
||||||
|
|
||||||
@ -12,10 +12,14 @@ export const filterUtils = {
|
|||||||
generateUUID(): string {
|
generateUUID(): string {
|
||||||
return uuid();
|
return uuid();
|
||||||
},
|
},
|
||||||
getFilter(address: string, eventName: ContractEvents,
|
getFilter(
|
||||||
indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi,
|
address: string,
|
||||||
blockRange?: BlockRange): Web3.FilterObject {
|
eventName: ContractEvents,
|
||||||
const eventAbi = _.find(abi, {name: eventName}) as Web3.EventAbi;
|
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 eventSignature = filterUtils.getEventSignatureFromAbiByName(eventAbi, eventName);
|
||||||
const topicForEventSignature = ethUtil.addHexPrefix(jsSHA3.keccak256(eventSignature));
|
const topicForEventSignature = ethUtil.addHexPrefix(jsSHA3.keccak256(eventSignature));
|
||||||
const topicsForIndexedArgs = filterUtils.getTopicsForIndexedArgs(eventAbi, indexFilterValues);
|
const topicsForIndexedArgs = filterUtils.getTopicsForIndexedArgs(eventAbi, indexFilterValues);
|
||||||
@ -37,8 +41,8 @@ export const filterUtils = {
|
|||||||
const signature = `${eventAbi.name}(${types.join(',')})`;
|
const signature = `${eventAbi.name}(${types.join(',')})`;
|
||||||
return signature;
|
return signature;
|
||||||
},
|
},
|
||||||
getTopicsForIndexedArgs(abi: Web3.EventAbi, indexFilterValues: IndexedFilterValues): Array<string|null> {
|
getTopicsForIndexedArgs(abi: Web3.EventAbi, indexFilterValues: IndexedFilterValues): Array<string | null> {
|
||||||
const topics: Array<string|null> = [];
|
const topics: Array<string | null> = [];
|
||||||
for (const eventInput of abi.inputs) {
|
for (const eventInput of abi.inputs) {
|
||||||
if (!eventInput.indexed) {
|
if (!eventInput.indexed) {
|
||||||
continue;
|
continue;
|
||||||
@ -65,12 +69,12 @@ export const filterUtils = {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
matchesTopics(logTopics: string[], filterTopics: Array<string[]|string|null>): boolean {
|
matchesTopics(logTopics: string[], filterTopics: Array<string[] | string | null>): boolean {
|
||||||
const matchesTopic = _.zipWith(logTopics, filterTopics, filterUtils.matchesTopic.bind(filterUtils));
|
const matchesTopic = _.zipWith(logTopics, filterTopics, filterUtils.matchesTopic.bind(filterUtils));
|
||||||
const matchesTopics = _.every(matchesTopic);
|
const matchesTopics = _.every(matchesTopic);
|
||||||
return matchesTopics;
|
return matchesTopics;
|
||||||
},
|
},
|
||||||
matchesTopic(logTopic: string, filterTopic: string[]|string|null): boolean {
|
matchesTopic(logTopic: string, filterTopic: string[] | string | null): boolean {
|
||||||
if (_.isArray(filterTopic)) {
|
if (_.isArray(filterTopic)) {
|
||||||
return _.includes(filterTopic, logTopic);
|
return _.includes(filterTopic, logTopic);
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {ZeroEx} from '../0x';
|
import { ZeroEx } from '../0x';
|
||||||
import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper';
|
import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper';
|
||||||
import {RemainingFillableCalculator} from '../order_watcher/remaining_fillable_calculator';
|
import { RemainingFillableCalculator } from '../order_watcher/remaining_fillable_calculator';
|
||||||
import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store';
|
import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allowance_lazy_store';
|
||||||
import {OrderFilledCancelledLazyStore} from '../stores/order_filled_cancelled_lazy_store';
|
import { OrderFilledCancelledLazyStore } from '../stores/order_filled_cancelled_lazy_store';
|
||||||
import {
|
import {
|
||||||
ExchangeContractErrs,
|
ExchangeContractErrs,
|
||||||
OrderRelevantState,
|
OrderRelevantState,
|
||||||
@ -44,15 +44,20 @@ export class OrderStateUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const minFillableTakerTokenAmountWithinNoRoundingErrorRange = signedOrder.takerTokenAmount
|
const minFillableTakerTokenAmountWithinNoRoundingErrorRange = signedOrder.takerTokenAmount
|
||||||
.dividedBy(ACCEPTABLE_RELATIVE_ROUNDING_ERROR)
|
.dividedBy(ACCEPTABLE_RELATIVE_ROUNDING_ERROR)
|
||||||
.dividedBy(signedOrder.makerTokenAmount);
|
.dividedBy(signedOrder.makerTokenAmount);
|
||||||
if (orderRelevantState.remainingFillableTakerTokenAmount
|
if (
|
||||||
.lessThan(minFillableTakerTokenAmountWithinNoRoundingErrorRange)) {
|
orderRelevantState.remainingFillableTakerTokenAmount.lessThan(
|
||||||
|
minFillableTakerTokenAmountWithinNoRoundingErrorRange,
|
||||||
|
)
|
||||||
|
) {
|
||||||
throw new Error(ExchangeContractErrs.OrderFillRoundingError);
|
throw new Error(ExchangeContractErrs.OrderFillRoundingError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
constructor(balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore,
|
constructor(
|
||||||
orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore) {
|
balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore,
|
||||||
|
orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore,
|
||||||
|
) {
|
||||||
this._balanceAndProxyAllowanceLazyStore = balanceAndProxyAllowanceLazyStore;
|
this._balanceAndProxyAllowanceLazyStore = balanceAndProxyAllowanceLazyStore;
|
||||||
this._orderFilledCancelledLazyStore = orderFilledCancelledLazyStore;
|
this._orderFilledCancelledLazyStore = orderFilledCancelledLazyStore;
|
||||||
}
|
}
|
||||||
@ -85,16 +90,20 @@ export class OrderStateUtils {
|
|||||||
const zrxTokenAddress = exchange.getZRXTokenAddress();
|
const zrxTokenAddress = exchange.getZRXTokenAddress();
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
const makerBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync(
|
const makerBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync(
|
||||||
signedOrder.makerTokenAddress, signedOrder.maker,
|
signedOrder.makerTokenAddress,
|
||||||
|
signedOrder.maker,
|
||||||
);
|
);
|
||||||
const makerProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
|
const makerProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
|
||||||
signedOrder.makerTokenAddress, signedOrder.maker,
|
signedOrder.makerTokenAddress,
|
||||||
|
signedOrder.maker,
|
||||||
);
|
);
|
||||||
const makerFeeBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync(
|
const makerFeeBalance = await this._balanceAndProxyAllowanceLazyStore.getBalanceAsync(
|
||||||
zrxTokenAddress, signedOrder.maker,
|
zrxTokenAddress,
|
||||||
|
signedOrder.maker,
|
||||||
);
|
);
|
||||||
const makerFeeProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
|
const makerFeeProxyAllowance = await this._balanceAndProxyAllowanceLazyStore.getProxyAllowanceAsync(
|
||||||
zrxTokenAddress, signedOrder.maker,
|
zrxTokenAddress,
|
||||||
|
signedOrder.maker,
|
||||||
);
|
);
|
||||||
const filledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getFilledTakerAmountAsync(orderHash);
|
const filledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getFilledTakerAmountAsync(orderHash);
|
||||||
const cancelledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getCancelledTakerAmountAsync(
|
const cancelledTakerTokenAmount = await this._orderFilledCancelledLazyStore.getCancelledTakerAmountAsync(
|
||||||
@ -104,17 +113,20 @@ export class OrderStateUtils {
|
|||||||
const totalMakerTokenAmount = signedOrder.makerTokenAmount;
|
const totalMakerTokenAmount = signedOrder.makerTokenAmount;
|
||||||
const totalTakerTokenAmount = signedOrder.takerTokenAmount;
|
const totalTakerTokenAmount = signedOrder.takerTokenAmount;
|
||||||
const remainingTakerTokenAmount = totalTakerTokenAmount.minus(unavailableTakerTokenAmount);
|
const remainingTakerTokenAmount = totalTakerTokenAmount.minus(unavailableTakerTokenAmount);
|
||||||
const remainingMakerTokenAmount = remainingTakerTokenAmount.times(totalMakerTokenAmount)
|
const remainingMakerTokenAmount = remainingTakerTokenAmount
|
||||||
.dividedToIntegerBy(totalTakerTokenAmount);
|
.times(totalMakerTokenAmount)
|
||||||
|
.dividedToIntegerBy(totalTakerTokenAmount);
|
||||||
const transferrableMakerTokenAmount = BigNumber.min([makerProxyAllowance, makerBalance]);
|
const transferrableMakerTokenAmount = BigNumber.min([makerProxyAllowance, makerBalance]);
|
||||||
const transferrableFeeTokenAmount = BigNumber.min([makerFeeProxyAllowance, makerFeeBalance]);
|
const transferrableFeeTokenAmount = BigNumber.min([makerFeeProxyAllowance, makerFeeBalance]);
|
||||||
|
|
||||||
const isMakerTokenZRX = signedOrder.makerTokenAddress === zrxTokenAddress;
|
const isMakerTokenZRX = signedOrder.makerTokenAddress === zrxTokenAddress;
|
||||||
const remainingFillableCalculator = new RemainingFillableCalculator(signedOrder,
|
const remainingFillableCalculator = new RemainingFillableCalculator(
|
||||||
isMakerTokenZRX,
|
signedOrder,
|
||||||
transferrableMakerTokenAmount,
|
isMakerTokenZRX,
|
||||||
transferrableFeeTokenAmount,
|
transferrableMakerTokenAmount,
|
||||||
remainingMakerTokenAmount);
|
transferrableFeeTokenAmount,
|
||||||
|
remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
const remainingFillableMakerTokenAmount = remainingFillableCalculator.computeRemainingMakerFillable();
|
const remainingFillableMakerTokenAmount = remainingFillableCalculator.computeRemainingMakerFillable();
|
||||||
const remainingFillableTakerTokenAmount = remainingFillableCalculator.computeRemainingTakerFillable();
|
const remainingFillableTakerTokenAmount = remainingFillableCalculator.computeRemainingTakerFillable();
|
||||||
const orderRelevantState = {
|
const orderRelevantState = {
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {ZeroEx} from '../0x';
|
import { ZeroEx } from '../0x';
|
||||||
import {ExchangeWrapper} from '../contract_wrappers/exchange_wrapper';
|
import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper';
|
||||||
import {ExchangeContractErrs, Order, SignedOrder, TradeSide, TransferType, ZeroExError} from '../types';
|
import { ExchangeContractErrs, Order, SignedOrder, TradeSide, TransferType, ZeroExError } from '../types';
|
||||||
import {constants} from '../utils/constants';
|
import { constants } from '../utils/constants';
|
||||||
import {utils} from '../utils/utils';
|
import { utils } from '../utils/utils';
|
||||||
|
|
||||||
import {ExchangeTransferSimulator} from './exchange_transfer_simulator';
|
import { ExchangeTransferSimulator } from './exchange_transfer_simulator';
|
||||||
|
|
||||||
export class OrderValidationUtils {
|
export class OrderValidationUtils {
|
||||||
private _exchangeWrapper: ExchangeWrapper;
|
private _exchangeWrapper: ExchangeWrapper;
|
||||||
public static validateCancelOrderThrowIfInvalid(
|
public static validateCancelOrderThrowIfInvalid(
|
||||||
order: Order, cancelTakerTokenAmount: BigNumber, unavailableTakerTokenAmount: BigNumber,
|
order: Order,
|
||||||
|
cancelTakerTokenAmount: BigNumber,
|
||||||
|
unavailableTakerTokenAmount: BigNumber,
|
||||||
): void {
|
): void {
|
||||||
if (cancelTakerTokenAmount.eq(0)) {
|
if (cancelTakerTokenAmount.eq(0)) {
|
||||||
throw new Error(ExchangeContractErrs.OrderCancelAmountZero);
|
throw new Error(ExchangeContractErrs.OrderCancelAmountZero);
|
||||||
@ -26,8 +28,11 @@ export class OrderValidationUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static async validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
public static async validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
||||||
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder,
|
exchangeTradeEmulator: ExchangeTransferSimulator,
|
||||||
fillTakerTokenAmount: BigNumber, senderAddress: string, zrxTokenAddress: string,
|
signedOrder: SignedOrder,
|
||||||
|
fillTakerTokenAmount: BigNumber,
|
||||||
|
senderAddress: string,
|
||||||
|
zrxTokenAddress: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const fillMakerTokenAmount = OrderValidationUtils._getPartialAmount(
|
const fillMakerTokenAmount = OrderValidationUtils._getPartialAmount(
|
||||||
fillTakerTokenAmount,
|
fillTakerTokenAmount,
|
||||||
@ -35,12 +40,20 @@ export class OrderValidationUtils {
|
|||||||
signedOrder.makerTokenAmount,
|
signedOrder.makerTokenAmount,
|
||||||
);
|
);
|
||||||
await exchangeTradeEmulator.transferFromAsync(
|
await exchangeTradeEmulator.transferFromAsync(
|
||||||
signedOrder.makerTokenAddress, signedOrder.maker, senderAddress, fillMakerTokenAmount,
|
signedOrder.makerTokenAddress,
|
||||||
TradeSide.Maker, TransferType.Trade,
|
signedOrder.maker,
|
||||||
|
senderAddress,
|
||||||
|
fillMakerTokenAmount,
|
||||||
|
TradeSide.Maker,
|
||||||
|
TransferType.Trade,
|
||||||
);
|
);
|
||||||
await exchangeTradeEmulator.transferFromAsync(
|
await exchangeTradeEmulator.transferFromAsync(
|
||||||
signedOrder.takerTokenAddress, senderAddress, signedOrder.maker, fillTakerTokenAmount,
|
signedOrder.takerTokenAddress,
|
||||||
TradeSide.Taker, TransferType.Trade,
|
senderAddress,
|
||||||
|
signedOrder.maker,
|
||||||
|
fillTakerTokenAmount,
|
||||||
|
TradeSide.Taker,
|
||||||
|
TransferType.Trade,
|
||||||
);
|
);
|
||||||
const makerFeeAmount = OrderValidationUtils._getPartialAmount(
|
const makerFeeAmount = OrderValidationUtils._getPartialAmount(
|
||||||
fillTakerTokenAmount,
|
fillTakerTokenAmount,
|
||||||
@ -48,7 +61,11 @@ export class OrderValidationUtils {
|
|||||||
signedOrder.makerFee,
|
signedOrder.makerFee,
|
||||||
);
|
);
|
||||||
await exchangeTradeEmulator.transferFromAsync(
|
await exchangeTradeEmulator.transferFromAsync(
|
||||||
zrxTokenAddress, signedOrder.maker, signedOrder.feeRecipient, makerFeeAmount, TradeSide.Maker,
|
zrxTokenAddress,
|
||||||
|
signedOrder.maker,
|
||||||
|
signedOrder.feeRecipient,
|
||||||
|
makerFeeAmount,
|
||||||
|
TradeSide.Maker,
|
||||||
TransferType.Fee,
|
TransferType.Fee,
|
||||||
);
|
);
|
||||||
const takerFeeAmount = OrderValidationUtils._getPartialAmount(
|
const takerFeeAmount = OrderValidationUtils._getPartialAmount(
|
||||||
@ -57,12 +74,17 @@ export class OrderValidationUtils {
|
|||||||
signedOrder.takerFee,
|
signedOrder.takerFee,
|
||||||
);
|
);
|
||||||
await exchangeTradeEmulator.transferFromAsync(
|
await exchangeTradeEmulator.transferFromAsync(
|
||||||
zrxTokenAddress, senderAddress, signedOrder.feeRecipient, takerFeeAmount, TradeSide.Taker,
|
zrxTokenAddress,
|
||||||
|
senderAddress,
|
||||||
|
signedOrder.feeRecipient,
|
||||||
|
takerFeeAmount,
|
||||||
|
TradeSide.Taker,
|
||||||
TransferType.Fee,
|
TransferType.Fee,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
private static _validateRemainingFillAmountNotZeroOrThrow(
|
private static _validateRemainingFillAmountNotZeroOrThrow(
|
||||||
takerTokenAmount: BigNumber, unavailableTakerTokenAmount: BigNumber,
|
takerTokenAmount: BigNumber,
|
||||||
|
unavailableTakerTokenAmount: BigNumber,
|
||||||
) {
|
) {
|
||||||
if (takerTokenAmount.eq(unavailableTakerTokenAmount)) {
|
if (takerTokenAmount.eq(unavailableTakerTokenAmount)) {
|
||||||
throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
throw new Error(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
||||||
@ -74,24 +96,27 @@ export class OrderValidationUtils {
|
|||||||
throw new Error(ExchangeContractErrs.OrderFillExpired);
|
throw new Error(ExchangeContractErrs.OrderFillExpired);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static _getPartialAmount(numerator: BigNumber, denominator: BigNumber,
|
private static _getPartialAmount(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber {
|
||||||
target: BigNumber): BigNumber {
|
|
||||||
const fillMakerTokenAmount = numerator
|
const fillMakerTokenAmount = numerator
|
||||||
.mul(target)
|
.mul(target)
|
||||||
.div(denominator)
|
.div(denominator)
|
||||||
.round(0);
|
.round(0);
|
||||||
return fillMakerTokenAmount;
|
return fillMakerTokenAmount;
|
||||||
}
|
}
|
||||||
constructor(exchangeWrapper: ExchangeWrapper) {
|
constructor(exchangeWrapper: ExchangeWrapper) {
|
||||||
this._exchangeWrapper = exchangeWrapper;
|
this._exchangeWrapper = exchangeWrapper;
|
||||||
}
|
}
|
||||||
public async validateOrderFillableOrThrowAsync(
|
public async validateOrderFillableOrThrowAsync(
|
||||||
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder, zrxTokenAddress: string,
|
exchangeTradeEmulator: ExchangeTransferSimulator,
|
||||||
expectedFillTakerTokenAmount?: BigNumber): Promise<void> {
|
signedOrder: SignedOrder,
|
||||||
|
zrxTokenAddress: string,
|
||||||
|
expectedFillTakerTokenAmount?: BigNumber,
|
||||||
|
): Promise<void> {
|
||||||
const orderHash = utils.getOrderHashHex(signedOrder);
|
const orderHash = utils.getOrderHashHex(signedOrder);
|
||||||
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
||||||
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
|
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
|
||||||
signedOrder.takerTokenAmount, unavailableTakerTokenAmount,
|
signedOrder.takerTokenAmount,
|
||||||
|
unavailableTakerTokenAmount,
|
||||||
);
|
);
|
||||||
OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
|
OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
|
||||||
let fillTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
|
let fillTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
|
||||||
@ -104,8 +129,12 @@ export class OrderValidationUtils {
|
|||||||
signedOrder.makerTokenAmount,
|
signedOrder.makerTokenAmount,
|
||||||
);
|
);
|
||||||
await exchangeTradeEmulator.transferFromAsync(
|
await exchangeTradeEmulator.transferFromAsync(
|
||||||
signedOrder.makerTokenAddress, signedOrder.maker, signedOrder.taker, fillMakerTokenAmount,
|
signedOrder.makerTokenAddress,
|
||||||
TradeSide.Maker, TransferType.Trade,
|
signedOrder.maker,
|
||||||
|
signedOrder.taker,
|
||||||
|
fillMakerTokenAmount,
|
||||||
|
TradeSide.Maker,
|
||||||
|
TransferType.Trade,
|
||||||
);
|
);
|
||||||
const makerFeeAmount = OrderValidationUtils._getPartialAmount(
|
const makerFeeAmount = OrderValidationUtils._getPartialAmount(
|
||||||
fillTakerTokenAmount,
|
fillTakerTokenAmount,
|
||||||
@ -113,14 +142,21 @@ export class OrderValidationUtils {
|
|||||||
signedOrder.makerFee,
|
signedOrder.makerFee,
|
||||||
);
|
);
|
||||||
await exchangeTradeEmulator.transferFromAsync(
|
await exchangeTradeEmulator.transferFromAsync(
|
||||||
zrxTokenAddress, signedOrder.maker, signedOrder.feeRecipient, makerFeeAmount,
|
zrxTokenAddress,
|
||||||
TradeSide.Maker, TransferType.Fee,
|
signedOrder.maker,
|
||||||
|
signedOrder.feeRecipient,
|
||||||
|
makerFeeAmount,
|
||||||
|
TradeSide.Maker,
|
||||||
|
TransferType.Fee,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public async validateFillOrderThrowIfInvalidAsync(
|
public async validateFillOrderThrowIfInvalidAsync(
|
||||||
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder,
|
exchangeTradeEmulator: ExchangeTransferSimulator,
|
||||||
fillTakerTokenAmount: BigNumber, takerAddress: string,
|
signedOrder: SignedOrder,
|
||||||
zrxTokenAddress: string): Promise<BigNumber> {
|
fillTakerTokenAmount: BigNumber,
|
||||||
|
takerAddress: string,
|
||||||
|
zrxTokenAddress: string,
|
||||||
|
): Promise<BigNumber> {
|
||||||
if (fillTakerTokenAmount.eq(0)) {
|
if (fillTakerTokenAmount.eq(0)) {
|
||||||
throw new Error(ExchangeContractErrs.OrderFillAmountZero);
|
throw new Error(ExchangeContractErrs.OrderFillAmountZero);
|
||||||
}
|
}
|
||||||
@ -130,22 +166,29 @@ export class OrderValidationUtils {
|
|||||||
}
|
}
|
||||||
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
const unavailableTakerTokenAmount = await this._exchangeWrapper.getUnavailableTakerAmountAsync(orderHash);
|
||||||
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
|
OrderValidationUtils._validateRemainingFillAmountNotZeroOrThrow(
|
||||||
signedOrder.takerTokenAmount, unavailableTakerTokenAmount,
|
signedOrder.takerTokenAmount,
|
||||||
|
unavailableTakerTokenAmount,
|
||||||
);
|
);
|
||||||
if (signedOrder.taker !== constants.NULL_ADDRESS && signedOrder.taker !== takerAddress) {
|
if (signedOrder.taker !== constants.NULL_ADDRESS && signedOrder.taker !== takerAddress) {
|
||||||
throw new Error(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker);
|
throw new Error(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker);
|
||||||
}
|
}
|
||||||
OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
|
OrderValidationUtils._validateOrderNotExpiredOrThrow(signedOrder.expirationUnixTimestampSec);
|
||||||
const remainingTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
|
const remainingTakerTokenAmount = signedOrder.takerTokenAmount.minus(unavailableTakerTokenAmount);
|
||||||
const filledTakerTokenAmount = remainingTakerTokenAmount.lessThan(fillTakerTokenAmount) ?
|
const filledTakerTokenAmount = remainingTakerTokenAmount.lessThan(fillTakerTokenAmount)
|
||||||
remainingTakerTokenAmount :
|
? remainingTakerTokenAmount
|
||||||
fillTakerTokenAmount;
|
: fillTakerTokenAmount;
|
||||||
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
||||||
exchangeTradeEmulator, signedOrder, filledTakerTokenAmount, takerAddress, zrxTokenAddress,
|
exchangeTradeEmulator,
|
||||||
|
signedOrder,
|
||||||
|
filledTakerTokenAmount,
|
||||||
|
takerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
);
|
);
|
||||||
|
|
||||||
const wouldRoundingErrorOccur = await this._exchangeWrapper.isRoundingErrorAsync(
|
const wouldRoundingErrorOccur = await this._exchangeWrapper.isRoundingErrorAsync(
|
||||||
filledTakerTokenAmount, signedOrder.takerTokenAmount, signedOrder.makerTokenAmount,
|
filledTakerTokenAmount,
|
||||||
|
signedOrder.takerTokenAmount,
|
||||||
|
signedOrder.makerTokenAmount,
|
||||||
);
|
);
|
||||||
if (wouldRoundingErrorOccur) {
|
if (wouldRoundingErrorOccur) {
|
||||||
throw new Error(ExchangeContractErrs.OrderFillRoundingError);
|
throw new Error(ExchangeContractErrs.OrderFillRoundingError);
|
||||||
@ -153,10 +196,18 @@ export class OrderValidationUtils {
|
|||||||
return filledTakerTokenAmount;
|
return filledTakerTokenAmount;
|
||||||
}
|
}
|
||||||
public async validateFillOrKillOrderThrowIfInvalidAsync(
|
public async validateFillOrKillOrderThrowIfInvalidAsync(
|
||||||
exchangeTradeEmulator: ExchangeTransferSimulator, signedOrder: SignedOrder,
|
exchangeTradeEmulator: ExchangeTransferSimulator,
|
||||||
fillTakerTokenAmount: BigNumber, takerAddress: string, zrxTokenAddress: string): Promise<void> {
|
signedOrder: SignedOrder,
|
||||||
|
fillTakerTokenAmount: BigNumber,
|
||||||
|
takerAddress: string,
|
||||||
|
zrxTokenAddress: string,
|
||||||
|
): Promise<void> {
|
||||||
const filledTakerTokenAmount = await this.validateFillOrderThrowIfInvalidAsync(
|
const filledTakerTokenAmount = await this.validateFillOrderThrowIfInvalidAsync(
|
||||||
exchangeTradeEmulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress,
|
exchangeTradeEmulator,
|
||||||
|
signedOrder,
|
||||||
|
fillTakerTokenAmount,
|
||||||
|
takerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
);
|
);
|
||||||
if (filledTakerTokenAmount !== fillTakerTokenAmount) {
|
if (filledTakerTokenAmount !== fillTakerTokenAmount) {
|
||||||
throw new Error(ExchangeContractErrs.InsufficientRemainingFillAmount);
|
throw new Error(ExchangeContractErrs.InsufficientRemainingFillAmount);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as ethUtil from 'ethereumjs-util';
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
|
|
||||||
import {ECSignature} from '../types';
|
import { ECSignature } from '../types';
|
||||||
|
|
||||||
export const signatureUtils = {
|
export const signatureUtils = {
|
||||||
isValidSignature(data: string, signature: ECSignature, signerAddress: string): boolean {
|
isValidSignature(data: string, signature: ECSignature, signerAddress: string): boolean {
|
||||||
@ -11,7 +11,8 @@ export const signatureUtils = {
|
|||||||
msgHashBuff,
|
msgHashBuff,
|
||||||
signature.v,
|
signature.v,
|
||||||
ethUtil.toBuffer(signature.r),
|
ethUtil.toBuffer(signature.r),
|
||||||
ethUtil.toBuffer(signature.s));
|
ethUtil.toBuffer(signature.s),
|
||||||
|
);
|
||||||
const retrievedAddress = ethUtil.bufferToHex(ethUtil.pubToAddress(pubKey));
|
const retrievedAddress = ethUtil.bufferToHex(ethUtil.pubToAddress(pubKey));
|
||||||
return retrievedAddress === signerAddress;
|
return retrievedAddress === signerAddress;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -34,7 +35,7 @@ export const signatureUtils = {
|
|||||||
return ecSignature;
|
return ecSignature;
|
||||||
},
|
},
|
||||||
parseSignatureHexAsRSV(signatureHex: string): ECSignature {
|
parseSignatureHexAsRSV(signatureHex: string): ECSignature {
|
||||||
const {v, r, s} = ethUtil.fromRpcSig(signatureHex);
|
const { v, r, s } = ethUtil.fromRpcSig(signatureHex);
|
||||||
const ecSignature: ECSignature = {
|
const ecSignature: ECSignature = {
|
||||||
v,
|
v,
|
||||||
r: ethUtil.bufferToHex(r),
|
r: ethUtil.bufferToHex(r),
|
||||||
|
@ -4,7 +4,7 @@ import * as ethABI from 'ethereumjs-abi';
|
|||||||
import * as ethUtil from 'ethereumjs-util';
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {Order, SignedOrder, SolidityTypes} from '../types';
|
import { Order, SignedOrder, SolidityTypes } from '../types';
|
||||||
|
|
||||||
export const utils = {
|
export const utils = {
|
||||||
/**
|
/**
|
||||||
@ -29,20 +29,35 @@ export const utils = {
|
|||||||
spawnSwitchErr(name: string, value: any): Error {
|
spawnSwitchErr(name: string, value: any): Error {
|
||||||
return new Error(`Unexpected switch value: ${value} encountered for ${name}`);
|
return new Error(`Unexpected switch value: ${value} encountered for ${name}`);
|
||||||
},
|
},
|
||||||
getOrderHashHex(order: Order|SignedOrder): string {
|
getOrderHashHex(order: Order | SignedOrder): string {
|
||||||
const orderParts = [
|
const orderParts = [
|
||||||
{value: order.exchangeContractAddress, type: SolidityTypes.Address},
|
{ value: order.exchangeContractAddress, type: SolidityTypes.Address },
|
||||||
{value: order.maker, type: SolidityTypes.Address},
|
{ value: order.maker, type: SolidityTypes.Address },
|
||||||
{value: order.taker, type: SolidityTypes.Address},
|
{ value: order.taker, type: SolidityTypes.Address },
|
||||||
{value: order.makerTokenAddress, type: SolidityTypes.Address},
|
{ value: order.makerTokenAddress, type: SolidityTypes.Address },
|
||||||
{value: order.takerTokenAddress, type: SolidityTypes.Address},
|
{ value: order.takerTokenAddress, type: SolidityTypes.Address },
|
||||||
{value: order.feeRecipient, 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.makerTokenAmount),
|
||||||
{value: utils.bigNumberToBN(order.makerFee), type: SolidityTypes.Uint256},
|
type: SolidityTypes.Uint256,
|
||||||
{value: utils.bigNumberToBN(order.takerFee), type: SolidityTypes.Uint256},
|
},
|
||||||
{value: utils.bigNumberToBN(order.expirationUnixTimestampSec), type: SolidityTypes.Uint256},
|
{
|
||||||
{value: utils.bigNumberToBN(order.salt), type: SolidityTypes.Uint256},
|
value: utils.bigNumberToBN(order.takerTokenAmount),
|
||||||
|
type: SolidityTypes.Uint256,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: utils.bigNumberToBN(order.makerFee),
|
||||||
|
type: SolidityTypes.Uint256,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: utils.bigNumberToBN(order.takerFee),
|
||||||
|
type: SolidityTypes.Uint256,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: utils.bigNumberToBN(order.expirationUnixTimestampSec),
|
||||||
|
type: SolidityTypes.Uint256,
|
||||||
|
},
|
||||||
|
{ value: utils.bigNumberToBN(order.salt), type: SolidityTypes.Uint256 },
|
||||||
];
|
];
|
||||||
const types = _.map(orderParts, o => o.type);
|
const types = _.map(orderParts, o => o.type);
|
||||||
const values = _.map(orderParts, o => o.value);
|
const values = _.map(orderParts, o => o.value);
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import {BlockchainLifecycle} from '@0xproject/dev-utils';
|
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
import * as Sinon from 'sinon';
|
import * as Sinon from 'sinon';
|
||||||
|
|
||||||
import {ApprovalContractEventArgs, LogWithDecodedArgs, Order, TokenEvents, ZeroEx} from '../src';
|
import { ApprovalContractEventArgs, LogWithDecodedArgs, Order, TokenEvents, ZeroEx } from '../src';
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
import {TokenUtils} from './utils/token_utils';
|
import { TokenUtils } from './utils/token_utils';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
import { web3Factory } from './utils/web3_factory';
|
||||||
|
|
||||||
const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL);
|
const blockchainLifecycle = new BlockchainLifecycle(constants.RPC_URL);
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
@ -41,11 +41,11 @@ describe('ZeroEx library', () => {
|
|||||||
|
|
||||||
// Check that all nested web3 wrapper instances return the updated provider
|
// Check that all nested web3 wrapper instances return the updated provider
|
||||||
const nestedWeb3WrapperProvider = (zeroEx as any)._web3Wrapper.getCurrentProvider();
|
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();
|
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();
|
const tokenRegistryWeb3WrapperProvider = (zeroEx.tokenRegistry as any)._web3Wrapper.getCurrentProvider();
|
||||||
expect((tokenRegistryWeb3WrapperProvider).zeroExTestId).to.be.a('number');
|
expect(tokenRegistryWeb3WrapperProvider.zeroExTestId).to.be.a('number');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#isValidSignature', () => {
|
describe('#isValidSignature', () => {
|
||||||
@ -58,22 +58,25 @@ describe('ZeroEx library', () => {
|
|||||||
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
|
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
|
||||||
};
|
};
|
||||||
const address = '0x5409ed021d9299bf6814279a6a1411a7e866a631';
|
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();
|
expect(ZeroEx.isValidSignature('0x0', signature, address)).to.be.false();
|
||||||
return expect(
|
return expect(
|
||||||
(zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync('0x0', signature, address),
|
(zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync('0x0', signature, address),
|
||||||
).to.become(false);
|
).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';
|
const validUnrelatedAddress = '0x8b0292b11a196601ed2ce54b665cafeca0347d42';
|
||||||
expect(ZeroEx.isValidSignature(dataHex, signature, validUnrelatedAddress)).to.be.false();
|
expect(ZeroEx.isValidSignature(dataHex, signature, validUnrelatedAddress)).to.be.false();
|
||||||
return expect(
|
return expect(
|
||||||
(zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync(dataHex, signature,
|
(zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync(
|
||||||
validUnrelatedAddress),
|
dataHex,
|
||||||
|
signature,
|
||||||
|
validUnrelatedAddress,
|
||||||
|
),
|
||||||
).to.become(false);
|
).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});
|
const wrongSignature = _.assign({}, signature, { v: 28 });
|
||||||
expect(ZeroEx.isValidSignature(dataHex, wrongSignature, address)).to.be.false();
|
expect(ZeroEx.isValidSignature(dataHex, wrongSignature, address)).to.be.false();
|
||||||
return expect(
|
return expect(
|
||||||
(zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync(dataHex, wrongSignature, address),
|
(zeroEx.exchange as any)._isValidSignatureUsingContractCallAsync(dataHex, wrongSignature, address),
|
||||||
@ -117,8 +120,9 @@ describe('ZeroEx library', () => {
|
|||||||
it('should throw if invalid baseUnit amount supplied as argument', () => {
|
it('should throw if invalid baseUnit amount supplied as argument', () => {
|
||||||
const invalidBaseUnitAmount = new BigNumber(1000000000.4);
|
const invalidBaseUnitAmount = new BigNumber(1000000000.4);
|
||||||
const decimals = 6;
|
const decimals = 6;
|
||||||
expect(() => ZeroEx.toUnitAmount(invalidBaseUnitAmount, decimals))
|
expect(() => ZeroEx.toUnitAmount(invalidBaseUnitAmount, decimals)).to.throw(
|
||||||
.to.throw('amount should be in baseUnits (no decimals), found value: 1000000000.4');
|
'amount should be in baseUnits (no decimals), found value: 1000000000.4',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('Should return the expected unit amount for the decimals passed in', () => {
|
it('Should return the expected unit amount for the decimals passed in', () => {
|
||||||
const baseUnitAmount = new BigNumber(1000000000);
|
const baseUnitAmount = new BigNumber(1000000000);
|
||||||
@ -139,8 +143,9 @@ describe('ZeroEx library', () => {
|
|||||||
it('should throw if unitAmount has more decimals then specified as the max decimal precision', () => {
|
it('should throw if unitAmount has more decimals then specified as the max decimal precision', () => {
|
||||||
const unitAmount = new BigNumber(0.823091);
|
const unitAmount = new BigNumber(0.823091);
|
||||||
const decimals = 5;
|
const decimals = 5;
|
||||||
expect(() => ZeroEx.toBaseUnitAmount(unitAmount, decimals))
|
expect(() => ZeroEx.toBaseUnitAmount(unitAmount, decimals)).to.throw(
|
||||||
.to.throw('Invalid unit amount: 0.823091 - Too many decimal places');
|
'Invalid unit amount: 0.823091 - Too many decimal places',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#getOrderHashHex', () => {
|
describe('#getOrderHashHex', () => {
|
||||||
@ -167,10 +172,10 @@ describe('ZeroEx library', () => {
|
|||||||
it('throws a readable error message if taker format is invalid', async () => {
|
it('throws a readable error message if taker format is invalid', async () => {
|
||||||
const orderWithInvalidtakerFormat = {
|
const orderWithInvalidtakerFormat = {
|
||||||
...order,
|
...order,
|
||||||
taker: null as any as string,
|
taker: (null as any) as string,
|
||||||
};
|
};
|
||||||
// tslint:disable-next-line:max-line-length
|
const expectedErrorMessage =
|
||||||
const expectedErrorMessage = 'Order taker must be of type string. If you want anyone to be able to fill an order - pass ZeroEx.NULL_ADDRESS';
|
'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);
|
expect(() => ZeroEx.getOrderHashHex(orderWithInvalidtakerFormat)).to.throw(expectedErrorMessage);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -198,16 +203,15 @@ describe('ZeroEx library', () => {
|
|||||||
});
|
});
|
||||||
it('should return the correct ECSignature for signatureHex concatenated as R + S + V', async () => {
|
it('should return the correct ECSignature for signatureHex concatenated as R + S + V', async () => {
|
||||||
const orderHash = '0x34decbedc118904df65f379a175bb39ca18209d6ce41d5ed549d54e6e0a95004';
|
const orderHash = '0x34decbedc118904df65f379a175bb39ca18209d6ce41d5ed549d54e6e0a95004';
|
||||||
// tslint:disable-next-line: max-line-length
|
const signature =
|
||||||
const signature = '0x22109d11d79cb8bf96ed88625e1cd9558800c4073332a9a02857499883ee5ce3050aa3cc1f2c435e67e114cdce54b9527b4f50548342401bc5d2b77adbdacb021b';
|
'0x22109d11d79cb8bf96ed88625e1cd9558800c4073332a9a02857499883ee5ce3050aa3cc1f2c435e67e114cdce54b9527b4f50548342401bc5d2b77adbdacb021b';
|
||||||
const expectedECSignature = {
|
const expectedECSignature = {
|
||||||
v: 27,
|
v: 27,
|
||||||
r: '0x22109d11d79cb8bf96ed88625e1cd9558800c4073332a9a02857499883ee5ce3',
|
r: '0x22109d11d79cb8bf96ed88625e1cd9558800c4073332a9a02857499883ee5ce3',
|
||||||
s: '0x050aa3cc1f2c435e67e114cdce54b9527b4f50548342401bc5d2b77adbdacb02',
|
s: '0x050aa3cc1f2c435e67e114cdce54b9527b4f50548342401bc5d2b77adbdacb02',
|
||||||
};
|
};
|
||||||
stubs = [
|
stubs = [
|
||||||
Sinon.stub((zeroEx as any)._web3Wrapper, 'signTransactionAsync')
|
Sinon.stub((zeroEx as any)._web3Wrapper, 'signTransactionAsync').returns(Promise.resolve(signature)),
|
||||||
.returns(Promise.resolve(signature)),
|
|
||||||
Sinon.stub(ZeroEx, 'isValidSignature').returns(true),
|
Sinon.stub(ZeroEx, 'isValidSignature').returns(true),
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -216,16 +220,15 @@ describe('ZeroEx library', () => {
|
|||||||
});
|
});
|
||||||
it('should return the correct ECSignature for signatureHex concatenated as V + R + S', async () => {
|
it('should return the correct ECSignature for signatureHex concatenated as V + R + S', async () => {
|
||||||
const orderHash = '0xc793e33ffded933b76f2f48d9aa3339fc090399d5e7f5dec8d3660f5480793f7';
|
const orderHash = '0xc793e33ffded933b76f2f48d9aa3339fc090399d5e7f5dec8d3660f5480793f7';
|
||||||
// tslint:disable-next-line: max-line-length
|
const signature =
|
||||||
const signature = '0x1bc80bedc6756722672753413efdd749b5adbd4fd552595f59c13427407ee9aee02dea66f25a608bbae457e020fb6decb763deb8b7192abab624997242da248960';
|
'0x1bc80bedc6756722672753413efdd749b5adbd4fd552595f59c13427407ee9aee02dea66f25a608bbae457e020fb6decb763deb8b7192abab624997242da248960';
|
||||||
const expectedECSignature = {
|
const expectedECSignature = {
|
||||||
v: 27,
|
v: 27,
|
||||||
r: '0xc80bedc6756722672753413efdd749b5adbd4fd552595f59c13427407ee9aee0',
|
r: '0xc80bedc6756722672753413efdd749b5adbd4fd552595f59c13427407ee9aee0',
|
||||||
s: '0x2dea66f25a608bbae457e020fb6decb763deb8b7192abab624997242da248960',
|
s: '0x2dea66f25a608bbae457e020fb6decb763deb8b7192abab624997242da248960',
|
||||||
};
|
};
|
||||||
stubs = [
|
stubs = [
|
||||||
Sinon.stub((zeroEx as any)._web3Wrapper, 'signTransactionAsync')
|
Sinon.stub((zeroEx as any)._web3Wrapper, 'signTransactionAsync').returns(Promise.resolve(signature)),
|
||||||
.returns(Promise.resolve(signature)),
|
|
||||||
Sinon.stub(ZeroEx, 'isValidSignature').returns(true),
|
Sinon.stub(ZeroEx, 'isValidSignature').returns(true),
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -271,8 +274,9 @@ describe('ZeroEx library', () => {
|
|||||||
networkId: constants.TESTRPC_NETWORK_ID,
|
networkId: constants.TESTRPC_NETWORK_ID,
|
||||||
};
|
};
|
||||||
const zeroExWithWrongTokenRegistryAddress = new ZeroEx(web3.currentProvider, zeroExConfig);
|
const zeroExWithWrongTokenRegistryAddress = new ZeroEx(web3.currentProvider, zeroExConfig);
|
||||||
expect(zeroExWithWrongTokenRegistryAddress.tokenRegistry.getContractAddress())
|
expect(zeroExWithWrongTokenRegistryAddress.tokenRegistry.getContractAddress()).to.be.equal(
|
||||||
.to.be.equal(ZeroEx.NULL_ADDRESS);
|
ZeroEx.NULL_ADDRESS,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import HDWalletProvider = require('truffle-hdwallet-provider');
|
import HDWalletProvider = require('truffle-hdwallet-provider');
|
||||||
|
|
||||||
import {ZeroEx} from '../src';
|
import { ZeroEx } from '../src';
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
|
|
||||||
import {ZeroEx} from '../src';
|
import { ZeroEx } from '../src';
|
||||||
import {assert} from '../src/utils/assert';
|
import { assert } from '../src/utils/assert';
|
||||||
|
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
import { web3Factory } from './utils/web3_factory';
|
||||||
|
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
|
|
||||||
@ -19,22 +19,25 @@ describe('Assertion library', () => {
|
|||||||
it('throws when address is invalid', async () => {
|
it('throws when address is invalid', async () => {
|
||||||
const address = '0xdeadbeef';
|
const address = '0xdeadbeef';
|
||||||
const varName = 'address';
|
const varName = 'address';
|
||||||
return expect(assert.isSenderAddressAsync(varName, address, (zeroEx as any)._web3Wrapper))
|
return expect(
|
||||||
.to.be.rejectedWith(`Expected ${varName} to be of type ETHAddressHex, encountered: ${address}`);
|
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 () => {
|
it('throws when address is unavailable', async () => {
|
||||||
const validUnrelatedAddress = '0x8b0292b11a196601eddce54b665cafeca0347d42';
|
const validUnrelatedAddress = '0x8b0292b11a196601eddce54b665cafeca0347d42';
|
||||||
const varName = 'address';
|
const varName = 'address';
|
||||||
return expect(assert.isSenderAddressAsync(varName, validUnrelatedAddress, (zeroEx as any)._web3Wrapper))
|
return expect(
|
||||||
.to.be.rejectedWith(
|
assert.isSenderAddressAsync(varName, validUnrelatedAddress, (zeroEx as any)._web3Wrapper),
|
||||||
`Specified ${varName} ${validUnrelatedAddress} isn't available through the supplied web3 provider`,
|
).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 availableAddress = (await zeroEx.getAvailableAddressesAsync())[0];
|
||||||
const varName = 'address';
|
const varName = 'address';
|
||||||
return expect(assert.isSenderAddressAsync(varName, availableAddress, (zeroEx as any)._web3Wrapper))
|
return expect(
|
||||||
.to.become(undefined);
|
assert.isSenderAddressAsync(varName, availableAddress, (zeroEx as any)._web3Wrapper),
|
||||||
|
).to.become(undefined);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {BlockchainLifecycle} from '@0xproject/dev-utils';
|
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
@ -17,13 +17,13 @@ import {
|
|||||||
ZeroEx,
|
ZeroEx,
|
||||||
ZeroExError,
|
ZeroExError,
|
||||||
} from '../src';
|
} from '../src';
|
||||||
import {artifacts} from '../src/artifacts';
|
import { artifacts } from '../src/artifacts';
|
||||||
import {DoneCallback} from '../src/types';
|
import { DoneCallback } from '../src/types';
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
import {TokenUtils} from './utils/token_utils';
|
import { TokenUtils } from './utils/token_utils';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
import { web3Factory } from './utils/web3_factory';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
@ -167,10 +167,12 @@ describe('EtherTokenWrapper', () => {
|
|||||||
done();
|
done();
|
||||||
};
|
};
|
||||||
await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
|
await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
|
||||||
zeroEx.etherToken.subscribe(
|
zeroEx.etherToken.subscribe(etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callback);
|
||||||
etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callback);
|
|
||||||
await zeroEx.token.transferAsync(
|
await zeroEx.token.transferAsync(
|
||||||
etherTokenAddress, addressWithETH, addressWithoutFunds, transferAmount,
|
etherTokenAddress,
|
||||||
|
addressWithETH,
|
||||||
|
addressWithoutFunds,
|
||||||
|
transferAmount,
|
||||||
);
|
);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
@ -186,10 +188,12 @@ describe('EtherTokenWrapper', () => {
|
|||||||
expect(args._value).to.be.bignumber.equal(allowanceAmount);
|
expect(args._value).to.be.bignumber.equal(allowanceAmount);
|
||||||
done();
|
done();
|
||||||
};
|
};
|
||||||
zeroEx.etherToken.subscribe(
|
zeroEx.etherToken.subscribe(etherTokenAddress, EtherTokenEvents.Approval, indexFilterValues, callback);
|
||||||
etherTokenAddress, EtherTokenEvents.Approval, indexFilterValues, callback);
|
|
||||||
await zeroEx.token.setAllowanceAsync(
|
await zeroEx.token.setAllowanceAsync(
|
||||||
etherTokenAddress, addressWithETH, addressWithoutFunds, allowanceAmount,
|
etherTokenAddress,
|
||||||
|
addressWithETH,
|
||||||
|
addressWithoutFunds,
|
||||||
|
allowanceAmount,
|
||||||
);
|
);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
@ -204,11 +208,8 @@ describe('EtherTokenWrapper', () => {
|
|||||||
expect(args._value).to.be.bignumber.equal(depositAmount);
|
expect(args._value).to.be.bignumber.equal(depositAmount);
|
||||||
done();
|
done();
|
||||||
};
|
};
|
||||||
zeroEx.etherToken.subscribe(
|
zeroEx.etherToken.subscribe(etherTokenAddress, EtherTokenEvents.Deposit, indexFilterValues, callback);
|
||||||
etherTokenAddress, EtherTokenEvents.Deposit, indexFilterValues, callback);
|
await zeroEx.etherToken.depositAsync(etherTokenAddress, depositAmount, addressWithETH);
|
||||||
await zeroEx.etherToken.depositAsync(
|
|
||||||
etherTokenAddress, depositAmount, addressWithETH,
|
|
||||||
);
|
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('Should receive the Withdrawal event when ether is being withdrawn', (done: DoneCallback) => {
|
it('Should receive the Withdrawal event when ether is being withdrawn', (done: DoneCallback) => {
|
||||||
@ -222,14 +223,14 @@ describe('EtherTokenWrapper', () => {
|
|||||||
expect(args._value).to.be.bignumber.equal(depositAmount);
|
expect(args._value).to.be.bignumber.equal(depositAmount);
|
||||||
done();
|
done();
|
||||||
};
|
};
|
||||||
await zeroEx.etherToken.depositAsync(
|
await zeroEx.etherToken.depositAsync(etherTokenAddress, depositAmount, addressWithETH);
|
||||||
etherTokenAddress, depositAmount, addressWithETH,
|
|
||||||
);
|
|
||||||
zeroEx.etherToken.subscribe(
|
zeroEx.etherToken.subscribe(
|
||||||
etherTokenAddress, EtherTokenEvents.Withdrawal, indexFilterValues, callback);
|
etherTokenAddress,
|
||||||
await zeroEx.etherToken.withdrawAsync(
|
EtherTokenEvents.Withdrawal,
|
||||||
etherTokenAddress, withdrawalAmount, addressWithETH,
|
indexFilterValues,
|
||||||
|
callback,
|
||||||
);
|
);
|
||||||
|
await zeroEx.etherToken.withdrawAsync(etherTokenAddress, withdrawalAmount, addressWithETH);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('should cancel outstanding subscriptions when ZeroEx.setProvider is called', (done: DoneCallback) => {
|
it('should cancel outstanding subscriptions when ZeroEx.setProvider is called', (done: DoneCallback) => {
|
||||||
@ -238,7 +239,10 @@ describe('EtherTokenWrapper', () => {
|
|||||||
done(new Error('Expected this subscription to have been cancelled'));
|
done(new Error('Expected this subscription to have been cancelled'));
|
||||||
};
|
};
|
||||||
zeroEx.etherToken.subscribe(
|
zeroEx.etherToken.subscribe(
|
||||||
etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled,
|
etherTokenAddress,
|
||||||
|
EtherTokenEvents.Transfer,
|
||||||
|
indexFilterValues,
|
||||||
|
callbackNeverToBeCalled,
|
||||||
);
|
);
|
||||||
const callbackToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
const callbackToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
||||||
done();
|
done();
|
||||||
@ -247,10 +251,16 @@ describe('EtherTokenWrapper', () => {
|
|||||||
zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID);
|
zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID);
|
||||||
await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
|
await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
|
||||||
zeroEx.etherToken.subscribe(
|
zeroEx.etherToken.subscribe(
|
||||||
etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callbackToBeCalled,
|
etherTokenAddress,
|
||||||
|
EtherTokenEvents.Transfer,
|
||||||
|
indexFilterValues,
|
||||||
|
callbackToBeCalled,
|
||||||
);
|
);
|
||||||
await zeroEx.token.transferAsync(
|
await zeroEx.token.transferAsync(
|
||||||
etherTokenAddress, addressWithETH, addressWithoutFunds, transferAmount,
|
etherTokenAddress,
|
||||||
|
addressWithETH,
|
||||||
|
addressWithoutFunds,
|
||||||
|
transferAmount,
|
||||||
);
|
);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
@ -261,10 +271,17 @@ describe('EtherTokenWrapper', () => {
|
|||||||
};
|
};
|
||||||
await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
|
await zeroEx.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH);
|
||||||
const subscriptionToken = zeroEx.etherToken.subscribe(
|
const subscriptionToken = zeroEx.etherToken.subscribe(
|
||||||
etherTokenAddress, EtherTokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled);
|
etherTokenAddress,
|
||||||
|
EtherTokenEvents.Transfer,
|
||||||
|
indexFilterValues,
|
||||||
|
callbackNeverToBeCalled,
|
||||||
|
);
|
||||||
zeroEx.etherToken.unsubscribe(subscriptionToken);
|
zeroEx.etherToken.unsubscribe(subscriptionToken);
|
||||||
await zeroEx.token.transferAsync(
|
await zeroEx.token.transferAsync(
|
||||||
etherTokenAddress, addressWithETH, addressWithoutFunds, transferAmount,
|
etherTokenAddress,
|
||||||
|
addressWithETH,
|
||||||
|
addressWithoutFunds,
|
||||||
|
transferAmount,
|
||||||
);
|
);
|
||||||
done();
|
done();
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
@ -291,7 +308,10 @@ describe('EtherTokenWrapper', () => {
|
|||||||
const eventName = EtherTokenEvents.Approval;
|
const eventName = EtherTokenEvents.Approval;
|
||||||
const indexFilterValues = {};
|
const indexFilterValues = {};
|
||||||
const logs = await zeroEx.etherToken.getLogsAsync<ApprovalContractEventArgs>(
|
const logs = await zeroEx.etherToken.getLogsAsync<ApprovalContractEventArgs>(
|
||||||
etherTokenAddress, eventName, blockRange, indexFilterValues,
|
etherTokenAddress,
|
||||||
|
eventName,
|
||||||
|
blockRange,
|
||||||
|
indexFilterValues,
|
||||||
);
|
);
|
||||||
expect(logs).to.have.length(1);
|
expect(logs).to.have.length(1);
|
||||||
const args = logs[0].args;
|
const args = logs[0].args;
|
||||||
@ -305,7 +325,10 @@ describe('EtherTokenWrapper', () => {
|
|||||||
const eventName = EtherTokenEvents.Deposit;
|
const eventName = EtherTokenEvents.Deposit;
|
||||||
const indexFilterValues = {};
|
const indexFilterValues = {};
|
||||||
const logs = await zeroEx.etherToken.getLogsAsync<DepositContractEventArgs>(
|
const logs = await zeroEx.etherToken.getLogsAsync<DepositContractEventArgs>(
|
||||||
etherTokenAddress, eventName, blockRange, indexFilterValues,
|
etherTokenAddress,
|
||||||
|
eventName,
|
||||||
|
blockRange,
|
||||||
|
indexFilterValues,
|
||||||
);
|
);
|
||||||
expect(logs).to.have.length(1);
|
expect(logs).to.have.length(1);
|
||||||
const args = logs[0].args;
|
const args = logs[0].args;
|
||||||
@ -319,7 +342,10 @@ describe('EtherTokenWrapper', () => {
|
|||||||
const differentEventName = EtherTokenEvents.Transfer;
|
const differentEventName = EtherTokenEvents.Transfer;
|
||||||
const indexFilterValues = {};
|
const indexFilterValues = {};
|
||||||
const logs = await zeroEx.etherToken.getLogsAsync(
|
const logs = await zeroEx.etherToken.getLogsAsync(
|
||||||
etherTokenAddress, differentEventName, blockRange, indexFilterValues,
|
etherTokenAddress,
|
||||||
|
differentEventName,
|
||||||
|
blockRange,
|
||||||
|
indexFilterValues,
|
||||||
);
|
);
|
||||||
expect(logs).to.have.length(0);
|
expect(logs).to.have.length(0);
|
||||||
});
|
});
|
||||||
@ -333,7 +359,10 @@ describe('EtherTokenWrapper', () => {
|
|||||||
_owner: addressWithETH,
|
_owner: addressWithETH,
|
||||||
};
|
};
|
||||||
const logs = await zeroEx.etherToken.getLogsAsync<ApprovalContractEventArgs>(
|
const logs = await zeroEx.etherToken.getLogsAsync<ApprovalContractEventArgs>(
|
||||||
etherTokenAddress, eventName, blockRange, indexFilterValues,
|
etherTokenAddress,
|
||||||
|
eventName,
|
||||||
|
blockRange,
|
||||||
|
indexFilterValues,
|
||||||
);
|
);
|
||||||
expect(logs).to.have.length(1);
|
expect(logs).to.have.length(1);
|
||||||
const args = logs[0].args;
|
const args = logs[0].args;
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
import * as Sinon from 'sinon';
|
import * as Sinon from 'sinon';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import {
|
import { LogEvent } from '../src';
|
||||||
LogEvent,
|
import { EventWatcher } from '../src/order_watcher/event_watcher';
|
||||||
} from '../src';
|
import { DoneCallback } from '../src/types';
|
||||||
import {EventWatcher} from '../src/order_watcher/event_watcher';
|
|
||||||
import {DoneCallback} from '../src/types';
|
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
import { web3Factory } from './utils/web3_factory';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
@ -38,7 +36,7 @@ describe('EventWatcher', () => {
|
|||||||
blockNumber: null,
|
blockNumber: null,
|
||||||
data: '',
|
data: '',
|
||||||
logIndex: null,
|
logIndex: null,
|
||||||
topics: [ '0xf341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb567' ],
|
topics: ['0xf341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb567'],
|
||||||
transactionHash: '0x01ef3c048b18d9b09ea195b4ed94cf8dd5f3d857a1905ff886b152cfb1166f25',
|
transactionHash: '0x01ef3c048b18d9b09ea195b4ed94cf8dd5f3d857a1905ff886b152cfb1166f25',
|
||||||
transactionIndex: 0,
|
transactionIndex: 0,
|
||||||
};
|
};
|
||||||
@ -48,7 +46,7 @@ describe('EventWatcher', () => {
|
|||||||
blockNumber: null,
|
blockNumber: null,
|
||||||
data: '',
|
data: '',
|
||||||
logIndex: null,
|
logIndex: null,
|
||||||
topics: [ '0xf341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb567' ],
|
topics: ['0xf341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb567'],
|
||||||
transactionHash: '0x01ef3c048b18d9b09ea195b4ed94cf8dd5f3d857a1905ff886b152cfb1166f25',
|
transactionHash: '0x01ef3c048b18d9b09ea195b4ed94cf8dd5f3d857a1905ff886b152cfb1166f25',
|
||||||
transactionIndex: 0,
|
transactionIndex: 0,
|
||||||
};
|
};
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import {BlockchainLifecycle} from '@0xproject/dev-utils';
|
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
|
|
||||||
import {ExchangeContractErrs, Token, ZeroEx} from '../src';
|
import { ExchangeContractErrs, Token, ZeroEx } from '../src';
|
||||||
import {BlockParamLiteral, TradeSide, TransferType} from '../src/types';
|
import { BlockParamLiteral, TradeSide, TransferType } from '../src/types';
|
||||||
import {ExchangeTransferSimulator} from '../src/utils/exchange_transfer_simulator';
|
import { ExchangeTransferSimulator } from '../src/utils/exchange_transfer_simulator';
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
import { web3Factory } from './utils/web3_factory';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
@ -45,17 +45,31 @@ describe('ExchangeTransferSimulator', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
exchangeTransferSimulator = new ExchangeTransferSimulator(zeroEx.token, BlockParamLiteral.Latest);
|
exchangeTransferSimulator = new ExchangeTransferSimulator(zeroEx.token, BlockParamLiteral.Latest);
|
||||||
});
|
});
|
||||||
it('throws if the user doesn\'t have enough allowance', async () => {
|
it("throws if the user doesn't have enough allowance", async () => {
|
||||||
return expect(exchangeTransferSimulator.transferFromAsync(
|
return expect(
|
||||||
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade,
|
exchangeTransferSimulator.transferFromAsync(
|
||||||
)).to.be.rejectedWith(ExchangeContractErrs.InsufficientTakerAllowance);
|
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);
|
txHash = await zeroEx.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount);
|
||||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||||
return expect(exchangeTransferSimulator.transferFromAsync(
|
return expect(
|
||||||
exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Maker, TransferType.Trade,
|
exchangeTransferSimulator.transferFromAsync(
|
||||||
)).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance);
|
exampleTokenAddress,
|
||||||
|
sender,
|
||||||
|
recipient,
|
||||||
|
transferAmount,
|
||||||
|
TradeSide.Maker,
|
||||||
|
TransferType.Trade,
|
||||||
|
),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance);
|
||||||
});
|
});
|
||||||
it('updates balances and proxyAllowance after transfer', async () => {
|
it('updates balances and proxyAllowance after transfer', async () => {
|
||||||
txHash = await zeroEx.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount);
|
txHash = await zeroEx.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount);
|
||||||
@ -63,7 +77,12 @@ describe('ExchangeTransferSimulator', () => {
|
|||||||
txHash = await zeroEx.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount);
|
txHash = await zeroEx.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount);
|
||||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||||
await exchangeTransferSimulator.transferFromAsync(
|
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 senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender);
|
||||||
@ -73,13 +92,18 @@ describe('ExchangeTransferSimulator', () => {
|
|||||||
expect(recipientBalance).to.be.bignumber.equal(transferAmount);
|
expect(recipientBalance).to.be.bignumber.equal(transferAmount);
|
||||||
expect(senderProxyAllowance).to.be.bignumber.equal(0);
|
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);
|
txHash = await zeroEx.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount);
|
||||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||||
txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(exampleTokenAddress, sender);
|
txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(exampleTokenAddress, sender);
|
||||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||||
await exchangeTransferSimulator.transferFromAsync(
|
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 senderBalance = await store.getBalanceAsync(exampleTokenAddress, sender);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {BlockchainLifecycle} from '@0xproject/dev-utils';
|
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
@ -17,13 +17,13 @@ import {
|
|||||||
Token,
|
Token,
|
||||||
ZeroEx,
|
ZeroEx,
|
||||||
} from '../src';
|
} from '../src';
|
||||||
import {BlockParamLiteral, DoneCallback} from '../src/types';
|
import { BlockParamLiteral, DoneCallback } from '../src/types';
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
import {FillScenarios} from './utils/fill_scenarios';
|
import { FillScenarios } from './utils/fill_scenarios';
|
||||||
import {TokenUtils} from './utils/token_utils';
|
import { TokenUtils } from './utils/token_utils';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
import { web3Factory } from './utils/web3_factory';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
@ -80,10 +80,18 @@ describe('ExchangeWrapper', () => {
|
|||||||
const fillableAmount = new BigNumber(5);
|
const fillableAmount = new BigNumber(5);
|
||||||
const partialFillTakerAmount = new BigNumber(2);
|
const partialFillTakerAmount = new BigNumber(2);
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const orderFillRequests = [
|
const orderFillRequests = [
|
||||||
{
|
{
|
||||||
@ -103,7 +111,11 @@ describe('ExchangeWrapper', () => {
|
|||||||
const fillableAmount = new BigNumber(5);
|
const fillableAmount = new BigNumber(5);
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
orderFillRequests = [
|
orderFillRequests = [
|
||||||
{
|
{
|
||||||
@ -113,18 +125,23 @@ describe('ExchangeWrapper', () => {
|
|||||||
];
|
];
|
||||||
});
|
});
|
||||||
it('should validate when orderTransactionOptions are not present', async () => {
|
it('should validate when orderTransactionOptions are not present', async () => {
|
||||||
return expect(zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress))
|
return expect(
|
||||||
.to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||||
});
|
});
|
||||||
it('should validate when orderTransactionOptions specify to validate', async () => {
|
it('should validate when orderTransactionOptions specify to validate', async () => {
|
||||||
return expect(zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress, {
|
return expect(
|
||||||
shouldValidate: true,
|
zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress, {
|
||||||
})).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
shouldValidate: true,
|
||||||
|
}),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||||
});
|
});
|
||||||
it('should not validate when orderTransactionOptions specify not to validate', async () => {
|
it('should not validate when orderTransactionOptions specify not to validate', async () => {
|
||||||
return expect(zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress, {
|
return expect(
|
||||||
shouldValidate: false,
|
zeroEx.exchange.batchFillOrKillAsync(orderFillRequests, takerAddress, {
|
||||||
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
shouldValidate: false,
|
||||||
|
}),
|
||||||
|
).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -133,57 +150,78 @@ describe('ExchangeWrapper', () => {
|
|||||||
const fillableAmount = new BigNumber(5);
|
const fillableAmount = new BigNumber(5);
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
describe('successful fills', () => {
|
describe('successful fills', () => {
|
||||||
it('should fill a valid order', async () => {
|
it('should fill a valid order', async () => {
|
||||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress))
|
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal(
|
||||||
.to.be.bignumber.equal(fillableAmount);
|
fillableAmount,
|
||||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress))
|
);
|
||||||
.to.be.bignumber.equal(0);
|
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal(
|
||||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress))
|
0,
|
||||||
.to.be.bignumber.equal(0);
|
);
|
||||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress))
|
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal(
|
||||||
.to.be.bignumber.equal(fillableAmount);
|
0,
|
||||||
|
);
|
||||||
|
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal(
|
||||||
|
fillableAmount,
|
||||||
|
);
|
||||||
await zeroEx.exchange.fillOrKillOrderAsync(signedOrder, takerTokenFillAmount, takerAddress);
|
await zeroEx.exchange.fillOrKillOrderAsync(signedOrder, takerTokenFillAmount, takerAddress);
|
||||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress))
|
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal(
|
||||||
.to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount));
|
fillableAmount.minus(takerTokenFillAmount),
|
||||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress))
|
);
|
||||||
.to.be.bignumber.equal(takerTokenFillAmount);
|
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal(
|
||||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress))
|
takerTokenFillAmount,
|
||||||
.to.be.bignumber.equal(takerTokenFillAmount);
|
);
|
||||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress))
|
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal(
|
||||||
.to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount));
|
takerTokenFillAmount,
|
||||||
|
);
|
||||||
|
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal(
|
||||||
|
fillableAmount.minus(takerTokenFillAmount),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should partially fill a valid order', async () => {
|
it('should partially fill a valid order', async () => {
|
||||||
const partialFillAmount = new BigNumber(3);
|
const partialFillAmount = new BigNumber(3);
|
||||||
await zeroEx.exchange.fillOrKillOrderAsync(signedOrder, partialFillAmount, takerAddress);
|
await zeroEx.exchange.fillOrKillOrderAsync(signedOrder, partialFillAmount, takerAddress);
|
||||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress))
|
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal(
|
||||||
.to.be.bignumber.equal(fillableAmount.minus(partialFillAmount));
|
fillableAmount.minus(partialFillAmount),
|
||||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress))
|
);
|
||||||
.to.be.bignumber.equal(partialFillAmount);
|
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal(
|
||||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress))
|
partialFillAmount,
|
||||||
.to.be.bignumber.equal(partialFillAmount);
|
);
|
||||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress))
|
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal(
|
||||||
.to.be.bignumber.equal(fillableAmount.minus(partialFillAmount));
|
partialFillAmount,
|
||||||
|
);
|
||||||
|
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal(
|
||||||
|
fillableAmount.minus(partialFillAmount),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('order transaction options', () => {
|
describe('order transaction options', () => {
|
||||||
const emptyFillableAmount = new BigNumber(0);
|
const emptyFillableAmount = new BigNumber(0);
|
||||||
it('should validate when orderTransactionOptions are not present', async () => {
|
it('should validate when orderTransactionOptions are not present', async () => {
|
||||||
return expect(zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress))
|
return expect(
|
||||||
.to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||||
});
|
});
|
||||||
it('should validate when orderTransactionOptions specify to validate', async () => {
|
it('should validate when orderTransactionOptions specify to validate', async () => {
|
||||||
return expect(zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress, {
|
return expect(
|
||||||
shouldValidate: true,
|
zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress, {
|
||||||
})).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
shouldValidate: true,
|
||||||
|
}),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||||
});
|
});
|
||||||
it('should not validate when orderTransactionOptions specify not to validate', async () => {
|
it('should not validate when orderTransactionOptions specify not to validate', async () => {
|
||||||
return expect(zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress, {
|
return expect(
|
||||||
shouldValidate: false,
|
zeroEx.exchange.fillOrKillOrderAsync(signedOrder, emptyFillableAmount, takerAddress, {
|
||||||
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
shouldValidate: false,
|
||||||
|
}),
|
||||||
|
).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -209,57 +247,96 @@ describe('ExchangeWrapper', () => {
|
|||||||
describe('successful fills', () => {
|
describe('successful fills', () => {
|
||||||
it('should fill a valid order', async () => {
|
it('should fill a valid order', async () => {
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
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(
|
const txHash = await zeroEx.exchange.fillOrderAsync(
|
||||||
signedOrder, takerTokenFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress);
|
signedOrder,
|
||||||
|
takerTokenFillAmount,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
takerAddress,
|
||||||
|
);
|
||||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress))
|
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal(
|
||||||
.to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount));
|
fillableAmount.minus(takerTokenFillAmount),
|
||||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress))
|
);
|
||||||
.to.be.bignumber.equal(takerTokenFillAmount);
|
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal(
|
||||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress))
|
takerTokenFillAmount,
|
||||||
.to.be.bignumber.equal(takerTokenFillAmount);
|
);
|
||||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress))
|
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal(
|
||||||
.to.be.bignumber.equal(fillableAmount.minus(takerTokenFillAmount));
|
takerTokenFillAmount,
|
||||||
|
);
|
||||||
|
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal(
|
||||||
|
fillableAmount.minus(takerTokenFillAmount),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should partially fill the valid order', async () => {
|
it('should partially fill the valid order', async () => {
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const partialFillAmount = new BigNumber(3);
|
const partialFillAmount = new BigNumber(3);
|
||||||
const txHash = await zeroEx.exchange.fillOrderAsync(
|
const txHash = await zeroEx.exchange.fillOrderAsync(
|
||||||
signedOrder, partialFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress);
|
signedOrder,
|
||||||
|
partialFillAmount,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
takerAddress,
|
||||||
|
);
|
||||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress))
|
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)).to.be.bignumber.equal(
|
||||||
.to.be.bignumber.equal(fillableAmount.minus(partialFillAmount));
|
fillableAmount.minus(partialFillAmount),
|
||||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress))
|
);
|
||||||
.to.be.bignumber.equal(partialFillAmount);
|
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)).to.be.bignumber.equal(
|
||||||
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress))
|
partialFillAmount,
|
||||||
.to.be.bignumber.equal(partialFillAmount);
|
);
|
||||||
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress))
|
expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)).to.be.bignumber.equal(
|
||||||
.to.be.bignumber.equal(fillableAmount.minus(partialFillAmount));
|
partialFillAmount,
|
||||||
|
);
|
||||||
|
expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)).to.be.bignumber.equal(
|
||||||
|
fillableAmount.minus(partialFillAmount),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should fill the valid orders with fees', async () => {
|
it('should fill the valid orders with fees', async () => {
|
||||||
const makerFee = new BigNumber(1);
|
const makerFee = new BigNumber(1);
|
||||||
const takerFee = new BigNumber(2);
|
const takerFee = new BigNumber(2);
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerFee, takerFee,
|
makerTokenAddress,
|
||||||
makerAddress, takerAddress, fillableAmount, feeRecipient,
|
takerTokenAddress,
|
||||||
|
makerFee,
|
||||||
|
takerFee,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
|
feeRecipient,
|
||||||
);
|
);
|
||||||
const txHash = await zeroEx.exchange.fillOrderAsync(
|
const txHash = await zeroEx.exchange.fillOrderAsync(
|
||||||
signedOrder, takerTokenFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress);
|
signedOrder,
|
||||||
|
takerTokenFillAmount,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
takerAddress,
|
||||||
|
);
|
||||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||||
expect(await zeroEx.token.getBalanceAsync(zrxTokenAddress, feeRecipient))
|
expect(await zeroEx.token.getBalanceAsync(zrxTokenAddress, feeRecipient)).to.be.bignumber.equal(
|
||||||
.to.be.bignumber.equal(makerFee.plus(takerFee));
|
makerFee.plus(takerFee),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('order transaction options', () => {
|
describe('order transaction options', () => {
|
||||||
@ -267,25 +344,48 @@ describe('ExchangeWrapper', () => {
|
|||||||
const emptyFillTakerAmount = new BigNumber(0);
|
const emptyFillTakerAmount = new BigNumber(0);
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should validate when orderTransactionOptions are not present', async () => {
|
it('should validate when orderTransactionOptions are not present', async () => {
|
||||||
return expect(zeroEx.exchange.fillOrderAsync(
|
return expect(
|
||||||
signedOrder, emptyFillTakerAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
|
zeroEx.exchange.fillOrderAsync(
|
||||||
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
signedOrder,
|
||||||
|
emptyFillTakerAmount,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
takerAddress,
|
||||||
|
),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||||
});
|
});
|
||||||
it('should validate when orderTransactionOptions specify to validate', async () => {
|
it('should validate when orderTransactionOptions specify to validate', async () => {
|
||||||
return expect(zeroEx.exchange.fillOrderAsync(
|
return expect(
|
||||||
signedOrder, emptyFillTakerAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, {
|
zeroEx.exchange.fillOrderAsync(
|
||||||
shouldValidate: true,
|
signedOrder,
|
||||||
})).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
emptyFillTakerAmount,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
takerAddress,
|
||||||
|
{
|
||||||
|
shouldValidate: true,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||||
});
|
});
|
||||||
it('should not validate when orderTransactionOptions specify not to validate', async () => {
|
it('should not validate when orderTransactionOptions specify not to validate', async () => {
|
||||||
return expect(zeroEx.exchange.fillOrderAsync(
|
return expect(
|
||||||
signedOrder, emptyFillTakerAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, {
|
zeroEx.exchange.fillOrderAsync(
|
||||||
shouldValidate: false,
|
signedOrder,
|
||||||
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
emptyFillTakerAmount,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
takerAddress,
|
||||||
|
{
|
||||||
|
shouldValidate: false,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -297,11 +397,19 @@ describe('ExchangeWrapper', () => {
|
|||||||
let orderFillBatch: OrderFillRequest[];
|
let orderFillBatch: OrderFillRequest[];
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
signedOrderHashHex = ZeroEx.getOrderHashHex(signedOrder);
|
signedOrderHashHex = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder);
|
anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder);
|
||||||
});
|
});
|
||||||
@ -319,13 +427,20 @@ describe('ExchangeWrapper', () => {
|
|||||||
];
|
];
|
||||||
});
|
});
|
||||||
it('should throw if a batch is empty', async () => {
|
it('should throw if a batch is empty', async () => {
|
||||||
return expect(zeroEx.exchange.batchFillOrdersAsync(
|
return expect(
|
||||||
[], shouldThrowOnInsufficientBalanceOrAllowance, takerAddress),
|
zeroEx.exchange.batchFillOrdersAsync(
|
||||||
|
[],
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
takerAddress,
|
||||||
|
),
|
||||||
).to.be.rejectedWith(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
|
).to.be.rejectedWith(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
|
||||||
});
|
});
|
||||||
it('should successfully fill multiple orders', async () => {
|
it('should successfully fill multiple orders', async () => {
|
||||||
const txHash = await zeroEx.exchange.batchFillOrdersAsync(
|
const txHash = await zeroEx.exchange.batchFillOrdersAsync(
|
||||||
orderFillBatch, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress);
|
orderFillBatch,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
takerAddress,
|
||||||
|
);
|
||||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||||
const filledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
|
const filledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
|
||||||
const anotherFilledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(anotherOrderHashHex);
|
const anotherFilledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(anotherOrderHashHex);
|
||||||
@ -348,21 +463,37 @@ describe('ExchangeWrapper', () => {
|
|||||||
];
|
];
|
||||||
});
|
});
|
||||||
it('should validate when orderTransactionOptions are not present', async () => {
|
it('should validate when orderTransactionOptions are not present', async () => {
|
||||||
return expect(zeroEx.exchange.batchFillOrdersAsync(
|
return expect(
|
||||||
orderFillBatch, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress),
|
zeroEx.exchange.batchFillOrdersAsync(
|
||||||
|
orderFillBatch,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
takerAddress,
|
||||||
|
),
|
||||||
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||||
});
|
});
|
||||||
it('should validate when orderTransactionOptions specify to validate', async () => {
|
it('should validate when orderTransactionOptions specify to validate', async () => {
|
||||||
return expect(zeroEx.exchange.batchFillOrdersAsync(
|
return expect(
|
||||||
orderFillBatch, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, {
|
zeroEx.exchange.batchFillOrdersAsync(
|
||||||
shouldValidate: true,
|
orderFillBatch,
|
||||||
})).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
takerAddress,
|
||||||
|
{
|
||||||
|
shouldValidate: true,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||||
});
|
});
|
||||||
it('should not validate when orderTransactionOptions specify not to validate', async () => {
|
it('should not validate when orderTransactionOptions specify not to validate', async () => {
|
||||||
return expect(zeroEx.exchange.batchFillOrdersAsync(
|
return expect(
|
||||||
orderFillBatch, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, {
|
zeroEx.exchange.batchFillOrdersAsync(
|
||||||
shouldValidate: false,
|
orderFillBatch,
|
||||||
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
takerAddress,
|
||||||
|
{
|
||||||
|
shouldValidate: false,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -375,24 +506,40 @@ describe('ExchangeWrapper', () => {
|
|||||||
const fillUpToAmount = fillableAmount.plus(fillableAmount).minus(1);
|
const fillUpToAmount = fillableAmount.plus(fillableAmount).minus(1);
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
signedOrderHashHex = ZeroEx.getOrderHashHex(signedOrder);
|
signedOrderHashHex = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder);
|
anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder);
|
||||||
signedOrders = [signedOrder, anotherSignedOrder];
|
signedOrders = [signedOrder, anotherSignedOrder];
|
||||||
});
|
});
|
||||||
describe('successful batch fills', () => {
|
describe('successful batch fills', () => {
|
||||||
it('should throw if a batch is empty', async () => {
|
it('should throw if a batch is empty', async () => {
|
||||||
return expect(zeroEx.exchange.fillOrdersUpToAsync(
|
return expect(
|
||||||
[], fillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress),
|
zeroEx.exchange.fillOrdersUpToAsync(
|
||||||
|
[],
|
||||||
|
fillUpToAmount,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
takerAddress,
|
||||||
|
),
|
||||||
).to.be.rejectedWith(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
|
).to.be.rejectedWith(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
|
||||||
});
|
});
|
||||||
it('should successfully fill up to specified amount', async () => {
|
it('should successfully fill up to specified amount', async () => {
|
||||||
const txHash = await zeroEx.exchange.fillOrdersUpToAsync(
|
const txHash = await zeroEx.exchange.fillOrdersUpToAsync(
|
||||||
signedOrders, fillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
|
signedOrders,
|
||||||
|
fillUpToAmount,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
takerAddress,
|
||||||
);
|
);
|
||||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||||
const filledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
|
const filledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
|
||||||
@ -405,21 +552,40 @@ describe('ExchangeWrapper', () => {
|
|||||||
describe('order transaction options', () => {
|
describe('order transaction options', () => {
|
||||||
const emptyFillUpToAmount = new BigNumber(0);
|
const emptyFillUpToAmount = new BigNumber(0);
|
||||||
it('should validate when orderTransactionOptions are not present', async () => {
|
it('should validate when orderTransactionOptions are not present', async () => {
|
||||||
return expect(zeroEx.exchange.fillOrdersUpToAsync(
|
return expect(
|
||||||
signedOrders, emptyFillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
|
zeroEx.exchange.fillOrdersUpToAsync(
|
||||||
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
signedOrders,
|
||||||
|
emptyFillUpToAmount,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
takerAddress,
|
||||||
|
),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||||
});
|
});
|
||||||
it('should validate when orderTransactionOptions specify to validate', async () => {
|
it('should validate when orderTransactionOptions specify to validate', async () => {
|
||||||
return expect(zeroEx.exchange.fillOrdersUpToAsync(
|
return expect(
|
||||||
signedOrders, emptyFillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, {
|
zeroEx.exchange.fillOrdersUpToAsync(
|
||||||
shouldValidate: true,
|
signedOrders,
|
||||||
})).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
emptyFillUpToAmount,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
takerAddress,
|
||||||
|
{
|
||||||
|
shouldValidate: true,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||||
});
|
});
|
||||||
it('should not validate when orderTransactionOptions specify not to validate', async () => {
|
it('should not validate when orderTransactionOptions specify not to validate', async () => {
|
||||||
return expect(zeroEx.exchange.fillOrdersUpToAsync(
|
return expect(
|
||||||
signedOrders, emptyFillUpToAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, {
|
zeroEx.exchange.fillOrdersUpToAsync(
|
||||||
shouldValidate: false,
|
signedOrders,
|
||||||
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
emptyFillUpToAmount,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
takerAddress,
|
||||||
|
{
|
||||||
|
shouldValidate: false,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
).to.not.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -440,7 +606,11 @@ describe('ExchangeWrapper', () => {
|
|||||||
makerTokenAddress = makerToken.address;
|
makerTokenAddress = makerToken.address;
|
||||||
takerTokenAddress = takerToken.address;
|
takerTokenAddress = takerToken.address;
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
orderHashHex = ZeroEx.getOrderHashHex(signedOrder);
|
orderHashHex = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
});
|
});
|
||||||
@ -456,18 +626,23 @@ describe('ExchangeWrapper', () => {
|
|||||||
describe('order transaction options', () => {
|
describe('order transaction options', () => {
|
||||||
const emptyCancelTakerTokenAmount = new BigNumber(0);
|
const emptyCancelTakerTokenAmount = new BigNumber(0);
|
||||||
it('should validate when orderTransactionOptions are not present', async () => {
|
it('should validate when orderTransactionOptions are not present', async () => {
|
||||||
return expect(zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount))
|
return expect(
|
||||||
.to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
||||||
});
|
});
|
||||||
it('should validate when orderTransactionOptions specify to validate', async () => {
|
it('should validate when orderTransactionOptions specify to validate', async () => {
|
||||||
return expect(zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount, {
|
return expect(
|
||||||
shouldValidate: true,
|
zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount, {
|
||||||
})).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
shouldValidate: true,
|
||||||
|
}),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
||||||
});
|
});
|
||||||
it('should not validate when orderTransactionOptions specify not to validate', async () => {
|
it('should not validate when orderTransactionOptions specify not to validate', async () => {
|
||||||
return expect(zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount, {
|
return expect(
|
||||||
shouldValidate: false,
|
zeroEx.exchange.cancelOrderAsync(signedOrder, emptyCancelTakerTokenAmount, {
|
||||||
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
shouldValidate: false,
|
||||||
|
}),
|
||||||
|
).to.not.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -477,7 +652,11 @@ describe('ExchangeWrapper', () => {
|
|||||||
let cancelBatch: OrderCancellationRequest[];
|
let cancelBatch: OrderCancellationRequest[];
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder);
|
anotherOrderHashHex = ZeroEx.getOrderHashHex(anotherSignedOrder);
|
||||||
cancelBatch = [
|
cancelBatch = [
|
||||||
@ -494,15 +673,21 @@ describe('ExchangeWrapper', () => {
|
|||||||
describe('failed batch cancels', () => {
|
describe('failed batch cancels', () => {
|
||||||
it('should throw when orders have different makers', async () => {
|
it('should throw when orders have different makers', async () => {
|
||||||
const signedOrderWithDifferentMaker = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrderWithDifferentMaker = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, takerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
takerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
return expect(zeroEx.exchange.batchCancelOrdersAsync([
|
return expect(
|
||||||
cancelBatch[0],
|
zeroEx.exchange.batchCancelOrdersAsync([
|
||||||
{
|
cancelBatch[0],
|
||||||
order: signedOrderWithDifferentMaker,
|
{
|
||||||
takerTokenCancelAmount: cancelAmount,
|
order: signedOrderWithDifferentMaker,
|
||||||
},
|
takerTokenCancelAmount: cancelAmount,
|
||||||
])).to.be.rejectedWith(ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed);
|
},
|
||||||
|
]),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.MultipleMakersInSingleCancelBatchDisallowed);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('successful batch cancels', () => {
|
describe('successful batch cancels', () => {
|
||||||
@ -531,18 +716,23 @@ describe('ExchangeWrapper', () => {
|
|||||||
];
|
];
|
||||||
});
|
});
|
||||||
it('should validate when orderTransactionOptions are not present', async () => {
|
it('should validate when orderTransactionOptions are not present', async () => {
|
||||||
return expect(zeroEx.exchange.batchCancelOrdersAsync(cancelBatch))
|
return expect(zeroEx.exchange.batchCancelOrdersAsync(cancelBatch)).to.be.rejectedWith(
|
||||||
.to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
ExchangeContractErrs.OrderCancelAmountZero,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should validate when orderTransactionOptions specify to validate', async () => {
|
it('should validate when orderTransactionOptions specify to validate', async () => {
|
||||||
return expect(zeroEx.exchange.batchCancelOrdersAsync(cancelBatch, {
|
return expect(
|
||||||
shouldValidate: true,
|
zeroEx.exchange.batchCancelOrdersAsync(cancelBatch, {
|
||||||
})).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
shouldValidate: true,
|
||||||
|
}),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
||||||
});
|
});
|
||||||
it('should not validate when orderTransactionOptions specify not to validate', async () => {
|
it('should not validate when orderTransactionOptions specify not to validate', async () => {
|
||||||
return expect(zeroEx.exchange.batchCancelOrdersAsync(cancelBatch, {
|
return expect(
|
||||||
shouldValidate: false,
|
zeroEx.exchange.batchCancelOrdersAsync(cancelBatch, {
|
||||||
})).to.not.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
shouldValidate: false,
|
||||||
|
}),
|
||||||
|
).to.not.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -566,7 +756,11 @@ describe('ExchangeWrapper', () => {
|
|||||||
fillableAmount = new BigNumber(5);
|
fillableAmount = new BigNumber(5);
|
||||||
partialFillAmount = new BigNumber(2);
|
partialFillAmount = new BigNumber(2);
|
||||||
signedOrder = await fillScenarios.createPartiallyFilledSignedOrderAsync(
|
signedOrder = await fillScenarios.createPartiallyFilledSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, takerAddress, fillableAmount, partialFillAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
|
partialFillAmount,
|
||||||
);
|
);
|
||||||
orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
});
|
});
|
||||||
@ -590,8 +784,7 @@ describe('ExchangeWrapper', () => {
|
|||||||
return expect(zeroEx.exchange.getFilledTakerAmountAsync(invalidOrderHashHex)).to.be.rejected();
|
return expect(zeroEx.exchange.getFilledTakerAmountAsync(invalidOrderHashHex)).to.be.rejected();
|
||||||
});
|
});
|
||||||
it('should return zero if passed a valid but non-existent orderHash', async () => {
|
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);
|
expect(filledValueT).to.be.bignumber.equal(0);
|
||||||
});
|
});
|
||||||
it('should return the filledValueT for a valid and partially filled orderHash', async () => {
|
it('should return the filledValueT for a valid and partially filled orderHash', async () => {
|
||||||
@ -641,7 +834,11 @@ describe('ExchangeWrapper', () => {
|
|||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
fillableAmount = new BigNumber(5);
|
fillableAmount = new BigNumber(5);
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
@ -654,42 +851,35 @@ describe('ExchangeWrapper', () => {
|
|||||||
// Source: https://github.com/mochajs/mocha/issues/2407
|
// Source: https://github.com/mochajs/mocha/issues/2407
|
||||||
it('Should receive the LogFill event when an order is filled', (done: DoneCallback) => {
|
it('Should receive the LogFill event when an order is filled', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
|
|
||||||
const callback = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
|
const callback = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
|
||||||
expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogFill);
|
expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogFill);
|
||||||
done();
|
done();
|
||||||
};
|
};
|
||||||
zeroEx.exchange.subscribe(
|
zeroEx.exchange.subscribe(ExchangeEvents.LogFill, indexFilterValues, callback);
|
||||||
ExchangeEvents.LogFill, indexFilterValues, callback,
|
|
||||||
);
|
|
||||||
await zeroEx.exchange.fillOrderAsync(
|
await zeroEx.exchange.fillOrderAsync(
|
||||||
signedOrder, takerTokenFillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance,
|
signedOrder,
|
||||||
|
takerTokenFillAmountInBaseUnits,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
takerAddress,
|
takerAddress,
|
||||||
);
|
);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('Should receive the LogCancel event when an order is cancelled', (done: DoneCallback) => {
|
it('Should receive the LogCancel event when an order is cancelled', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
|
|
||||||
const callback = (err: Error, logEvent: DecodedLogEvent<LogCancelContractEventArgs>) => {
|
const callback = (err: Error, logEvent: DecodedLogEvent<LogCancelContractEventArgs>) => {
|
||||||
expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogCancel);
|
expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogCancel);
|
||||||
done();
|
done();
|
||||||
};
|
};
|
||||||
zeroEx.exchange.subscribe(
|
zeroEx.exchange.subscribe(ExchangeEvents.LogCancel, indexFilterValues, callback);
|
||||||
ExchangeEvents.LogCancel, indexFilterValues, callback,
|
|
||||||
);
|
|
||||||
await zeroEx.exchange.cancelOrderAsync(signedOrder, cancelTakerAmountInBaseUnits);
|
await zeroEx.exchange.cancelOrderAsync(signedOrder, cancelTakerAmountInBaseUnits);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('Outstanding subscriptions are cancelled when zeroEx.setProvider called', (done: DoneCallback) => {
|
it('Outstanding subscriptions are cancelled when zeroEx.setProvider called', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
|
|
||||||
const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
|
const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<LogFillContractEventArgs>) => {
|
||||||
done(new Error('Expected this subscription to have been cancelled'));
|
done(new Error('Expected this subscription to have been cancelled'));
|
||||||
};
|
};
|
||||||
zeroEx.exchange.subscribe(
|
zeroEx.exchange.subscribe(ExchangeEvents.LogFill, indexFilterValues, callbackNeverToBeCalled);
|
||||||
ExchangeEvents.LogFill, indexFilterValues, callbackNeverToBeCalled,
|
|
||||||
);
|
|
||||||
|
|
||||||
const newProvider = web3Factory.getRpcProvider();
|
const newProvider = web3Factory.getRpcProvider();
|
||||||
zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID);
|
zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID);
|
||||||
@ -698,11 +888,11 @@ describe('ExchangeWrapper', () => {
|
|||||||
expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogFill);
|
expect(logEvent.log.event).to.be.equal(ExchangeEvents.LogFill);
|
||||||
done();
|
done();
|
||||||
};
|
};
|
||||||
zeroEx.exchange.subscribe(
|
zeroEx.exchange.subscribe(ExchangeEvents.LogFill, indexFilterValues, callback);
|
||||||
ExchangeEvents.LogFill, indexFilterValues, callback,
|
|
||||||
);
|
|
||||||
await zeroEx.exchange.fillOrderAsync(
|
await zeroEx.exchange.fillOrderAsync(
|
||||||
signedOrder, takerTokenFillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance,
|
signedOrder,
|
||||||
|
takerTokenFillAmountInBaseUnits,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
takerAddress,
|
takerAddress,
|
||||||
);
|
);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
@ -713,11 +903,15 @@ describe('ExchangeWrapper', () => {
|
|||||||
done(new Error('Expected this subscription to have been cancelled'));
|
done(new Error('Expected this subscription to have been cancelled'));
|
||||||
};
|
};
|
||||||
const subscriptionToken = zeroEx.exchange.subscribe(
|
const subscriptionToken = zeroEx.exchange.subscribe(
|
||||||
ExchangeEvents.LogFill, indexFilterValues, callbackNeverToBeCalled,
|
ExchangeEvents.LogFill,
|
||||||
|
indexFilterValues,
|
||||||
|
callbackNeverToBeCalled,
|
||||||
);
|
);
|
||||||
zeroEx.exchange.unsubscribe(subscriptionToken);
|
zeroEx.exchange.unsubscribe(subscriptionToken);
|
||||||
await zeroEx.exchange.fillOrderAsync(
|
await zeroEx.exchange.fillOrderAsync(
|
||||||
signedOrder, takerTokenFillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance,
|
signedOrder,
|
||||||
|
takerTokenFillAmountInBaseUnits,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
takerAddress,
|
takerAddress,
|
||||||
);
|
);
|
||||||
done();
|
done();
|
||||||
@ -736,13 +930,18 @@ describe('ExchangeWrapper', () => {
|
|||||||
makerTokenAddress = makerToken.address;
|
makerTokenAddress = makerToken.address;
|
||||||
takerTokenAddress = takerToken.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(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
const orderHashFromContract = await (zeroEx.exchange as any)
|
const orderHashFromContract = await (zeroEx.exchange as any)._getOrderHashHexUsingContractCallAsync(
|
||||||
._getOrderHashHexUsingContractCallAsync(signedOrder);
|
signedOrder,
|
||||||
|
);
|
||||||
expect(orderHash).to.equal(orderHashFromContract);
|
expect(orderHash).to.equal(orderHashFromContract);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -773,10 +972,17 @@ describe('ExchangeWrapper', () => {
|
|||||||
});
|
});
|
||||||
it('should get logs with decoded args emitted by LogFill', async () => {
|
it('should get logs with decoded args emitted by LogFill', async () => {
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
txHash = await zeroEx.exchange.fillOrderAsync(
|
txHash = await zeroEx.exchange.fillOrderAsync(
|
||||||
signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
|
signedOrder,
|
||||||
|
fillableAmount,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
takerAddress,
|
||||||
);
|
);
|
||||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||||
const eventName = ExchangeEvents.LogFill;
|
const eventName = ExchangeEvents.LogFill;
|
||||||
@ -787,10 +993,17 @@ describe('ExchangeWrapper', () => {
|
|||||||
});
|
});
|
||||||
it('should only get the logs with the correct event name', async () => {
|
it('should only get the logs with the correct event name', async () => {
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
txHash = await zeroEx.exchange.fillOrderAsync(
|
txHash = await zeroEx.exchange.fillOrderAsync(
|
||||||
signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
|
signedOrder,
|
||||||
|
fillableAmount,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
takerAddress,
|
||||||
);
|
);
|
||||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||||
const differentEventName = ExchangeEvents.LogCancel;
|
const differentEventName = ExchangeEvents.LogCancel;
|
||||||
@ -800,19 +1013,33 @@ describe('ExchangeWrapper', () => {
|
|||||||
});
|
});
|
||||||
it('should only get the logs with the correct indexed fields', async () => {
|
it('should only get the logs with the correct indexed fields', async () => {
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
txHash = await zeroEx.exchange.fillOrderAsync(
|
txHash = await zeroEx.exchange.fillOrderAsync(
|
||||||
signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
|
signedOrder,
|
||||||
|
fillableAmount,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
takerAddress,
|
||||||
);
|
);
|
||||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||||
|
|
||||||
const differentMakerAddress = userAddresses[2];
|
const differentMakerAddress = userAddresses[2];
|
||||||
const anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, differentMakerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
differentMakerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
txHash = await zeroEx.exchange.fillOrderAsync(
|
txHash = await zeroEx.exchange.fillOrderAsync(
|
||||||
anotherSignedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
|
anotherSignedOrder,
|
||||||
|
fillableAmount,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
takerAddress,
|
||||||
);
|
);
|
||||||
await zeroEx.awaitTransactionMinedAsync(txHash);
|
await zeroEx.awaitTransactionMinedAsync(txHash);
|
||||||
|
|
||||||
@ -821,7 +1048,9 @@ describe('ExchangeWrapper', () => {
|
|||||||
maker: differentMakerAddress,
|
maker: differentMakerAddress,
|
||||||
};
|
};
|
||||||
const logs = await zeroEx.exchange.getLogsAsync<LogFillContractEventArgs>(
|
const logs = await zeroEx.exchange.getLogsAsync<LogFillContractEventArgs>(
|
||||||
eventName, blockRange, indexFilterValues,
|
eventName,
|
||||||
|
blockRange,
|
||||||
|
indexFilterValues,
|
||||||
);
|
);
|
||||||
expect(logs).to.have.length(1);
|
expect(logs).to.have.length(1);
|
||||||
const args = logs[0].args;
|
const args = logs[0].args;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {BlockchainLifecycle} from '@0xproject/dev-utils';
|
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
@ -6,18 +6,18 @@ import 'mocha';
|
|||||||
import * as Sinon from 'sinon';
|
import * as Sinon from 'sinon';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import {ZeroEx} from '../src/0x';
|
import { ZeroEx } from '../src/0x';
|
||||||
import {ExpirationWatcher} from '../src/order_watcher/expiration_watcher';
|
import { ExpirationWatcher } from '../src/order_watcher/expiration_watcher';
|
||||||
import {DoneCallback, Token} from '../src/types';
|
import { DoneCallback, Token } from '../src/types';
|
||||||
import {constants} from '../src/utils/constants';
|
import { constants } from '../src/utils/constants';
|
||||||
import {utils} from '../src/utils/utils';
|
import { utils } from '../src/utils/utils';
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {constants as testConstants} from './utils/constants';
|
import { constants as testConstants } from './utils/constants';
|
||||||
import {FillScenarios} from './utils/fill_scenarios';
|
import { FillScenarios } from './utils/fill_scenarios';
|
||||||
import {reportCallbackErrors} from './utils/report_callback_errors';
|
import { reportCallbackErrors } from './utils/report_callback_errors';
|
||||||
import {TokenUtils} from './utils/token_utils';
|
import { TokenUtils } from './utils/token_utils';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
import { web3Factory } from './utils/web3_factory';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
@ -62,7 +62,7 @@ describe('ExpirationWatcher', () => {
|
|||||||
});
|
});
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await blockchainLifecycle.startAsync();
|
await blockchainLifecycle.startAsync();
|
||||||
const sinonTimerConfig = {shouldAdvanceTime: true} as any;
|
const sinonTimerConfig = { shouldAdvanceTime: true } as any;
|
||||||
// This constructor has incorrect types
|
// This constructor has incorrect types
|
||||||
timer = Sinon.useFakeTimers(sinonTimerConfig);
|
timer = Sinon.useFakeTimers(sinonTimerConfig);
|
||||||
currentUnixTimestampSec = utils.getCurrentUnixTimestampSec();
|
currentUnixTimestampSec = utils.getCurrentUnixTimestampSec();
|
||||||
@ -78,7 +78,11 @@ describe('ExpirationWatcher', () => {
|
|||||||
const orderLifetimeSec = 60;
|
const orderLifetimeSec = 60;
|
||||||
const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec);
|
const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec);
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
expirationUnixTimestampSec,
|
expirationUnixTimestampSec,
|
||||||
);
|
);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
@ -92,12 +96,16 @@ describe('ExpirationWatcher', () => {
|
|||||||
timer.tick(orderLifetimeSec * 1000);
|
timer.tick(orderLifetimeSec * 1000);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('doesn\'t emit events before order expires', (done: DoneCallback) => {
|
it("doesn't emit events before order expires", (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const orderLifetimeSec = 60;
|
const orderLifetimeSec = 60;
|
||||||
const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec);
|
const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec);
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
expirationUnixTimestampSec,
|
expirationUnixTimestampSec,
|
||||||
);
|
);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
@ -118,11 +126,19 @@ describe('ExpirationWatcher', () => {
|
|||||||
const order1ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order1Lifetime);
|
const order1ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order1Lifetime);
|
||||||
const order2ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order2Lifetime);
|
const order2ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order2Lifetime);
|
||||||
const signedOrder1 = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder1 = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
order1ExpirationUnixTimestampSec,
|
order1ExpirationUnixTimestampSec,
|
||||||
);
|
);
|
||||||
const signedOrder2 = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder2 = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
order2ExpirationUnixTimestampSec,
|
order2ExpirationUnixTimestampSec,
|
||||||
);
|
);
|
||||||
const orderHash1 = ZeroEx.getOrderHashHex(signedOrder1);
|
const orderHash1 = ZeroEx.getOrderHashHex(signedOrder1);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {BlockchainLifecycle} from '@0xproject/dev-utils';
|
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
@ -15,14 +15,14 @@ import {
|
|||||||
ZeroEx,
|
ZeroEx,
|
||||||
ZeroExError,
|
ZeroExError,
|
||||||
} from '../src';
|
} from '../src';
|
||||||
import {DoneCallback} from '../src/types';
|
import { DoneCallback } from '../src/types';
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
import {FillScenarios} from './utils/fill_scenarios';
|
import { FillScenarios } from './utils/fill_scenarios';
|
||||||
import {reportCallbackErrors} from './utils/report_callback_errors';
|
import { reportCallbackErrors } from './utils/report_callback_errors';
|
||||||
import {TokenUtils} from './utils/token_utils';
|
import { TokenUtils } from './utils/token_utils';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
import { web3Factory } from './utils/web3_factory';
|
||||||
|
|
||||||
const TIMEOUT_MS = 150;
|
const TIMEOUT_MS = 150;
|
||||||
|
|
||||||
@ -71,7 +71,11 @@ describe('OrderStateWatcher', () => {
|
|||||||
describe('#removeOrder', async () => {
|
describe('#removeOrder', async () => {
|
||||||
it('should successfully remove existing order', async () => {
|
it('should successfully remove existing order', async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
@ -89,10 +93,18 @@ describe('OrderStateWatcher', () => {
|
|||||||
});
|
});
|
||||||
it('should no-op when removing a non-existing order', async () => {
|
it('should no-op when removing a non-existing order', async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
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);
|
zeroEx.orderStateWatcher.removeOrder(nonExistentOrderHash);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -102,8 +114,7 @@ describe('OrderStateWatcher', () => {
|
|||||||
});
|
});
|
||||||
it('should fail when trying to subscribe twice', async () => {
|
it('should fail when trying to subscribe twice', async () => {
|
||||||
zeroEx.orderStateWatcher.subscribe(_.noop);
|
zeroEx.orderStateWatcher.subscribe(_.noop);
|
||||||
expect(() => zeroEx.orderStateWatcher.subscribe(_.noop))
|
expect(() => zeroEx.orderStateWatcher.subscribe(_.noop)).to.throw(ZeroExError.SubscriptionAlreadyPresent);
|
||||||
.to.throw(ZeroExError.SubscriptionAlreadyPresent);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('tests with cleanup', async () => {
|
describe('tests with cleanup', async () => {
|
||||||
@ -115,7 +126,11 @@ describe('OrderStateWatcher', () => {
|
|||||||
it('should emit orderStateInvalid when maker allowance set to 0 for watched order', (done: DoneCallback) => {
|
it('should emit orderStateInvalid when maker allowance set to 0 for watched order', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
@ -133,7 +148,11 @@ describe('OrderStateWatcher', () => {
|
|||||||
it('should not emit an orderState event when irrelevant Transfer event received', (done: DoneCallback) => {
|
it('should not emit an orderState event when irrelevant Transfer event received', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||||
@ -152,7 +171,11 @@ describe('OrderStateWatcher', () => {
|
|||||||
it('should emit orderStateInvalid when maker moves balance backing watched order', (done: DoneCallback) => {
|
it('should emit orderStateInvalid when maker moves balance backing watched order', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
@ -172,7 +195,11 @@ describe('OrderStateWatcher', () => {
|
|||||||
it('should emit orderStateInvalid when watched order fully filled', (done: DoneCallback) => {
|
it('should emit orderStateInvalid when watched order fully filled', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
@ -188,14 +215,21 @@ describe('OrderStateWatcher', () => {
|
|||||||
|
|
||||||
const shouldThrowOnInsufficientBalanceOrAllowance = true;
|
const shouldThrowOnInsufficientBalanceOrAllowance = true;
|
||||||
await zeroEx.exchange.fillOrderAsync(
|
await zeroEx.exchange.fillOrderAsync(
|
||||||
signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, taker,
|
signedOrder,
|
||||||
|
fillableAmount,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
taker,
|
||||||
);
|
);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('should emit orderStateValid when watched order partially filled', (done: DoneCallback) => {
|
it('should emit orderStateValid when watched order partially filled', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
|
|
||||||
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
|
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
|
||||||
@ -211,16 +245,21 @@ describe('OrderStateWatcher', () => {
|
|||||||
const remainingMakerBalance = makerBalance.sub(fillAmountInBaseUnits);
|
const remainingMakerBalance = makerBalance.sub(fillAmountInBaseUnits);
|
||||||
const remainingFillable = fillableAmount.minus(fillAmountInBaseUnits);
|
const remainingFillable = fillableAmount.minus(fillAmountInBaseUnits);
|
||||||
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
||||||
remainingFillable);
|
remainingFillable,
|
||||||
|
);
|
||||||
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
|
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
|
||||||
remainingFillable);
|
remainingFillable,
|
||||||
|
);
|
||||||
expect(orderRelevantState.makerBalance).to.be.bignumber.equal(remainingMakerBalance);
|
expect(orderRelevantState.makerBalance).to.be.bignumber.equal(remainingMakerBalance);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
const shouldThrowOnInsufficientBalanceOrAllowance = true;
|
const shouldThrowOnInsufficientBalanceOrAllowance = true;
|
||||||
await zeroEx.exchange.fillOrderAsync(
|
await zeroEx.exchange.fillOrderAsync(
|
||||||
signedOrder, fillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance, taker,
|
signedOrder,
|
||||||
|
fillAmountInBaseUnits,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
taker,
|
||||||
);
|
);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
@ -229,8 +268,15 @@ describe('OrderStateWatcher', () => {
|
|||||||
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(2), 18);
|
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(2), 18);
|
||||||
const takerFee = ZeroEx.toBaseUnitAmount(new BigNumber(0), 18);
|
const takerFee = ZeroEx.toBaseUnitAmount(new BigNumber(0), 18);
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||||
makerToken.address, takerToken.address, makerFee, takerFee, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
taker);
|
takerToken.address,
|
||||||
|
makerFee,
|
||||||
|
takerFee,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
|
taker,
|
||||||
|
);
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -245,7 +291,11 @@ describe('OrderStateWatcher', () => {
|
|||||||
const takerFillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(10), decimals);
|
const takerFillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(10), decimals);
|
||||||
const makerFillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(20), decimals);
|
const makerFillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(20), decimals);
|
||||||
signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, makerFillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
makerFillableAmount,
|
||||||
takerFillableAmount,
|
takerFillableAmount,
|
||||||
);
|
);
|
||||||
const fillAmountInBaseUnits = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
const fillAmountInBaseUnits = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
||||||
@ -257,22 +307,31 @@ describe('OrderStateWatcher', () => {
|
|||||||
expect(validOrderState.orderHash).to.be.equal(orderHash);
|
expect(validOrderState.orderHash).to.be.equal(orderHash);
|
||||||
const orderRelevantState = validOrderState.orderRelevantState;
|
const orderRelevantState = validOrderState.orderRelevantState;
|
||||||
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
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(
|
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
|
||||||
ZeroEx.toBaseUnitAmount(new BigNumber(8), decimals));
|
ZeroEx.toBaseUnitAmount(new BigNumber(8), decimals),
|
||||||
|
);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
const shouldThrowOnInsufficientBalanceOrAllowance = true;
|
const shouldThrowOnInsufficientBalanceOrAllowance = true;
|
||||||
await zeroEx.exchange.fillOrderAsync(
|
await zeroEx.exchange.fillOrderAsync(
|
||||||
signedOrder, fillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance, taker,
|
signedOrder,
|
||||||
|
fillAmountInBaseUnits,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
taker,
|
||||||
);
|
);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('should equal approved amount when approved amount is lowest', (done: DoneCallback) => {
|
it('should equal approved amount when approved amount is lowest', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
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);
|
const changedMakerApprovalAmount = ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals);
|
||||||
@ -282,9 +341,11 @@ describe('OrderStateWatcher', () => {
|
|||||||
const validOrderState = orderState as OrderStateValid;
|
const validOrderState = orderState as OrderStateValid;
|
||||||
const orderRelevantState = validOrderState.orderRelevantState;
|
const orderRelevantState = validOrderState.orderRelevantState;
|
||||||
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
||||||
changedMakerApprovalAmount);
|
changedMakerApprovalAmount,
|
||||||
|
);
|
||||||
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
|
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
|
||||||
changedMakerApprovalAmount);
|
changedMakerApprovalAmount,
|
||||||
|
);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
@ -294,7 +355,11 @@ describe('OrderStateWatcher', () => {
|
|||||||
it('should equal balance amount when balance amount is lowest', (done: DoneCallback) => {
|
it('should equal balance amount when balance amount is lowest', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
|
|
||||||
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
|
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
|
||||||
@ -308,14 +373,15 @@ describe('OrderStateWatcher', () => {
|
|||||||
const validOrderState = orderState as OrderStateValid;
|
const validOrderState = orderState as OrderStateValid;
|
||||||
const orderRelevantState = validOrderState.orderRelevantState;
|
const orderRelevantState = validOrderState.orderRelevantState;
|
||||||
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
||||||
remainingAmount);
|
remainingAmount,
|
||||||
|
);
|
||||||
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
|
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
|
||||||
remainingAmount);
|
remainingAmount,
|
||||||
|
);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
await zeroEx.token.transferAsync(
|
await zeroEx.token.transferAsync(makerToken.address, maker, ZeroEx.NULL_ADDRESS, transferAmount);
|
||||||
makerToken.address, maker, ZeroEx.NULL_ADDRESS, transferAmount);
|
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('should equal remaining amount when partially cancelled and order has fees', (done: DoneCallback) => {
|
it('should equal remaining amount when partially cancelled and order has fees', (done: DoneCallback) => {
|
||||||
@ -324,8 +390,15 @@ describe('OrderStateWatcher', () => {
|
|||||||
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals);
|
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals);
|
||||||
const feeRecipient = taker;
|
const feeRecipient = taker;
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||||
makerToken.address, takerToken.address, makerFee, takerFee, maker,
|
makerToken.address,
|
||||||
taker, fillableAmount, feeRecipient);
|
takerToken.address,
|
||||||
|
makerFee,
|
||||||
|
takerFee,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
|
feeRecipient,
|
||||||
|
);
|
||||||
|
|
||||||
const remainingTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(4), decimals);
|
const remainingTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(4), decimals);
|
||||||
const transferTokenAmount = makerFee.sub(remainingTokenAmount);
|
const transferTokenAmount = makerFee.sub(remainingTokenAmount);
|
||||||
@ -336,7 +409,8 @@ describe('OrderStateWatcher', () => {
|
|||||||
const validOrderState = orderState as OrderStateValid;
|
const validOrderState = orderState as OrderStateValid;
|
||||||
const orderRelevantState = validOrderState.orderRelevantState;
|
const orderRelevantState = validOrderState.orderRelevantState;
|
||||||
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
||||||
remainingTokenAmount);
|
remainingTokenAmount,
|
||||||
|
);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
@ -349,8 +423,15 @@ describe('OrderStateWatcher', () => {
|
|||||||
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals);
|
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals);
|
||||||
const feeRecipient = taker;
|
const feeRecipient = taker;
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||||
makerToken.address, takerToken.address, makerFee, takerFee, maker,
|
makerToken.address,
|
||||||
taker, fillableAmount, feeRecipient);
|
takerToken.address,
|
||||||
|
makerFee,
|
||||||
|
takerFee,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
|
feeRecipient,
|
||||||
|
);
|
||||||
|
|
||||||
const remainingFeeAmount = ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals);
|
const remainingFeeAmount = ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals);
|
||||||
|
|
||||||
@ -362,13 +443,18 @@ describe('OrderStateWatcher', () => {
|
|||||||
const validOrderState = orderState as OrderStateValid;
|
const validOrderState = orderState as OrderStateValid;
|
||||||
const orderRelevantState = validOrderState.orderRelevantState;
|
const orderRelevantState = validOrderState.orderRelevantState;
|
||||||
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
||||||
remainingFeeAmount);
|
remainingFeeAmount,
|
||||||
|
);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
await zeroEx.token.setProxyAllowanceAsync(zrxTokenAddress, maker, remainingFeeAmount);
|
await zeroEx.token.setProxyAllowanceAsync(zrxTokenAddress, maker, remainingFeeAmount);
|
||||||
await zeroEx.token.transferAsync(
|
await zeroEx.token.transferAsync(
|
||||||
makerToken.address, maker, ZeroEx.NULL_ADDRESS, transferTokenAmount);
|
makerToken.address,
|
||||||
|
maker,
|
||||||
|
ZeroEx.NULL_ADDRESS,
|
||||||
|
transferTokenAmount,
|
||||||
|
);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('should calculate full amount when all available and non-divisible', (done: DoneCallback) => {
|
it('should calculate full amount when all available and non-divisible', (done: DoneCallback) => {
|
||||||
@ -377,8 +463,15 @@ describe('OrderStateWatcher', () => {
|
|||||||
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
||||||
const feeRecipient = taker;
|
const feeRecipient = taker;
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||||
makerToken.address, takerToken.address, makerFee, takerFee, maker,
|
makerToken.address,
|
||||||
taker, fillableAmount, feeRecipient);
|
takerToken.address,
|
||||||
|
makerFee,
|
||||||
|
takerFee,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
|
feeRecipient,
|
||||||
|
);
|
||||||
|
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
|
|
||||||
@ -386,19 +479,27 @@ describe('OrderStateWatcher', () => {
|
|||||||
const validOrderState = orderState as OrderStateValid;
|
const validOrderState = orderState as OrderStateValid;
|
||||||
const orderRelevantState = validOrderState.orderRelevantState;
|
const orderRelevantState = validOrderState.orderRelevantState;
|
||||||
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
|
||||||
fillableAmount);
|
fillableAmount,
|
||||||
|
);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
await zeroEx.token.setProxyAllowanceAsync(
|
await zeroEx.token.setProxyAllowanceAsync(
|
||||||
makerToken.address, maker, ZeroEx.toBaseUnitAmount(new BigNumber(100), decimals));
|
makerToken.address,
|
||||||
|
maker,
|
||||||
|
ZeroEx.toBaseUnitAmount(new BigNumber(100), decimals),
|
||||||
|
);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('should emit orderStateInvalid when watched order cancelled', (done: DoneCallback) => {
|
it('should emit orderStateInvalid when watched order cancelled', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
@ -419,7 +520,11 @@ describe('OrderStateWatcher', () => {
|
|||||||
(async () => {
|
(async () => {
|
||||||
const remainingFillableAmountInBaseUnits = new BigNumber(100);
|
const remainingFillableAmountInBaseUnits = new BigNumber(100);
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
||||||
@ -433,14 +538,19 @@ describe('OrderStateWatcher', () => {
|
|||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
await zeroEx.exchange.cancelOrderAsync(
|
await zeroEx.exchange.cancelOrderAsync(
|
||||||
signedOrder, fillableAmount.minus(remainingFillableAmountInBaseUnits),
|
signedOrder,
|
||||||
|
fillableAmount.minus(remainingFillableAmountInBaseUnits),
|
||||||
);
|
);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('should emit orderStateValid when watched order partially cancelled', (done: DoneCallback) => {
|
it('should emit orderStateValid when watched order partially cancelled', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
makerToken.address,
|
||||||
|
takerToken.address,
|
||||||
|
maker,
|
||||||
|
taker,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
|
|
||||||
const cancelAmountInBaseUnits = new BigNumber(2);
|
const cancelAmountInBaseUnits = new BigNumber(2);
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
import {BlockchainLifecycle} from '@0xproject/dev-utils';
|
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import * as Sinon from 'sinon';
|
import * as Sinon from 'sinon';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import {ExchangeContractErrs, SignedOrder, Token, ZeroEx, ZeroExError} from '../src';
|
import { ExchangeContractErrs, SignedOrder, Token, ZeroEx, ZeroExError } from '../src';
|
||||||
import {BlockParamLiteral, TradeSide, TransferType} from '../src/types';
|
import { BlockParamLiteral, TradeSide, TransferType } from '../src/types';
|
||||||
import {ExchangeTransferSimulator} from '../src/utils/exchange_transfer_simulator';
|
import { ExchangeTransferSimulator } from '../src/utils/exchange_transfer_simulator';
|
||||||
import {OrderValidationUtils} from '../src/utils/order_validation_utils';
|
import { OrderValidationUtils } from '../src/utils/order_validation_utils';
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
import {FillScenarios} from './utils/fill_scenarios';
|
import { FillScenarios } from './utils/fill_scenarios';
|
||||||
import {TokenUtils} from './utils/token_utils';
|
import { TokenUtils } from './utils/token_utils';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
import { web3Factory } from './utils/web3_factory';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
@ -62,108 +62,152 @@ describe('OrderValidation', () => {
|
|||||||
describe('validateOrderFillableOrThrowAsync', () => {
|
describe('validateOrderFillableOrThrowAsync', () => {
|
||||||
it('should succeed if the order is fillable', async () => {
|
it('should succeed if the order is fillable', async () => {
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
);
|
takerTokenAddress,
|
||||||
await zeroEx.exchange.validateOrderFillableOrThrowAsync(
|
makerAddress,
|
||||||
signedOrder,
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
|
await zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder);
|
||||||
});
|
});
|
||||||
it('should succeed if the order is asymmetric and fillable', async () => {
|
it('should succeed if the order is asymmetric and fillable', async () => {
|
||||||
const makerFillableAmount = fillableAmount;
|
const makerFillableAmount = fillableAmount;
|
||||||
const takerFillableAmount = fillableAmount.minus(4);
|
const takerFillableAmount = fillableAmount.minus(4);
|
||||||
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
makerTokenAddress,
|
||||||
makerFillableAmount, takerFillableAmount,
|
takerTokenAddress,
|
||||||
);
|
makerAddress,
|
||||||
await zeroEx.exchange.validateOrderFillableOrThrowAsync(
|
takerAddress,
|
||||||
signedOrder,
|
makerFillableAmount,
|
||||||
|
takerFillableAmount,
|
||||||
);
|
);
|
||||||
|
await zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder);
|
||||||
});
|
});
|
||||||
it('should throw when the order is fully filled or cancelled', async () => {
|
it('should throw when the order is fully filled or cancelled', async () => {
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
|
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
|
||||||
return expect(zeroEx.exchange.validateOrderFillableOrThrowAsync(
|
return expect(zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder)).to.be.rejectedWith(
|
||||||
signedOrder,
|
ExchangeContractErrs.OrderRemainingFillAmountZero,
|
||||||
)).to.be.rejectedWith(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
);
|
||||||
});
|
});
|
||||||
it('should throw when order is expired', async () => {
|
it('should throw when order is expired', async () => {
|
||||||
const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
|
const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
makerTokenAddress,
|
||||||
fillableAmount, expirationInPast,
|
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', () => {
|
describe('validateFillOrderAndThrowIfInvalidAsync', () => {
|
||||||
it('should throw when the fill amount is zero', async () => {
|
it('should throw when the fill amount is zero', async () => {
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const zeroFillAmount = new BigNumber(0);
|
const zeroFillAmount = new BigNumber(0);
|
||||||
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
return expect(
|
||||||
signedOrder, zeroFillAmount, takerAddress,
|
zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, zeroFillAmount, takerAddress),
|
||||||
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
).to.be.rejectedWith(ExchangeContractErrs.OrderFillAmountZero);
|
||||||
});
|
});
|
||||||
it('should throw when the signature is invalid', async () => {
|
it('should throw when the signature is invalid', async () => {
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
// 27 <--> 28
|
// 27 <--> 28
|
||||||
signedOrder.ecSignature.v = (28 - signedOrder.ecSignature.v) + 27;
|
signedOrder.ecSignature.v = 28 - signedOrder.ecSignature.v + 27;
|
||||||
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
return expect(
|
||||||
signedOrder, fillableAmount, takerAddress,
|
zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillableAmount, takerAddress),
|
||||||
)).to.be.rejectedWith(ZeroExError.InvalidSignature);
|
).to.be.rejectedWith(ZeroExError.InvalidSignature);
|
||||||
});
|
});
|
||||||
it('should throw when the order is fully filled or cancelled', async () => {
|
it('should throw when the order is fully filled or cancelled', async () => {
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
|
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
|
||||||
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
return expect(
|
||||||
signedOrder, fillableAmount, takerAddress,
|
zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillableAmount, takerAddress),
|
||||||
)).to.be.rejectedWith(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
).to.be.rejectedWith(ExchangeContractErrs.OrderRemainingFillAmountZero);
|
||||||
});
|
});
|
||||||
it('should throw when sender is not a taker', async () => {
|
it('should throw when sender is not a taker', async () => {
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const nonTakerAddress = userAddresses[6];
|
const nonTakerAddress = userAddresses[6];
|
||||||
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
return expect(
|
||||||
signedOrder, fillTakerAmount, nonTakerAddress,
|
zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillTakerAmount, nonTakerAddress),
|
||||||
)).to.be.rejectedWith(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker);
|
).to.be.rejectedWith(ExchangeContractErrs.TransactionSenderIsNotFillOrderTaker);
|
||||||
});
|
});
|
||||||
it('should throw when order is expired', async () => {
|
it('should throw when order is expired', async () => {
|
||||||
const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
|
const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
makerTokenAddress,
|
||||||
fillableAmount, expirationInPast,
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
|
expirationInPast,
|
||||||
);
|
);
|
||||||
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
return expect(
|
||||||
signedOrder, fillTakerAmount, takerAddress,
|
zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(signedOrder, fillTakerAmount, takerAddress),
|
||||||
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillExpired);
|
).to.be.rejectedWith(ExchangeContractErrs.OrderFillExpired);
|
||||||
});
|
});
|
||||||
it('should throw when there a rounding error would have occurred', async () => {
|
it('should throw when there a rounding error would have occurred', async () => {
|
||||||
const makerAmount = new BigNumber(3);
|
const makerAmount = new BigNumber(3);
|
||||||
const takerAmount = new BigNumber(5);
|
const takerAmount = new BigNumber(5);
|
||||||
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
makerTokenAddress,
|
||||||
makerAmount, takerAmount,
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
makerAmount,
|
||||||
|
takerAmount,
|
||||||
);
|
);
|
||||||
const fillTakerAmountThatCausesRoundingError = new BigNumber(3);
|
const fillTakerAmountThatCausesRoundingError = new BigNumber(3);
|
||||||
return expect(zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
return expect(
|
||||||
signedOrder, fillTakerAmountThatCausesRoundingError, takerAddress,
|
zeroEx.exchange.validateFillOrderThrowIfInvalidAsync(
|
||||||
)).to.be.rejectedWith(ExchangeContractErrs.OrderFillRoundingError);
|
signedOrder,
|
||||||
|
fillTakerAmountThatCausesRoundingError,
|
||||||
|
takerAddress,
|
||||||
|
),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.OrderFillRoundingError);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#validateFillOrKillOrderAndThrowIfInvalidAsync', () => {
|
describe('#validateFillOrKillOrderAndThrowIfInvalidAsync', () => {
|
||||||
it('should throw if remaining fillAmount is less then the desired fillAmount', async () => {
|
it('should throw if remaining fillAmount is less then the desired fillAmount', async () => {
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const tooLargeFillAmount = new BigNumber(7);
|
const tooLargeFillAmount = new BigNumber(7);
|
||||||
const fillAmountDifference = tooLargeFillAmount.minus(fillableAmount);
|
const fillAmountDifference = tooLargeFillAmount.minus(fillableAmount);
|
||||||
@ -172,9 +216,13 @@ describe('OrderValidation', () => {
|
|||||||
await zeroEx.token.transferAsync(makerTokenAddress, coinbase, makerAddress, fillAmountDifference);
|
await zeroEx.token.transferAsync(makerTokenAddress, coinbase, makerAddress, fillAmountDifference);
|
||||||
await zeroEx.token.setProxyAllowanceAsync(makerTokenAddress, makerAddress, tooLargeFillAmount);
|
await zeroEx.token.setProxyAllowanceAsync(makerTokenAddress, makerAddress, tooLargeFillAmount);
|
||||||
|
|
||||||
return expect(zeroEx.exchange.validateFillOrKillOrderThrowIfInvalidAsync(
|
return expect(
|
||||||
signedOrder, tooLargeFillAmount, takerAddress,
|
zeroEx.exchange.validateFillOrKillOrderThrowIfInvalidAsync(
|
||||||
)).to.be.rejectedWith(ExchangeContractErrs.InsufficientRemainingFillAmount);
|
signedOrder,
|
||||||
|
tooLargeFillAmount,
|
||||||
|
takerAddress,
|
||||||
|
),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.InsufficientRemainingFillAmount);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('validateCancelOrderAndThrowIfInvalidAsync', () => {
|
describe('validateCancelOrderAndThrowIfInvalidAsync', () => {
|
||||||
@ -186,27 +234,38 @@ describe('OrderValidation', () => {
|
|||||||
makerTokenAddress = makerToken.address;
|
makerTokenAddress = makerToken.address;
|
||||||
takerTokenAddress = takerToken.address;
|
takerTokenAddress = takerToken.address;
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should throw when cancel amount is zero', async () => {
|
it('should throw when cancel amount is zero', async () => {
|
||||||
const zeroCancelAmount = new BigNumber(0);
|
const zeroCancelAmount = new BigNumber(0);
|
||||||
return expect(zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, zeroCancelAmount))
|
return expect(
|
||||||
.to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, zeroCancelAmount),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.OrderCancelAmountZero);
|
||||||
});
|
});
|
||||||
it('should throw when order is expired', async () => {
|
it('should throw when order is expired', async () => {
|
||||||
const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
|
const expirationInPast = new BigNumber(1496826058); // 7th Jun 2017
|
||||||
const expiredSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
const expiredSignedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
makerTokenAddress,
|
||||||
fillableAmount, expirationInPast,
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
|
expirationInPast,
|
||||||
);
|
);
|
||||||
return expect(zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(expiredSignedOrder, cancelAmount))
|
return expect(
|
||||||
.to.be.rejectedWith(ExchangeContractErrs.OrderCancelExpired);
|
zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(expiredSignedOrder, cancelAmount),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.OrderCancelExpired);
|
||||||
});
|
});
|
||||||
it('should throw when order is already cancelled or filled', async () => {
|
it('should throw when order is already cancelled or filled', async () => {
|
||||||
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
|
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
|
||||||
return expect(zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, fillableAmount))
|
return expect(
|
||||||
.to.be.rejectedWith(ExchangeContractErrs.OrderAlreadyCancelledOrFilled);
|
zeroEx.exchange.validateCancelOrderThrowIfInvalidAsync(signedOrder, fillableAmount),
|
||||||
|
).to.be.rejectedWith(ExchangeContractErrs.OrderAlreadyCancelledOrFilled);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#validateFillOrderBalancesAllowancesThrowIfInvalidAsync', () => {
|
describe('#validateFillOrderBalancesAllowancesThrowIfInvalidAsync', () => {
|
||||||
@ -224,82 +283,159 @@ describe('OrderValidation', () => {
|
|||||||
const makerFee = new BigNumber(2);
|
const makerFee = new BigNumber(2);
|
||||||
const takerFee = new BigNumber(2);
|
const takerFee = new BigNumber(2);
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerFee, takerFee,
|
makerTokenAddress,
|
||||||
makerAddress, takerAddress, fillableAmount, feeRecipient,
|
takerTokenAddress,
|
||||||
|
makerFee,
|
||||||
|
takerFee,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
|
feeRecipient,
|
||||||
);
|
);
|
||||||
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
||||||
exchangeTransferSimulator, signedOrder, fillableAmount, takerAddress, zrxTokenAddress,
|
exchangeTransferSimulator,
|
||||||
|
signedOrder,
|
||||||
|
fillableAmount,
|
||||||
|
takerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
);
|
);
|
||||||
expect(transferFromAsync.callCount).to.be.equal(4);
|
expect(transferFromAsync.callCount).to.be.equal(4);
|
||||||
expect(
|
expect(
|
||||||
transferFromAsync.getCall(0).calledWith(
|
transferFromAsync
|
||||||
makerTokenAddress, makerAddress, takerAddress, bigNumberMatch(fillableAmount),
|
.getCall(0)
|
||||||
TradeSide.Maker, TransferType.Trade,
|
.calledWith(
|
||||||
),
|
makerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
bigNumberMatch(fillableAmount),
|
||||||
|
TradeSide.Maker,
|
||||||
|
TransferType.Trade,
|
||||||
|
),
|
||||||
).to.be.true();
|
).to.be.true();
|
||||||
expect(
|
expect(
|
||||||
transferFromAsync.getCall(1).calledWith(
|
transferFromAsync
|
||||||
takerTokenAddress, takerAddress, makerAddress, bigNumberMatch(fillableAmount),
|
.getCall(1)
|
||||||
TradeSide.Taker, TransferType.Trade,
|
.calledWith(
|
||||||
),
|
takerTokenAddress,
|
||||||
|
takerAddress,
|
||||||
|
makerAddress,
|
||||||
|
bigNumberMatch(fillableAmount),
|
||||||
|
TradeSide.Taker,
|
||||||
|
TransferType.Trade,
|
||||||
|
),
|
||||||
).to.be.true();
|
).to.be.true();
|
||||||
expect(
|
expect(
|
||||||
transferFromAsync.getCall(2).calledWith(
|
transferFromAsync
|
||||||
zrxTokenAddress, makerAddress, feeRecipient, bigNumberMatch(makerFee),
|
.getCall(2)
|
||||||
TradeSide.Maker, TransferType.Fee,
|
.calledWith(
|
||||||
),
|
zrxTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
feeRecipient,
|
||||||
|
bigNumberMatch(makerFee),
|
||||||
|
TradeSide.Maker,
|
||||||
|
TransferType.Fee,
|
||||||
|
),
|
||||||
).to.be.true();
|
).to.be.true();
|
||||||
expect(
|
expect(
|
||||||
transferFromAsync.getCall(3).calledWith(
|
transferFromAsync
|
||||||
zrxTokenAddress, takerAddress, feeRecipient, bigNumberMatch(takerFee),
|
.getCall(3)
|
||||||
TradeSide.Taker, TransferType.Fee,
|
.calledWith(
|
||||||
),
|
zrxTokenAddress,
|
||||||
|
takerAddress,
|
||||||
|
feeRecipient,
|
||||||
|
bigNumberMatch(takerFee),
|
||||||
|
TradeSide.Taker,
|
||||||
|
TransferType.Fee,
|
||||||
|
),
|
||||||
).to.be.true();
|
).to.be.true();
|
||||||
});
|
});
|
||||||
it('should call exchangeTransferSimulator.transferFrom with correct values for an open order', async () => {
|
it('should call exchangeTransferSimulator.transferFrom with correct values for an open order', async () => {
|
||||||
const makerFee = new BigNumber(2);
|
const makerFee = new BigNumber(2);
|
||||||
const takerFee = new BigNumber(2);
|
const takerFee = new BigNumber(2);
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerFee, takerFee,
|
makerTokenAddress,
|
||||||
makerAddress, ZeroEx.NULL_ADDRESS, fillableAmount, feeRecipient,
|
takerTokenAddress,
|
||||||
|
makerFee,
|
||||||
|
takerFee,
|
||||||
|
makerAddress,
|
||||||
|
ZeroEx.NULL_ADDRESS,
|
||||||
|
fillableAmount,
|
||||||
|
feeRecipient,
|
||||||
);
|
);
|
||||||
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
||||||
exchangeTransferSimulator, signedOrder, fillableAmount, takerAddress, zrxTokenAddress,
|
exchangeTransferSimulator,
|
||||||
|
signedOrder,
|
||||||
|
fillableAmount,
|
||||||
|
takerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
);
|
);
|
||||||
expect(transferFromAsync.callCount).to.be.equal(4);
|
expect(transferFromAsync.callCount).to.be.equal(4);
|
||||||
expect(
|
expect(
|
||||||
transferFromAsync.getCall(0).calledWith(
|
transferFromAsync
|
||||||
makerTokenAddress, makerAddress, takerAddress, bigNumberMatch(fillableAmount),
|
.getCall(0)
|
||||||
TradeSide.Maker, TransferType.Trade,
|
.calledWith(
|
||||||
),
|
makerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
bigNumberMatch(fillableAmount),
|
||||||
|
TradeSide.Maker,
|
||||||
|
TransferType.Trade,
|
||||||
|
),
|
||||||
).to.be.true();
|
).to.be.true();
|
||||||
expect(
|
expect(
|
||||||
transferFromAsync.getCall(1).calledWith(
|
transferFromAsync
|
||||||
takerTokenAddress, takerAddress, makerAddress, bigNumberMatch(fillableAmount),
|
.getCall(1)
|
||||||
TradeSide.Taker, TransferType.Trade,
|
.calledWith(
|
||||||
),
|
takerTokenAddress,
|
||||||
|
takerAddress,
|
||||||
|
makerAddress,
|
||||||
|
bigNumberMatch(fillableAmount),
|
||||||
|
TradeSide.Taker,
|
||||||
|
TransferType.Trade,
|
||||||
|
),
|
||||||
).to.be.true();
|
).to.be.true();
|
||||||
expect(
|
expect(
|
||||||
transferFromAsync.getCall(2).calledWith(
|
transferFromAsync
|
||||||
zrxTokenAddress, makerAddress, feeRecipient, bigNumberMatch(makerFee),
|
.getCall(2)
|
||||||
TradeSide.Maker, TransferType.Fee,
|
.calledWith(
|
||||||
),
|
zrxTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
feeRecipient,
|
||||||
|
bigNumberMatch(makerFee),
|
||||||
|
TradeSide.Maker,
|
||||||
|
TransferType.Fee,
|
||||||
|
),
|
||||||
).to.be.true();
|
).to.be.true();
|
||||||
expect(
|
expect(
|
||||||
transferFromAsync.getCall(3).calledWith(
|
transferFromAsync
|
||||||
zrxTokenAddress, takerAddress, feeRecipient, bigNumberMatch(takerFee),
|
.getCall(3)
|
||||||
TradeSide.Taker, TransferType.Fee,
|
.calledWith(
|
||||||
),
|
zrxTokenAddress,
|
||||||
|
takerAddress,
|
||||||
|
feeRecipient,
|
||||||
|
bigNumberMatch(takerFee),
|
||||||
|
TradeSide.Taker,
|
||||||
|
TransferType.Fee,
|
||||||
|
),
|
||||||
).to.be.true();
|
).to.be.true();
|
||||||
});
|
});
|
||||||
it('should correctly round the fillMakerTokenAmount', async () => {
|
it('should correctly round the fillMakerTokenAmount', async () => {
|
||||||
const makerTokenAmount = new BigNumber(3);
|
const makerTokenAmount = new BigNumber(3);
|
||||||
const takerTokenAmount = new BigNumber(1);
|
const takerTokenAmount = new BigNumber(1);
|
||||||
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
const signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, makerTokenAmount, takerTokenAmount,
|
makerTokenAddress,
|
||||||
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
makerTokenAmount,
|
||||||
|
takerTokenAmount,
|
||||||
);
|
);
|
||||||
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
||||||
exchangeTransferSimulator, signedOrder, takerTokenAmount, takerAddress, zrxTokenAddress,
|
exchangeTransferSimulator,
|
||||||
|
signedOrder,
|
||||||
|
takerTokenAmount,
|
||||||
|
takerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
);
|
);
|
||||||
expect(transferFromAsync.callCount).to.be.equal(4);
|
expect(transferFromAsync.callCount).to.be.equal(4);
|
||||||
const makerFillAmount = transferFromAsync.getCall(0).args[3];
|
const makerFillAmount = transferFromAsync.getCall(0).args[3];
|
||||||
@ -309,12 +445,22 @@ describe('OrderValidation', () => {
|
|||||||
const makerFee = new BigNumber(2);
|
const makerFee = new BigNumber(2);
|
||||||
const takerFee = new BigNumber(4);
|
const takerFee = new BigNumber(4);
|
||||||
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress,
|
makerTokenAddress,
|
||||||
fillableAmount, ZeroEx.NULL_ADDRESS,
|
takerTokenAddress,
|
||||||
|
makerFee,
|
||||||
|
takerFee,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
|
ZeroEx.NULL_ADDRESS,
|
||||||
);
|
);
|
||||||
const fillTakerTokenAmount = fillableAmount.div(2).round(0);
|
const fillTakerTokenAmount = fillableAmount.div(2).round(0);
|
||||||
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
|
||||||
exchangeTransferSimulator, signedOrder, fillTakerTokenAmount, takerAddress, zrxTokenAddress,
|
exchangeTransferSimulator,
|
||||||
|
signedOrder,
|
||||||
|
fillTakerTokenAmount,
|
||||||
|
takerAddress,
|
||||||
|
zrxTokenAddress,
|
||||||
);
|
);
|
||||||
const makerPartialFee = makerFee.div(2);
|
const makerPartialFee = makerFee.div(2);
|
||||||
const takerPartialFee = takerFee.div(2);
|
const takerPartialFee = takerFee.div(2);
|
||||||
|
@ -2,11 +2,11 @@ import BigNumber from 'bignumber.js';
|
|||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
|
|
||||||
import {ZeroEx} from '../src/0x';
|
import { ZeroEx } from '../src/0x';
|
||||||
import {RemainingFillableCalculator} from '../src/order_watcher/remaining_fillable_calculator';
|
import { RemainingFillableCalculator } from '../src/order_watcher/remaining_fillable_calculator';
|
||||||
import {ECSignature, SignedOrder} from '../src/types';
|
import { ECSignature, SignedOrder } from '../src/types';
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
@ -26,29 +26,34 @@ describe('RemainingFillableCalculator', () => {
|
|||||||
const decimals: number = 4;
|
const decimals: number = 4;
|
||||||
const zero: BigNumber = new BigNumber(0);
|
const zero: BigNumber = new BigNumber(0);
|
||||||
const zeroAddress = '0x0';
|
const zeroAddress = '0x0';
|
||||||
const signature: ECSignature = {v: 27, r: '', s: ''};
|
const signature: ECSignature = { v: 27, r: '', s: '' };
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
[makerAmount, takerAmount, makerFeeAmount] = [ZeroEx.toBaseUnitAmount(new BigNumber(50), decimals),
|
[makerAmount, takerAmount, makerFeeAmount] = [
|
||||||
ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals),
|
ZeroEx.toBaseUnitAmount(new BigNumber(50), decimals),
|
||||||
ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals)];
|
ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals),
|
||||||
|
ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals),
|
||||||
|
];
|
||||||
[transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount] = [
|
[transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount] = [
|
||||||
ZeroEx.toBaseUnitAmount(new BigNumber(50), decimals),
|
ZeroEx.toBaseUnitAmount(new BigNumber(50), decimals),
|
||||||
ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals)];
|
ZeroEx.toBaseUnitAmount(new BigNumber(5), decimals),
|
||||||
|
];
|
||||||
});
|
});
|
||||||
function buildSignedOrder(): SignedOrder {
|
function buildSignedOrder(): SignedOrder {
|
||||||
return { ecSignature: signature,
|
return {
|
||||||
exchangeContractAddress: zeroAddress,
|
ecSignature: signature,
|
||||||
feeRecipient: zeroAddress,
|
exchangeContractAddress: zeroAddress,
|
||||||
maker: zeroAddress,
|
feeRecipient: zeroAddress,
|
||||||
taker: zeroAddress,
|
maker: zeroAddress,
|
||||||
makerFee: makerFeeAmount,
|
taker: zeroAddress,
|
||||||
takerFee: zero,
|
makerFee: makerFeeAmount,
|
||||||
makerTokenAmount: makerAmount,
|
takerFee: zero,
|
||||||
takerTokenAmount: takerAmount,
|
makerTokenAmount: makerAmount,
|
||||||
makerTokenAddress: makerToken,
|
takerTokenAmount: takerAmount,
|
||||||
takerTokenAddress: takerToken,
|
makerTokenAddress: makerToken,
|
||||||
salt: zero,
|
takerTokenAddress: takerToken,
|
||||||
expirationUnixTimestampSec: zero };
|
salt: zero,
|
||||||
|
expirationUnixTimestampSec: zero,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
describe('Maker token is NOT ZRX', () => {
|
describe('Maker token is NOT ZRX', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
@ -57,23 +62,38 @@ describe('RemainingFillableCalculator', () => {
|
|||||||
it('calculates the correct amount when unfilled and funds available', () => {
|
it('calculates the correct amount when unfilled and funds available', () => {
|
||||||
signedOrder = buildSignedOrder();
|
signedOrder = buildSignedOrder();
|
||||||
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
||||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
calculator = new RemainingFillableCalculator(
|
||||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
signedOrder,
|
||||||
|
isMakerTokenZRX,
|
||||||
|
transferrableMakerTokenAmount,
|
||||||
|
transferrableMakerFeeTokenAmount,
|
||||||
|
remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
|
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
|
||||||
});
|
});
|
||||||
it('calculates the correct amount when partially filled and funds available', () => {
|
it('calculates the correct amount when partially filled and funds available', () => {
|
||||||
signedOrder = buildSignedOrder();
|
signedOrder = buildSignedOrder();
|
||||||
remainingMakerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals);
|
remainingMakerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals);
|
||||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
calculator = new RemainingFillableCalculator(
|
||||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
signedOrder,
|
||||||
|
isMakerTokenZRX,
|
||||||
|
transferrableMakerTokenAmount,
|
||||||
|
transferrableMakerFeeTokenAmount,
|
||||||
|
remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
|
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
|
||||||
});
|
});
|
||||||
it('calculates the amount to be 0 when all fee funds are transferred', () => {
|
it('calculates the amount to be 0 when all fee funds are transferred', () => {
|
||||||
signedOrder = buildSignedOrder();
|
signedOrder = buildSignedOrder();
|
||||||
transferrableMakerFeeTokenAmount = zero;
|
transferrableMakerFeeTokenAmount = zero;
|
||||||
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
||||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
calculator = new RemainingFillableCalculator(
|
||||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
signedOrder,
|
||||||
|
isMakerTokenZRX,
|
||||||
|
transferrableMakerTokenAmount,
|
||||||
|
transferrableMakerFeeTokenAmount,
|
||||||
|
remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(zero);
|
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(zero);
|
||||||
});
|
});
|
||||||
it('calculates the correct amount when balance is less than remaining fillable', () => {
|
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);
|
const partiallyFilledAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
||||||
remainingMakerTokenAmount = signedOrder.makerTokenAmount.minus(partiallyFilledAmount);
|
remainingMakerTokenAmount = signedOrder.makerTokenAmount.minus(partiallyFilledAmount);
|
||||||
transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(partiallyFilledAmount);
|
transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(partiallyFilledAmount);
|
||||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
calculator = new RemainingFillableCalculator(
|
||||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
signedOrder,
|
||||||
|
isMakerTokenZRX,
|
||||||
|
transferrableMakerTokenAmount,
|
||||||
|
transferrableMakerFeeTokenAmount,
|
||||||
|
remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(transferrableMakerTokenAmount);
|
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(transferrableMakerTokenAmount);
|
||||||
});
|
});
|
||||||
describe('Order to Fee Ratio is < 1', () => {
|
describe('Order to Fee Ratio is < 1', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
[makerAmount, takerAmount, makerFeeAmount] = [ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals),
|
[makerAmount, takerAmount, makerFeeAmount] = [
|
||||||
ZeroEx.toBaseUnitAmount(new BigNumber(6), decimals),
|
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', () => {
|
it('calculates the correct amount when funds unavailable', () => {
|
||||||
signedOrder = buildSignedOrder();
|
signedOrder = buildSignedOrder();
|
||||||
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
||||||
const transferredAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
const transferredAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
||||||
transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(transferredAmount);
|
transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(transferredAmount);
|
||||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
calculator = new RemainingFillableCalculator(
|
||||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount,
|
signedOrder,
|
||||||
remainingMakerTokenAmount);
|
isMakerTokenZRX,
|
||||||
|
transferrableMakerTokenAmount,
|
||||||
|
transferrableMakerFeeTokenAmount,
|
||||||
|
remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(transferrableMakerTokenAmount);
|
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(transferrableMakerTokenAmount);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('Ratio is not evenly divisble', () => {
|
describe('Ratio is not evenly divisble', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
[makerAmount, takerAmount, makerFeeAmount] = [ZeroEx.toBaseUnitAmount(new BigNumber(3), decimals),
|
[makerAmount, takerAmount, makerFeeAmount] = [
|
||||||
ZeroEx.toBaseUnitAmount(new BigNumber(7), decimals),
|
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', () => {
|
it('calculates the correct amount when funds unavailable', () => {
|
||||||
signedOrder = buildSignedOrder();
|
signedOrder = buildSignedOrder();
|
||||||
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
||||||
const transferredAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
const transferredAmount = ZeroEx.toBaseUnitAmount(new BigNumber(2), decimals);
|
||||||
transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(transferredAmount);
|
transferrableMakerTokenAmount = remainingMakerTokenAmount.minus(transferredAmount);
|
||||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
calculator = new RemainingFillableCalculator(
|
||||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount,
|
signedOrder,
|
||||||
remainingMakerTokenAmount);
|
isMakerTokenZRX,
|
||||||
|
transferrableMakerTokenAmount,
|
||||||
|
transferrableMakerFeeTokenAmount,
|
||||||
|
remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
const calculatedFillableAmount = calculator.computeRemainingMakerFillable();
|
const calculatedFillableAmount = calculator.computeRemainingMakerFillable();
|
||||||
expect(calculatedFillableAmount.lessThanOrEqualTo(transferrableMakerTokenAmount)).to.be.true();
|
expect(calculatedFillableAmount.lessThanOrEqualTo(transferrableMakerTokenAmount)).to.be.true();
|
||||||
expect(calculatedFillableAmount).to.be.bignumber.greaterThan(new BigNumber(0));
|
expect(calculatedFillableAmount).to.be.bignumber.greaterThan(new BigNumber(0));
|
||||||
@ -134,15 +171,25 @@ describe('RemainingFillableCalculator', () => {
|
|||||||
transferrableMakerTokenAmount = makerAmount.plus(makerFeeAmount);
|
transferrableMakerTokenAmount = makerAmount.plus(makerFeeAmount);
|
||||||
transferrableMakerFeeTokenAmount = transferrableMakerTokenAmount;
|
transferrableMakerFeeTokenAmount = transferrableMakerTokenAmount;
|
||||||
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
||||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
calculator = new RemainingFillableCalculator(
|
||||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
signedOrder,
|
||||||
|
isMakerTokenZRX,
|
||||||
|
transferrableMakerTokenAmount,
|
||||||
|
transferrableMakerFeeTokenAmount,
|
||||||
|
remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
|
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
|
||||||
});
|
});
|
||||||
it('calculates the correct amount when partially filled and funds available', () => {
|
it('calculates the correct amount when partially filled and funds available', () => {
|
||||||
signedOrder = buildSignedOrder();
|
signedOrder = buildSignedOrder();
|
||||||
remainingMakerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals);
|
remainingMakerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), decimals);
|
||||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
calculator = new RemainingFillableCalculator(
|
||||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
signedOrder,
|
||||||
|
isMakerTokenZRX,
|
||||||
|
transferrableMakerTokenAmount,
|
||||||
|
transferrableMakerFeeTokenAmount,
|
||||||
|
remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
|
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(remainingMakerTokenAmount);
|
||||||
});
|
});
|
||||||
it('calculates the amount to be 0 when all fee funds are transferred', () => {
|
it('calculates the amount to be 0 when all fee funds are transferred', () => {
|
||||||
@ -150,8 +197,13 @@ describe('RemainingFillableCalculator', () => {
|
|||||||
transferrableMakerTokenAmount = zero;
|
transferrableMakerTokenAmount = zero;
|
||||||
transferrableMakerFeeTokenAmount = zero;
|
transferrableMakerFeeTokenAmount = zero;
|
||||||
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
remainingMakerTokenAmount = signedOrder.makerTokenAmount;
|
||||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
calculator = new RemainingFillableCalculator(
|
||||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
signedOrder,
|
||||||
|
isMakerTokenZRX,
|
||||||
|
transferrableMakerTokenAmount,
|
||||||
|
transferrableMakerFeeTokenAmount,
|
||||||
|
remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(zero);
|
expect(calculator.computeRemainingMakerFillable()).to.be.bignumber.equal(zero);
|
||||||
});
|
});
|
||||||
it('calculates the correct amount when balance is less than remaining fillable', () => {
|
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 orderToFeeRatio = signedOrder.makerTokenAmount.dividedToIntegerBy(signedOrder.makerFee);
|
||||||
const expectedFillableAmount = new BigNumber(450980);
|
const expectedFillableAmount = new BigNumber(450980);
|
||||||
calculator = new RemainingFillableCalculator(signedOrder, isMakerTokenZRX,
|
calculator = new RemainingFillableCalculator(
|
||||||
transferrableMakerTokenAmount, transferrableMakerFeeTokenAmount, remainingMakerTokenAmount);
|
signedOrder,
|
||||||
|
isMakerTokenZRX,
|
||||||
|
transferrableMakerTokenAmount,
|
||||||
|
transferrableMakerFeeTokenAmount,
|
||||||
|
remainingMakerTokenAmount,
|
||||||
|
);
|
||||||
const calculatedFillableAmount = calculator.computeRemainingMakerFillable();
|
const calculatedFillableAmount = calculator.computeRemainingMakerFillable();
|
||||||
const numberOfFillsInRatio = calculatedFillableAmount.dividedToIntegerBy(orderToFeeRatio);
|
const numberOfFillsInRatio = calculatedFillableAmount.dividedToIntegerBy(orderToFeeRatio);
|
||||||
const calculatedFillableAmountPlusFees = calculatedFillableAmount.plus(numberOfFillsInRatio);
|
const calculatedFillableAmountPlusFees = calculatedFillableAmount.plus(numberOfFillsInRatio);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {BlockchainLifecycle} from '@0xproject/dev-utils';
|
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
@ -6,19 +6,13 @@ import 'mocha';
|
|||||||
import * as Sinon from 'sinon';
|
import * as Sinon from 'sinon';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import {
|
import { ApprovalContractEventArgs, DecodedLogEvent, Token, TokenEvents, ZeroEx } from '../src';
|
||||||
ApprovalContractEventArgs,
|
import { DoneCallback } from '../src/types';
|
||||||
DecodedLogEvent,
|
|
||||||
Token,
|
|
||||||
TokenEvents,
|
|
||||||
ZeroEx,
|
|
||||||
} from '../src';
|
|
||||||
import {DoneCallback} from '../src/types';
|
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
import {reportCallbackErrors} from './utils/report_callback_errors';
|
import { reportCallbackErrors } from './utils/report_callback_errors';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
import { web3Factory } from './utils/web3_factory';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
@ -72,12 +66,8 @@ describe('SubscriptionTest', () => {
|
|||||||
done();
|
done();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
stubs = [
|
stubs = [Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync').throws(new Error(errMsg))];
|
||||||
Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync')
|
zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
||||||
.throws(new Error(errMsg)),
|
|
||||||
];
|
|
||||||
zeroEx.token.subscribe(
|
|
||||||
tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
|
||||||
await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount);
|
await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
@ -91,24 +81,16 @@ describe('SubscriptionTest', () => {
|
|||||||
done();
|
done();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
stubs = [
|
stubs = [Sinon.stub((zeroEx as any)._web3Wrapper, 'getLogsAsync').throws(new Error(errMsg))];
|
||||||
Sinon.stub((zeroEx as any)._web3Wrapper, 'getLogsAsync')
|
zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
||||||
.throws(new Error(errMsg)),
|
|
||||||
];
|
|
||||||
zeroEx.token.subscribe(
|
|
||||||
tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
|
||||||
await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount);
|
await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
it('Should allow unsubscribeAll to be called successfully after an error', (done: DoneCallback) => {
|
it('Should allow unsubscribeAll to be called successfully after an error', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const callback = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => _.noop;
|
const callback = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => _.noop;
|
||||||
zeroEx.token.subscribe(
|
zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
||||||
tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
stubs = [Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync').throws(new Error('JSON RPC error'))];
|
||||||
stubs = [
|
|
||||||
Sinon.stub((zeroEx as any)._web3Wrapper, 'getBlockAsync')
|
|
||||||
.throws(new Error('JSON RPC error')),
|
|
||||||
];
|
|
||||||
zeroEx.token.unsubscribeAll();
|
zeroEx.token.unsubscribeAll();
|
||||||
done();
|
done();
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import {BlockchainLifecycle} from '@0xproject/dev-utils';
|
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||||
import {schemas, SchemaValidator} from '@0xproject/json-schemas';
|
import { schemas, SchemaValidator } from '@0xproject/json-schemas';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
|
|
||||||
import {Token, ZeroEx} from '../src';
|
import { Token, ZeroEx } from '../src';
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
import { web3Factory } from './utils/web3_factory';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
@ -19,10 +19,10 @@ const TOKEN_REGISTRY_SIZE_AFTER_MIGRATION = 7;
|
|||||||
describe('TokenRegistryWrapper', () => {
|
describe('TokenRegistryWrapper', () => {
|
||||||
let zeroEx: ZeroEx;
|
let zeroEx: ZeroEx;
|
||||||
let tokens: Token[];
|
let tokens: Token[];
|
||||||
const tokenAddressBySymbol: {[symbol: string]: string} = {};
|
const tokenAddressBySymbol: { [symbol: string]: string } = {};
|
||||||
const tokenAddressByName: {[symbol: string]: string} = {};
|
const tokenAddressByName: { [symbol: string]: string } = {};
|
||||||
const tokenBySymbol: {[symbol: string]: Token} = {};
|
const tokenBySymbol: { [symbol: string]: Token } = {};
|
||||||
const tokenByName: {[symbol: string]: Token} = {};
|
const tokenByName: { [symbol: string]: Token } = {};
|
||||||
const registeredSymbol = 'ZRX';
|
const registeredSymbol = 'ZRX';
|
||||||
const registeredName = '0x Protocol Token';
|
const registeredName = '0x Protocol Token';
|
||||||
const unregisteredSymbol = 'MAL';
|
const unregisteredSymbol = 'MAL';
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
|
|
||||||
import {ZeroEx} from '../src';
|
import { ZeroEx } from '../src';
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
import { web3Factory } from './utils/web3_factory';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import {BlockchainLifecycle} from '@0xproject/dev-utils';
|
import { BlockchainLifecycle } from '@0xproject/dev-utils';
|
||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
@ -16,12 +16,12 @@ import {
|
|||||||
ZeroEx,
|
ZeroEx,
|
||||||
ZeroExError,
|
ZeroExError,
|
||||||
} from '../src';
|
} from '../src';
|
||||||
import {DoneCallback} from '../src/types';
|
import { DoneCallback } from '../src/types';
|
||||||
|
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import { chaiSetup } from './utils/chai_setup';
|
||||||
import {constants} from './utils/constants';
|
import { constants } from './utils/constants';
|
||||||
import {TokenUtils} from './utils/token_utils';
|
import { TokenUtils } from './utils/token_utils';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
import { web3Factory } from './utils/web3_factory';
|
||||||
|
|
||||||
chaiSetup.configure();
|
chaiSetup.configure();
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
@ -74,17 +74,17 @@ describe('TokenWrapper', () => {
|
|||||||
it('should fail to transfer tokens if fromAddress has an insufficient balance', async () => {
|
it('should fail to transfer tokens if fromAddress has an insufficient balance', async () => {
|
||||||
const fromAddress = addressWithoutFunds;
|
const fromAddress = addressWithoutFunds;
|
||||||
const toAddress = coinbase;
|
const toAddress = coinbase;
|
||||||
return expect(zeroEx.token.transferAsync(
|
return expect(
|
||||||
token.address, fromAddress, toAddress, transferAmount,
|
zeroEx.token.transferAsync(token.address, fromAddress, toAddress, transferAmount),
|
||||||
)).to.be.rejectedWith(ZeroExError.InsufficientBalanceForTransfer);
|
).to.be.rejectedWith(ZeroExError.InsufficientBalanceForTransfer);
|
||||||
});
|
});
|
||||||
it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
|
it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
|
||||||
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
|
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
|
||||||
const fromAddress = coinbase;
|
const fromAddress = coinbase;
|
||||||
const toAddress = coinbase;
|
const toAddress = coinbase;
|
||||||
return expect(zeroEx.token.transferAsync(
|
return expect(
|
||||||
nonExistentTokenAddress, fromAddress, toAddress, transferAmount,
|
zeroEx.token.transferAsync(nonExistentTokenAddress, fromAddress, toAddress, transferAmount),
|
||||||
)).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
|
).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#transferFromAsync', () => {
|
describe('#transferFromAsync', () => {
|
||||||
@ -103,24 +103,22 @@ describe('TokenWrapper', () => {
|
|||||||
const fromAddressBalance = await zeroEx.token.getBalanceAsync(token.address, fromAddress);
|
const fromAddressBalance = await zeroEx.token.getBalanceAsync(token.address, fromAddress);
|
||||||
expect(fromAddressBalance).to.be.bignumber.greaterThan(transferAmount);
|
expect(fromAddressBalance).to.be.bignumber.greaterThan(transferAmount);
|
||||||
|
|
||||||
const fromAddressAllowance = await zeroEx.token.getAllowanceAsync(token.address, fromAddress,
|
const fromAddressAllowance = await zeroEx.token.getAllowanceAsync(token.address, fromAddress, toAddress);
|
||||||
toAddress);
|
|
||||||
expect(fromAddressAllowance).to.be.bignumber.equal(0);
|
expect(fromAddressAllowance).to.be.bignumber.equal(0);
|
||||||
|
|
||||||
return expect(zeroEx.token.transferFromAsync(
|
return expect(
|
||||||
token.address, fromAddress, toAddress, senderAddress, transferAmount,
|
zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount),
|
||||||
)).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer);
|
).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer);
|
||||||
});
|
});
|
||||||
it('[regression] should fail to transfer tokens if set allowance for toAddress instead of senderAddress',
|
it('[regression] should fail to transfer tokens if set allowance for toAddress instead of senderAddress', async () => {
|
||||||
async () => {
|
|
||||||
const fromAddress = coinbase;
|
const fromAddress = coinbase;
|
||||||
const transferAmount = new BigNumber(42);
|
const transferAmount = new BigNumber(42);
|
||||||
|
|
||||||
await zeroEx.token.setAllowanceAsync(token.address, fromAddress, toAddress, transferAmount);
|
await zeroEx.token.setAllowanceAsync(token.address, fromAddress, toAddress, transferAmount);
|
||||||
|
|
||||||
return expect(zeroEx.token.transferFromAsync(
|
return expect(
|
||||||
token.address, fromAddress, toAddress, senderAddress, transferAmount,
|
zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount),
|
||||||
)).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer);
|
).to.be.rejectedWith(ZeroExError.InsufficientAllowanceForTransfer);
|
||||||
});
|
});
|
||||||
it('should fail to transfer tokens if fromAddress has insufficient balance', async () => {
|
it('should fail to transfer tokens if fromAddress has insufficient balance', async () => {
|
||||||
const fromAddress = addressWithoutFunds;
|
const fromAddress = addressWithoutFunds;
|
||||||
@ -130,13 +128,16 @@ describe('TokenWrapper', () => {
|
|||||||
expect(fromAddressBalance).to.be.bignumber.equal(0);
|
expect(fromAddressBalance).to.be.bignumber.equal(0);
|
||||||
|
|
||||||
await zeroEx.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount);
|
await zeroEx.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount);
|
||||||
const fromAddressAllowance = await zeroEx.token.getAllowanceAsync(token.address, fromAddress,
|
const fromAddressAllowance = await zeroEx.token.getAllowanceAsync(
|
||||||
senderAddress);
|
token.address,
|
||||||
|
fromAddress,
|
||||||
|
senderAddress,
|
||||||
|
);
|
||||||
expect(fromAddressAllowance).to.be.bignumber.equal(transferAmount);
|
expect(fromAddressAllowance).to.be.bignumber.equal(transferAmount);
|
||||||
|
|
||||||
return expect(zeroEx.token.transferFromAsync(
|
return expect(
|
||||||
token.address, fromAddress, toAddress, senderAddress, transferAmount,
|
zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount),
|
||||||
)).to.be.rejectedWith(ZeroExError.InsufficientBalanceForTransfer);
|
).to.be.rejectedWith(ZeroExError.InsufficientBalanceForTransfer);
|
||||||
});
|
});
|
||||||
it('should successfully transfer tokens', async () => {
|
it('should successfully transfer tokens', async () => {
|
||||||
const fromAddress = coinbase;
|
const fromAddress = coinbase;
|
||||||
@ -147,17 +148,22 @@ describe('TokenWrapper', () => {
|
|||||||
const transferAmount = new BigNumber(42);
|
const transferAmount = new BigNumber(42);
|
||||||
await zeroEx.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount);
|
await zeroEx.token.setAllowanceAsync(token.address, fromAddress, senderAddress, transferAmount);
|
||||||
|
|
||||||
await zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress,
|
await zeroEx.token.transferFromAsync(token.address, fromAddress, toAddress, senderAddress, transferAmount);
|
||||||
transferAmount);
|
|
||||||
const postBalance = await zeroEx.token.getBalanceAsync(token.address, toAddress);
|
const postBalance = await zeroEx.token.getBalanceAsync(token.address, toAddress);
|
||||||
return expect(postBalance).to.be.bignumber.equal(transferAmount);
|
return expect(postBalance).to.be.bignumber.equal(transferAmount);
|
||||||
});
|
});
|
||||||
it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
|
it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
|
||||||
const fromAddress = coinbase;
|
const fromAddress = coinbase;
|
||||||
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
|
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
|
||||||
return expect(zeroEx.token.transferFromAsync(
|
return expect(
|
||||||
nonExistentTokenAddress, fromAddress, toAddress, senderAddress, new BigNumber(42),
|
zeroEx.token.transferFromAsync(
|
||||||
)).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
|
nonExistentTokenAddress,
|
||||||
|
fromAddress,
|
||||||
|
toAddress,
|
||||||
|
senderAddress,
|
||||||
|
new BigNumber(42),
|
||||||
|
),
|
||||||
|
).to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#getBalanceAsync', () => {
|
describe('#getBalanceAsync', () => {
|
||||||
@ -172,8 +178,9 @@ describe('TokenWrapper', () => {
|
|||||||
it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
|
it('should throw a CONTRACT_DOES_NOT_EXIST error for a non-existent token contract', async () => {
|
||||||
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
|
const nonExistentTokenAddress = '0x9dd402f14d67e001d8efbe6583e51bf9706aa065';
|
||||||
const ownerAddress = coinbase;
|
const ownerAddress = coinbase;
|
||||||
return expect(zeroEx.token.getBalanceAsync(nonExistentTokenAddress, ownerAddress))
|
return expect(zeroEx.token.getBalanceAsync(nonExistentTokenAddress, ownerAddress)).to.be.rejectedWith(
|
||||||
.to.be.rejectedWith(ZeroExError.TokenContractDoesNotExist);
|
ZeroExError.TokenContractDoesNotExist,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('should return a balance of 0 for a non-existent owner address', async () => {
|
it('should return a balance of 0 for a non-existent owner address', async () => {
|
||||||
const token = tokens[0];
|
const token = tokens[0];
|
||||||
@ -191,22 +198,25 @@ describe('TokenWrapper', () => {
|
|||||||
zeroExWithoutAccounts = new ZeroEx(web3WithoutAccounts.currentProvider, config);
|
zeroExWithoutAccounts = new ZeroEx(web3WithoutAccounts.currentProvider, config);
|
||||||
});
|
});
|
||||||
it('should return balance even when called with Web3 provider instance without addresses', async () => {
|
it('should return balance even when called with Web3 provider instance without addresses', async () => {
|
||||||
const token = tokens[0];
|
const token = tokens[0];
|
||||||
const ownerAddress = coinbase;
|
const ownerAddress = coinbase;
|
||||||
const balance = await zeroExWithoutAccounts.token.getBalanceAsync(token.address, ownerAddress);
|
const balance = await zeroExWithoutAccounts.token.getBalanceAsync(token.address, ownerAddress);
|
||||||
const expectedBalance = new BigNumber('1000000000000000000000000000');
|
const expectedBalance = new BigNumber('1000000000000000000000000000');
|
||||||
return expect(balance).to.be.bignumber.equal(expectedBalance);
|
return expect(balance).to.be.bignumber.equal(expectedBalance);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#setAllowanceAsync', () => {
|
describe('#setAllowanceAsync', () => {
|
||||||
it('should set the spender\'s allowance', async () => {
|
it("should set the spender's allowance", async () => {
|
||||||
const token = tokens[0];
|
const token = tokens[0];
|
||||||
const ownerAddress = coinbase;
|
const ownerAddress = coinbase;
|
||||||
const spenderAddress = addressWithoutFunds;
|
const spenderAddress = addressWithoutFunds;
|
||||||
|
|
||||||
const allowanceBeforeSet = await zeroEx.token.getAllowanceAsync(token.address, ownerAddress,
|
const allowanceBeforeSet = await zeroEx.token.getAllowanceAsync(
|
||||||
spenderAddress);
|
token.address,
|
||||||
|
ownerAddress,
|
||||||
|
spenderAddress,
|
||||||
|
);
|
||||||
const expectedAllowanceBeforeAllowanceSet = new BigNumber(0);
|
const expectedAllowanceBeforeAllowanceSet = new BigNumber(0);
|
||||||
expect(allowanceBeforeSet).to.be.bignumber.equal(expectedAllowanceBeforeAllowanceSet);
|
expect(allowanceBeforeSet).to.be.bignumber.equal(expectedAllowanceBeforeAllowanceSet);
|
||||||
|
|
||||||
@ -219,7 +229,7 @@ describe('TokenWrapper', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#setUnlimitedAllowanceAsync', () => {
|
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 token = tokens[0];
|
||||||
const ownerAddress = coinbase;
|
const ownerAddress = coinbase;
|
||||||
const spenderAddress = addressWithoutFunds;
|
const spenderAddress = addressWithoutFunds;
|
||||||
@ -241,10 +251,18 @@ describe('TokenWrapper', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
await zeroEx.token.transferFromAsync(
|
await zeroEx.token.transferFromAsync(
|
||||||
zrx.address, coinbase, userWithNormalAllowance, userWithNormalAllowance, transferAmount,
|
zrx.address,
|
||||||
|
coinbase,
|
||||||
|
userWithNormalAllowance,
|
||||||
|
userWithNormalAllowance,
|
||||||
|
transferAmount,
|
||||||
);
|
);
|
||||||
await zeroEx.token.transferFromAsync(
|
await zeroEx.token.transferFromAsync(
|
||||||
zrx.address, coinbase, userWithUnlimitedAllowance, userWithUnlimitedAllowance, transferAmount,
|
zrx.address,
|
||||||
|
coinbase,
|
||||||
|
userWithUnlimitedAllowance,
|
||||||
|
userWithUnlimitedAllowance,
|
||||||
|
transferAmount,
|
||||||
);
|
);
|
||||||
|
|
||||||
const finalBalanceWithNormalAllowance = await web3Wrapper.getBalanceInWeiAsync(userWithNormalAllowance);
|
const finalBalanceWithNormalAllowance = await web3Wrapper.getBalanceInWeiAsync(userWithNormalAllowance);
|
||||||
@ -300,7 +318,9 @@ describe('TokenWrapper', () => {
|
|||||||
await zeroEx.token.setAllowanceAsync(token.address, ownerAddress, spenderAddress, amountInBaseUnits);
|
await zeroEx.token.setAllowanceAsync(token.address, ownerAddress, spenderAddress, amountInBaseUnits);
|
||||||
|
|
||||||
const allowance = await zeroExWithoutAccounts.token.getAllowanceAsync(
|
const allowance = await zeroExWithoutAccounts.token.getAllowanceAsync(
|
||||||
token.address, ownerAddress, spenderAddress,
|
token.address,
|
||||||
|
ownerAddress,
|
||||||
|
spenderAddress,
|
||||||
);
|
);
|
||||||
const expectedAllowance = amountInBaseUnits;
|
const expectedAllowance = amountInBaseUnits;
|
||||||
return expect(allowance).to.be.bignumber.equal(expectedAllowance);
|
return expect(allowance).to.be.bignumber.equal(expectedAllowance);
|
||||||
@ -378,8 +398,7 @@ describe('TokenWrapper', () => {
|
|||||||
expect(args._value).to.be.bignumber.equal(transferAmount);
|
expect(args._value).to.be.bignumber.equal(transferAmount);
|
||||||
done();
|
done();
|
||||||
};
|
};
|
||||||
zeroEx.token.subscribe(
|
zeroEx.token.subscribe(tokenAddress, TokenEvents.Transfer, indexFilterValues, callback);
|
||||||
tokenAddress, TokenEvents.Transfer, indexFilterValues, callback);
|
|
||||||
await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
|
await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
@ -394,8 +413,7 @@ describe('TokenWrapper', () => {
|
|||||||
expect(args._value).to.be.bignumber.equal(allowanceAmount);
|
expect(args._value).to.be.bignumber.equal(allowanceAmount);
|
||||||
done();
|
done();
|
||||||
};
|
};
|
||||||
zeroEx.token.subscribe(
|
zeroEx.token.subscribe(tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
||||||
tokenAddress, TokenEvents.Approval, indexFilterValues, callback);
|
|
||||||
await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount);
|
await zeroEx.token.setAllowanceAsync(tokenAddress, coinbase, addressWithoutFunds, allowanceAmount);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
@ -404,17 +422,13 @@ describe('TokenWrapper', () => {
|
|||||||
const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
const callbackNeverToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
||||||
done(new Error('Expected this subscription to have been cancelled'));
|
done(new Error('Expected this subscription to have been cancelled'));
|
||||||
};
|
};
|
||||||
zeroEx.token.subscribe(
|
zeroEx.token.subscribe(tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled);
|
||||||
tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled,
|
|
||||||
);
|
|
||||||
const callbackToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
const callbackToBeCalled = (err: Error, logEvent: DecodedLogEvent<ApprovalContractEventArgs>) => {
|
||||||
done();
|
done();
|
||||||
};
|
};
|
||||||
const newProvider = web3Factory.getRpcProvider();
|
const newProvider = web3Factory.getRpcProvider();
|
||||||
zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID);
|
zeroEx.setProvider(newProvider, constants.TESTRPC_NETWORK_ID);
|
||||||
zeroEx.token.subscribe(
|
zeroEx.token.subscribe(tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackToBeCalled);
|
||||||
tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackToBeCalled,
|
|
||||||
);
|
|
||||||
await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
|
await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
@ -424,7 +438,11 @@ describe('TokenWrapper', () => {
|
|||||||
done(new Error('Expected this subscription to have been cancelled'));
|
done(new Error('Expected this subscription to have been cancelled'));
|
||||||
};
|
};
|
||||||
const subscriptionToken = zeroEx.token.subscribe(
|
const subscriptionToken = zeroEx.token.subscribe(
|
||||||
tokenAddress, TokenEvents.Transfer, indexFilterValues, callbackNeverToBeCalled);
|
tokenAddress,
|
||||||
|
TokenEvents.Transfer,
|
||||||
|
indexFilterValues,
|
||||||
|
callbackNeverToBeCalled,
|
||||||
|
);
|
||||||
zeroEx.token.unsubscribe(subscriptionToken);
|
zeroEx.token.unsubscribe(subscriptionToken);
|
||||||
await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
|
await zeroEx.token.transferAsync(tokenAddress, coinbase, addressWithoutFunds, transferAmount);
|
||||||
done();
|
done();
|
||||||
@ -450,7 +468,10 @@ describe('TokenWrapper', () => {
|
|||||||
const eventName = TokenEvents.Approval;
|
const eventName = TokenEvents.Approval;
|
||||||
const indexFilterValues = {};
|
const indexFilterValues = {};
|
||||||
const logs = await zeroEx.token.getLogsAsync<ApprovalContractEventArgs>(
|
const logs = await zeroEx.token.getLogsAsync<ApprovalContractEventArgs>(
|
||||||
tokenAddress, eventName, blockRange, indexFilterValues,
|
tokenAddress,
|
||||||
|
eventName,
|
||||||
|
blockRange,
|
||||||
|
indexFilterValues,
|
||||||
);
|
);
|
||||||
expect(logs).to.have.length(1);
|
expect(logs).to.have.length(1);
|
||||||
const args = logs[0].args;
|
const args = logs[0].args;
|
||||||
@ -465,7 +486,10 @@ describe('TokenWrapper', () => {
|
|||||||
const differentEventName = TokenEvents.Transfer;
|
const differentEventName = TokenEvents.Transfer;
|
||||||
const indexFilterValues = {};
|
const indexFilterValues = {};
|
||||||
const logs = await zeroEx.token.getLogsAsync(
|
const logs = await zeroEx.token.getLogsAsync(
|
||||||
tokenAddress, differentEventName, blockRange, indexFilterValues,
|
tokenAddress,
|
||||||
|
differentEventName,
|
||||||
|
blockRange,
|
||||||
|
indexFilterValues,
|
||||||
);
|
);
|
||||||
expect(logs).to.have.length(0);
|
expect(logs).to.have.length(0);
|
||||||
});
|
});
|
||||||
@ -479,7 +503,10 @@ describe('TokenWrapper', () => {
|
|||||||
_owner: coinbase,
|
_owner: coinbase,
|
||||||
};
|
};
|
||||||
const logs = await zeroEx.token.getLogsAsync<ApprovalContractEventArgs>(
|
const logs = await zeroEx.token.getLogsAsync<ApprovalContractEventArgs>(
|
||||||
tokenAddress, eventName, blockRange, indexFilterValues,
|
tokenAddress,
|
||||||
|
eventName,
|
||||||
|
blockRange,
|
||||||
|
indexFilterValues,
|
||||||
);
|
);
|
||||||
expect(logs).to.have.length(1);
|
expect(logs).to.have.length(1);
|
||||||
const args = logs[0].args;
|
const args = logs[0].args;
|
||||||
@ -487,3 +514,4 @@ describe('TokenWrapper', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// tslint:disable:max-file-line-count
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
|
|
||||||
import {SignedOrder, Token, ZeroEx} from '../../src';
|
import { SignedOrder, Token, ZeroEx } from '../../src';
|
||||||
import {artifacts} from '../../src/artifacts';
|
import { artifacts } from '../../src/artifacts';
|
||||||
import {DummyTokenContract} from '../../src/contract_wrappers/generated/dummy_token';
|
import { DummyTokenContract } from '../../src/contract_wrappers/generated/dummy_token';
|
||||||
import {orderFactory} from '../utils/order_factory';
|
import { orderFactory } from '../utils/order_factory';
|
||||||
|
|
||||||
import {constants} from './constants';
|
import { constants } from './constants';
|
||||||
|
|
||||||
const INITIAL_COINBASE_TOKEN_SUPPLY_IN_UNITS = new BigNumber(100);
|
const INITIAL_COINBASE_TOKEN_SUPPLY_IN_UNITS = new BigNumber(100);
|
||||||
|
|
||||||
@ -17,8 +17,13 @@ export class FillScenarios {
|
|||||||
private _coinbase: string;
|
private _coinbase: string;
|
||||||
private _zrxTokenAddress: string;
|
private _zrxTokenAddress: string;
|
||||||
private _exchangeContractAddress: string;
|
private _exchangeContractAddress: string;
|
||||||
constructor(zeroEx: ZeroEx, userAddresses: string[],
|
constructor(
|
||||||
tokens: Token[], zrxTokenAddress: string, exchangeContractAddress: string) {
|
zeroEx: ZeroEx,
|
||||||
|
userAddresses: string[],
|
||||||
|
tokens: Token[],
|
||||||
|
zrxTokenAddress: string,
|
||||||
|
exchangeContractAddress: string,
|
||||||
|
) {
|
||||||
this._zeroEx = zeroEx;
|
this._zeroEx = zeroEx;
|
||||||
this._userAddresses = userAddresses;
|
this._userAddresses = userAddresses;
|
||||||
this._tokens = tokens;
|
this._tokens = tokens;
|
||||||
@ -31,7 +36,8 @@ export class FillScenarios {
|
|||||||
for (const token of this._tokens) {
|
for (const token of this._tokens) {
|
||||||
if (token.symbol !== 'ZRX' && token.symbol !== 'WETH') {
|
if (token.symbol !== 'ZRX' && token.symbol !== 'WETH') {
|
||||||
const contractInstance = web3Wrapper.getContractInstance(
|
const contractInstance = web3Wrapper.getContractInstance(
|
||||||
artifacts.DummyTokenArtifact.abi, token.address,
|
artifacts.DummyTokenArtifact.abi,
|
||||||
|
token.address,
|
||||||
);
|
);
|
||||||
const defaults = {};
|
const defaults = {};
|
||||||
const dummyToken = new DummyTokenContract(contractInstance, defaults);
|
const dummyToken = new DummyTokenContract(contractInstance, defaults);
|
||||||
@ -43,61 +49,110 @@ export class FillScenarios {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public async createFillableSignedOrderAsync(makerTokenAddress: string, takerTokenAddress: string,
|
public async createFillableSignedOrderAsync(
|
||||||
makerAddress: string, takerAddress: string,
|
makerTokenAddress: string,
|
||||||
fillableAmount: BigNumber,
|
takerTokenAddress: string,
|
||||||
expirationUnixTimestampSec?: BigNumber):
|
makerAddress: string,
|
||||||
Promise<SignedOrder> {
|
takerAddress: string,
|
||||||
|
fillableAmount: BigNumber,
|
||||||
|
expirationUnixTimestampSec?: BigNumber,
|
||||||
|
): Promise<SignedOrder> {
|
||||||
return this.createAsymmetricFillableSignedOrderAsync(
|
return this.createAsymmetricFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
makerTokenAddress,
|
||||||
fillableAmount, fillableAmount, expirationUnixTimestampSec,
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
|
fillableAmount,
|
||||||
|
expirationUnixTimestampSec,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public async createFillableSignedOrderWithFeesAsync(
|
public async createFillableSignedOrderWithFeesAsync(
|
||||||
makerTokenAddress: string, takerTokenAddress: string,
|
makerTokenAddress: string,
|
||||||
makerFee: BigNumber, takerFee: BigNumber,
|
takerTokenAddress: string,
|
||||||
makerAddress: string, takerAddress: string,
|
makerFee: BigNumber,
|
||||||
|
takerFee: BigNumber,
|
||||||
|
makerAddress: string,
|
||||||
|
takerAddress: string,
|
||||||
fillableAmount: BigNumber,
|
fillableAmount: BigNumber,
|
||||||
feeRecepient: string, expirationUnixTimestampSec?: BigNumber,
|
feeRecepient: string,
|
||||||
|
expirationUnixTimestampSec?: BigNumber,
|
||||||
): Promise<SignedOrder> {
|
): Promise<SignedOrder> {
|
||||||
return this._createAsymmetricFillableSignedOrderWithFeesAsync(
|
return this._createAsymmetricFillableSignedOrderWithFeesAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress,
|
makerTokenAddress,
|
||||||
fillableAmount, fillableAmount, feeRecepient, expirationUnixTimestampSec,
|
takerTokenAddress,
|
||||||
|
makerFee,
|
||||||
|
takerFee,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
|
fillableAmount,
|
||||||
|
feeRecepient,
|
||||||
|
expirationUnixTimestampSec,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public async createAsymmetricFillableSignedOrderAsync(
|
public async createAsymmetricFillableSignedOrderAsync(
|
||||||
makerTokenAddress: string, takerTokenAddress: string, makerAddress: string, takerAddress: string,
|
makerTokenAddress: string,
|
||||||
makerFillableAmount: BigNumber, takerFillableAmount: BigNumber,
|
takerTokenAddress: string,
|
||||||
expirationUnixTimestampSec?: BigNumber): Promise<SignedOrder> {
|
makerAddress: string,
|
||||||
|
takerAddress: string,
|
||||||
|
makerFillableAmount: BigNumber,
|
||||||
|
takerFillableAmount: BigNumber,
|
||||||
|
expirationUnixTimestampSec?: BigNumber,
|
||||||
|
): Promise<SignedOrder> {
|
||||||
const makerFee = new BigNumber(0);
|
const makerFee = new BigNumber(0);
|
||||||
const takerFee = new BigNumber(0);
|
const takerFee = new BigNumber(0);
|
||||||
const feeRecepient = constants.NULL_ADDRESS;
|
const feeRecepient = constants.NULL_ADDRESS;
|
||||||
return this._createAsymmetricFillableSignedOrderWithFeesAsync(
|
return this._createAsymmetricFillableSignedOrderWithFeesAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerFee, takerFee, makerAddress, takerAddress,
|
makerTokenAddress,
|
||||||
makerFillableAmount, takerFillableAmount, feeRecepient, expirationUnixTimestampSec,
|
takerTokenAddress,
|
||||||
|
makerFee,
|
||||||
|
takerFee,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
makerFillableAmount,
|
||||||
|
takerFillableAmount,
|
||||||
|
feeRecepient,
|
||||||
|
expirationUnixTimestampSec,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public async createPartiallyFilledSignedOrderAsync(makerTokenAddress: string, takerTokenAddress: string,
|
public async createPartiallyFilledSignedOrderAsync(
|
||||||
takerAddress: string, fillableAmount: BigNumber,
|
makerTokenAddress: string,
|
||||||
partialFillAmount: BigNumber) {
|
takerTokenAddress: string,
|
||||||
|
takerAddress: string,
|
||||||
|
fillableAmount: BigNumber,
|
||||||
|
partialFillAmount: BigNumber,
|
||||||
|
) {
|
||||||
const [makerAddress] = this._userAddresses;
|
const [makerAddress] = this._userAddresses;
|
||||||
const signedOrder = await this.createAsymmetricFillableSignedOrderAsync(
|
const signedOrder = await this.createAsymmetricFillableSignedOrderAsync(
|
||||||
makerTokenAddress, takerTokenAddress, makerAddress, takerAddress,
|
makerTokenAddress,
|
||||||
fillableAmount, fillableAmount,
|
takerTokenAddress,
|
||||||
|
makerAddress,
|
||||||
|
takerAddress,
|
||||||
|
fillableAmount,
|
||||||
|
fillableAmount,
|
||||||
);
|
);
|
||||||
const shouldThrowOnInsufficientBalanceOrAllowance = false;
|
const shouldThrowOnInsufficientBalanceOrAllowance = false;
|
||||||
await this._zeroEx.exchange.fillOrderAsync(
|
await this._zeroEx.exchange.fillOrderAsync(
|
||||||
signedOrder, partialFillAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress,
|
signedOrder,
|
||||||
|
partialFillAmount,
|
||||||
|
shouldThrowOnInsufficientBalanceOrAllowance,
|
||||||
|
takerAddress,
|
||||||
);
|
);
|
||||||
return signedOrder;
|
return signedOrder;
|
||||||
}
|
}
|
||||||
private async _createAsymmetricFillableSignedOrderWithFeesAsync(
|
private async _createAsymmetricFillableSignedOrderWithFeesAsync(
|
||||||
makerTokenAddress: string, takerTokenAddress: string,
|
makerTokenAddress: string,
|
||||||
makerFee: BigNumber, takerFee: BigNumber,
|
takerTokenAddress: string,
|
||||||
makerAddress: string, takerAddress: string,
|
makerFee: BigNumber,
|
||||||
makerFillableAmount: BigNumber, takerFillableAmount: BigNumber,
|
takerFee: BigNumber,
|
||||||
feeRecepient: string, expirationUnixTimestampSec?: BigNumber): Promise<SignedOrder> {
|
makerAddress: string,
|
||||||
|
takerAddress: string,
|
||||||
|
makerFillableAmount: BigNumber,
|
||||||
|
takerFillableAmount: BigNumber,
|
||||||
|
feeRecepient: string,
|
||||||
|
expirationUnixTimestampSec?: BigNumber,
|
||||||
|
): Promise<SignedOrder> {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
this._increaseBalanceAndAllowanceAsync(makerTokenAddress, makerAddress, makerFillableAmount),
|
this._increaseBalanceAndAllowanceAsync(makerTokenAddress, makerAddress, makerFillableAmount),
|
||||||
this._increaseBalanceAndAllowanceAsync(takerTokenAddress, takerAddress, takerFillableAmount),
|
this._increaseBalanceAndAllowanceAsync(takerTokenAddress, takerAddress, takerFillableAmount),
|
||||||
@ -107,14 +162,27 @@ export class FillScenarios {
|
|||||||
this._increaseBalanceAndAllowanceAsync(this._zrxTokenAddress, takerAddress, takerFee),
|
this._increaseBalanceAndAllowanceAsync(this._zrxTokenAddress, takerAddress, takerFee),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const signedOrder = await orderFactory.createSignedOrderAsync(this._zeroEx,
|
const signedOrder = await orderFactory.createSignedOrderAsync(
|
||||||
makerAddress, takerAddress, makerFee, takerFee,
|
this._zeroEx,
|
||||||
makerFillableAmount, makerTokenAddress, takerFillableAmount, takerTokenAddress,
|
makerAddress,
|
||||||
this._exchangeContractAddress, feeRecepient, expirationUnixTimestampSec);
|
takerAddress,
|
||||||
|
makerFee,
|
||||||
|
takerFee,
|
||||||
|
makerFillableAmount,
|
||||||
|
makerTokenAddress,
|
||||||
|
takerFillableAmount,
|
||||||
|
takerTokenAddress,
|
||||||
|
this._exchangeContractAddress,
|
||||||
|
feeRecepient,
|
||||||
|
expirationUnixTimestampSec,
|
||||||
|
);
|
||||||
return signedOrder;
|
return signedOrder;
|
||||||
}
|
}
|
||||||
private async _increaseBalanceAndAllowanceAsync(
|
private async _increaseBalanceAndAllowanceAsync(
|
||||||
tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
|
tokenAddress: string,
|
||||||
|
address: string,
|
||||||
|
amount: BigNumber,
|
||||||
|
): Promise<void> {
|
||||||
if (amount.isZero() || address === ZeroEx.NULL_ADDRESS) {
|
if (amount.isZero() || address === ZeroEx.NULL_ADDRESS) {
|
||||||
return; // noop
|
return; // noop
|
||||||
}
|
}
|
||||||
@ -123,16 +191,12 @@ export class FillScenarios {
|
|||||||
this._increaseAllowanceAsync(tokenAddress, address, amount),
|
this._increaseAllowanceAsync(tokenAddress, address, amount),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
private async _increaseBalanceAsync(
|
private async _increaseBalanceAsync(tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
|
||||||
tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
|
|
||||||
await this._zeroEx.token.transferAsync(tokenAddress, this._coinbase, address, amount);
|
await this._zeroEx.token.transferAsync(tokenAddress, this._coinbase, address, amount);
|
||||||
}
|
}
|
||||||
private async _increaseAllowanceAsync(
|
private async _increaseAllowanceAsync(tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
|
||||||
tokenAddress: string, address: string, amount: BigNumber): Promise<void> {
|
|
||||||
const oldMakerAllowance = await this._zeroEx.token.getProxyAllowanceAsync(tokenAddress, address);
|
const oldMakerAllowance = await this._zeroEx.token.getProxyAllowanceAsync(tokenAddress, address);
|
||||||
const newMakerAllowance = oldMakerAllowance.plus(amount);
|
const newMakerAllowance = oldMakerAllowance.plus(amount);
|
||||||
await this._zeroEx.token.setProxyAllowanceAsync(
|
await this._zeroEx.token.setProxyAllowanceAsync(tokenAddress, address, newMakerAllowance);
|
||||||
tokenAddress, address, newMakerAllowance,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {SignedOrder, ZeroEx} from '../../src';
|
import { SignedOrder, ZeroEx } from '../../src';
|
||||||
|
|
||||||
export const orderFactory = {
|
export const orderFactory = {
|
||||||
async createSignedOrderAsync(
|
async createSignedOrderAsync(
|
||||||
@ -16,11 +16,12 @@ export const orderFactory = {
|
|||||||
takerTokenAddress: string,
|
takerTokenAddress: string,
|
||||||
exchangeContractAddress: string,
|
exchangeContractAddress: string,
|
||||||
feeRecipient: string,
|
feeRecipient: string,
|
||||||
expirationUnixTimestampSecIfExists?: BigNumber): Promise<SignedOrder> {
|
expirationUnixTimestampSecIfExists?: BigNumber,
|
||||||
|
): Promise<SignedOrder> {
|
||||||
const defaultExpirationUnixTimestampSec = new BigNumber(2524604400); // Close to infinite
|
const defaultExpirationUnixTimestampSec = new BigNumber(2524604400); // Close to infinite
|
||||||
const expirationUnixTimestampSec = _.isUndefined(expirationUnixTimestampSecIfExists) ?
|
const expirationUnixTimestampSec = _.isUndefined(expirationUnixTimestampSecIfExists)
|
||||||
defaultExpirationUnixTimestampSec :
|
? defaultExpirationUnixTimestampSec
|
||||||
expirationUnixTimestampSecIfExists;
|
: expirationUnixTimestampSecIfExists;
|
||||||
const order = {
|
const order = {
|
||||||
maker,
|
maker,
|
||||||
taker,
|
taker,
|
||||||
@ -37,7 +38,7 @@ export const orderFactory = {
|
|||||||
};
|
};
|
||||||
const orderHash = ZeroEx.getOrderHashHex(order);
|
const orderHash = ZeroEx.getOrderHashHex(order);
|
||||||
const ecSignature = await zeroEx.signOrderHashAsync(orderHash, maker);
|
const ecSignature = await zeroEx.signOrderHashAsync(orderHash, maker);
|
||||||
const signedOrder: SignedOrder = _.assign(order, {ecSignature});
|
const signedOrder: SignedOrder = _.assign(order, { ecSignature });
|
||||||
return signedOrder;
|
return signedOrder;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {DoneCallback} from '../../src/types';
|
import { DoneCallback } from '../../src/types';
|
||||||
|
|
||||||
export const reportCallbackErrors = (done: DoneCallback) => {
|
export const reportCallbackErrors = (done: DoneCallback) => {
|
||||||
return (f: (...args: any[]) => void) => {
|
return (f: (...args: any[]) => void) => {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {JSONRPCPayload} from '../../../src/types';
|
import { JSONRPCPayload } from '../../../src/types';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This class implements the web3-provider-engine subprovider interface and returns
|
* This class implements the web3-provider-engine subprovider interface and returns
|
||||||
@ -8,7 +8,7 @@ import {JSONRPCPayload} from '../../../src/types';
|
|||||||
export class EmptyWalletSubprovider {
|
export class EmptyWalletSubprovider {
|
||||||
// This method needs to be here to satisfy the interface but linter wants it to be static.
|
// 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
|
// tslint:disable-next-line:prefer-function-over-method
|
||||||
public handleRequest(payload: JSONRPCPayload, next: () => void, end: (err: Error|null, result: any) => void) {
|
public handleRequest(payload: JSONRPCPayload, next: () => void, end: (err: Error | null, result: any) => void) {
|
||||||
switch (payload.method) {
|
switch (payload.method) {
|
||||||
case 'eth_accounts':
|
case 'eth_accounts':
|
||||||
end(null, []);
|
end(null, []);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {JSONRPCPayload} from '../../../src/types';
|
import { JSONRPCPayload } from '../../../src/types';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This class implements the web3-provider-engine subprovider interface and returns
|
* This class implements the web3-provider-engine subprovider interface and returns
|
||||||
@ -15,7 +15,7 @@ export class FakeGasEstimateSubprovider {
|
|||||||
}
|
}
|
||||||
// This method needs to be here to satisfy the interface but linter wants it to be static.
|
// 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
|
// tslint:disable-next-line:prefer-function-over-method
|
||||||
public handleRequest(payload: JSONRPCPayload, next: () => void, end: (err: Error|null, result: any) => void) {
|
public handleRequest(payload: JSONRPCPayload, next: () => void, end: (err: Error | null, result: any) => void) {
|
||||||
switch (payload.method) {
|
switch (payload.method) {
|
||||||
case 'eth_estimateGas':
|
case 'eth_estimateGas':
|
||||||
end(null, this._constantGasAmount);
|
end(null, this._constantGasAmount);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {InternalZeroExError, Token} from '../../src/types';
|
import { InternalZeroExError, Token } from '../../src/types';
|
||||||
|
|
||||||
const PROTOCOL_TOKEN_SYMBOL = 'ZRX';
|
const PROTOCOL_TOKEN_SYMBOL = 'ZRX';
|
||||||
const WETH_TOKEN_SYMBOL = 'WETH';
|
const WETH_TOKEN_SYMBOL = 'WETH';
|
||||||
@ -11,14 +11,14 @@ export class TokenUtils {
|
|||||||
this._tokens = tokens;
|
this._tokens = tokens;
|
||||||
}
|
}
|
||||||
public getProtocolTokenOrThrow(): Token {
|
public getProtocolTokenOrThrow(): Token {
|
||||||
const zrxToken = _.find(this._tokens, {symbol: PROTOCOL_TOKEN_SYMBOL});
|
const zrxToken = _.find(this._tokens, { symbol: PROTOCOL_TOKEN_SYMBOL });
|
||||||
if (_.isUndefined(zrxToken)) {
|
if (_.isUndefined(zrxToken)) {
|
||||||
throw new Error(InternalZeroExError.ZrxNotInTokenRegistry);
|
throw new Error(InternalZeroExError.ZrxNotInTokenRegistry);
|
||||||
}
|
}
|
||||||
return zrxToken;
|
return zrxToken;
|
||||||
}
|
}
|
||||||
public getWethTokenOrThrow(): Token {
|
public getWethTokenOrThrow(): Token {
|
||||||
const wethToken = _.find(this._tokens, {symbol: WETH_TOKEN_SYMBOL});
|
const wethToken = _.find(this._tokens, { symbol: WETH_TOKEN_SYMBOL });
|
||||||
if (_.isUndefined(wethToken)) {
|
if (_.isUndefined(wethToken)) {
|
||||||
throw new Error(InternalZeroExError.WethNotInTokenRegistry);
|
throw new Error(InternalZeroExError.WethNotInTokenRegistry);
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,10 @@
|
|||||||
import ProviderEngine = require('web3-provider-engine');
|
import ProviderEngine = require('web3-provider-engine');
|
||||||
import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
|
import RpcSubprovider = require('web3-provider-engine/subproviders/rpc');
|
||||||
|
|
||||||
import {EmptyWalletSubprovider} from './subproviders/empty_wallet_subprovider';
|
import { EmptyWalletSubprovider } from './subproviders/empty_wallet_subprovider';
|
||||||
import {FakeGasEstimateSubprovider} from './subproviders/fake_gas_estimate_subprovider';
|
import { FakeGasEstimateSubprovider } from './subproviders/fake_gas_estimate_subprovider';
|
||||||
|
|
||||||
import {constants} from './constants';
|
import { constants } from './constants';
|
||||||
|
|
||||||
// HACK: web3 leaks XMLHttpRequest into the global scope and causes requests to hang
|
// HACK: web3 leaks XMLHttpRequest into the global scope and causes requests to hang
|
||||||
// because they are using the wrong XHR package.
|
// because they are using the wrong XHR package.
|
||||||
@ -31,9 +31,11 @@ export const web3Factory = {
|
|||||||
provider.addProvider(new EmptyWalletSubprovider());
|
provider.addProvider(new EmptyWalletSubprovider());
|
||||||
}
|
}
|
||||||
provider.addProvider(new FakeGasEstimateSubprovider(constants.GAS_ESTIMATE));
|
provider.addProvider(new FakeGasEstimateSubprovider(constants.GAS_ESTIMATE));
|
||||||
provider.addProvider(new RpcSubprovider({
|
provider.addProvider(
|
||||||
rpcUrl: constants.RPC_URL,
|
new RpcSubprovider({
|
||||||
}));
|
rpcUrl: constants.RPC_URL,
|
||||||
|
}),
|
||||||
|
);
|
||||||
provider.start();
|
provider.start();
|
||||||
return provider;
|
return provider;
|
||||||
},
|
},
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
vx.x.x
|
v0.x.x - _TBD, 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,9 +5,9 @@ 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.
|
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.
|
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.
|
||||||
|
|
||||||
## Instalation
|
## Installation
|
||||||
`yarn add -g @0xproject/abi-gen`
|
`yarn add -g @0xproject/abi-gen`
|
||||||
## Usage
|
## Usage
|
||||||
```
|
```
|
||||||
@ -29,8 +29,8 @@ We could've just used `--abiGlob 'src/artifacts/*.json` but we wanted to exclude
|
|||||||
|
|
||||||
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.
|
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?
|
## 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.
|
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](handlebarsjs.com) template engine under the hood.
|
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.
|
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?
|
## 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.
|
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.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0xproject/abi-gen",
|
"name": "@0xproject/abi-gen",
|
||||||
"version": "0.0.3",
|
"version": "0.0.4",
|
||||||
"description": "Generate contract wrappers from ABI and handlebars templates",
|
"description": "Generate contract wrappers from ABI and handlebars templates",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "lib/index.d.ts",
|
"types": "lib/index.d.ts",
|
||||||
@ -33,7 +33,7 @@
|
|||||||
"yargs": "^10.0.3"
|
"yargs": "^10.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0xproject/tslint-config": "^0.3.0",
|
"@0xproject/tslint-config": "^0.4.0",
|
||||||
"@types/glob": "^5.0.33",
|
"@types/glob": "^5.0.33",
|
||||||
"@types/handlebars": "^4.0.36",
|
"@types/handlebars": "^4.0.36",
|
||||||
"@types/mkdirp": "^0.5.1",
|
"@types/mkdirp": "^0.5.1",
|
||||||
@ -43,6 +43,6 @@
|
|||||||
"shx": "^0.2.2",
|
"shx": "^0.2.2",
|
||||||
"tslint": "5.8.0",
|
"tslint": "5.8.0",
|
||||||
"typescript": "~2.6.1",
|
"typescript": "~2.6.1",
|
||||||
"web3-typescript-typings": "^0.7.2"
|
"web3-typescript-typings": "^0.9.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import {sync as globSync} from 'glob';
|
import { sync as globSync } from 'glob';
|
||||||
import * as Handlebars from 'handlebars';
|
import * as Handlebars from 'handlebars';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as mkdirp from 'mkdirp';
|
import * as mkdirp from 'mkdirp';
|
||||||
@ -11,10 +11,12 @@ import * as yargs from 'yargs';
|
|||||||
import toSnakeCase = require('to-snake-case');
|
import toSnakeCase = require('to-snake-case');
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import {ContextData, ParamKind} from './types';
|
import { ContextData, ParamKind } from './types';
|
||||||
import {utils} from './utils';
|
import { utils } from './utils';
|
||||||
|
|
||||||
|
const ABI_TYPE_CONSTRUCTOR = 'constructor';
|
||||||
const ABI_TYPE_METHOD = 'function';
|
const ABI_TYPE_METHOD = 'function';
|
||||||
|
const ABI_TYPE_EVENT = 'event';
|
||||||
const MAIN_TEMPLATE_NAME = 'contract.mustache';
|
const MAIN_TEMPLATE_NAME = 'contract.mustache';
|
||||||
|
|
||||||
const args = yargs
|
const args = yargs
|
||||||
@ -32,8 +34,7 @@ const args = yargs
|
|||||||
describe: 'Folder where to put the output files',
|
describe: 'Folder where to put the output files',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
demand: true,
|
demand: true,
|
||||||
})
|
}).argv;
|
||||||
.argv;
|
|
||||||
|
|
||||||
function writeOutputFile(name: string, renderedTsCode: string): void {
|
function writeOutputFile(name: string, renderedTsCode: string): void {
|
||||||
const fileName = toSnakeCase(name);
|
const fileName = toSnakeCase(name);
|
||||||
@ -66,14 +67,20 @@ for (const abiFileName of abiFileNames) {
|
|||||||
const namedContent = utils.getNamedContent(abiFileName);
|
const namedContent = utils.getNamedContent(abiFileName);
|
||||||
utils.log(`Processing: ${chalk.bold(namedContent.name)}...`);
|
utils.log(`Processing: ${chalk.bold(namedContent.name)}...`);
|
||||||
const parsedContent = JSON.parse(namedContent.content);
|
const parsedContent = JSON.parse(namedContent.content);
|
||||||
const ABI = _.isArray(parsedContent) ?
|
const ABI = _.isArray(parsedContent)
|
||||||
parsedContent : // ABI file
|
? parsedContent // ABI file
|
||||||
parsedContent.abi; // Truffle contracts file
|
: parsedContent.abi; // Truffle contracts file
|
||||||
if (_.isUndefined(ABI)) {
|
if (_.isUndefined(ABI)) {
|
||||||
utils.log(`${chalk.red(`ABI not found in ${abiFileName}.`)}`);
|
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`);
|
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);
|
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 methodAbis = ABI.filter((abi: Web3.AbiDefinition) => abi.type === ABI_TYPE_METHOD) as Web3.MethodAbi[];
|
||||||
const methodsData = _.map(methodAbis, methodAbi => {
|
const methodsData = _.map(methodAbis, methodAbi => {
|
||||||
_.map(methodAbi.inputs, input => {
|
_.map(methodAbi.inputs, input => {
|
||||||
@ -89,9 +96,14 @@ for (const abiFileName of abiFileNames) {
|
|||||||
};
|
};
|
||||||
return methodData;
|
return methodData;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const eventAbis = ABI.filter((abi: Web3.AbiDefinition) => abi.type === ABI_TYPE_EVENT) as Web3.EventAbi[];
|
||||||
|
|
||||||
const contextData = {
|
const contextData = {
|
||||||
contractName: namedContent.name,
|
contractName: namedContent.name,
|
||||||
|
ctor,
|
||||||
methods: methodsData,
|
methods: methodsData,
|
||||||
|
events: eventAbis,
|
||||||
};
|
};
|
||||||
const renderedTsCode = template(contextData);
|
const renderedTsCode = template(contextData);
|
||||||
writeOutputFile(namedContent.name, renderedTsCode);
|
writeOutputFile(namedContent.name, renderedTsCode);
|
||||||
|
@ -12,4 +12,5 @@ export interface Method extends Web3.MethodAbi {
|
|||||||
export interface ContextData {
|
export interface ContextData {
|
||||||
contractName: string;
|
contractName: string;
|
||||||
methods: Method[];
|
methods: Method[];
|
||||||
|
events: Web3.EventAbi[];
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import {ParamKind} from './types';
|
import { ParamKind } from './types';
|
||||||
|
|
||||||
export const utils = {
|
export const utils = {
|
||||||
solTypeToTsType(paramKind: ParamKind, solType: string): string {
|
solTypeToTsType(paramKind: ParamKind, solType: string): string {
|
||||||
@ -10,23 +11,26 @@ export const utils = {
|
|||||||
if (solType.match(trailingArrayRegex)) {
|
if (solType.match(trailingArrayRegex)) {
|
||||||
const arrayItemSolType = solType.replace(trailingArrayRegex, '');
|
const arrayItemSolType = solType.replace(trailingArrayRegex, '');
|
||||||
const arrayItemTsType = utils.solTypeToTsType(paramKind, arrayItemSolType);
|
const arrayItemTsType = utils.solTypeToTsType(paramKind, arrayItemSolType);
|
||||||
const arrayTsType = `${arrayItemTsType}[]`;
|
const arrayTsType = `(${arrayItemTsType})[]`;
|
||||||
return arrayTsType;
|
return arrayTsType;
|
||||||
} else {
|
} else {
|
||||||
const solTypeRegexToTsType = [
|
const solTypeRegexToTsType = [
|
||||||
{regex: '^string$', tsType: 'string'},
|
{ regex: '^string$', tsType: 'string' },
|
||||||
{regex: '^address$', tsType: 'string'},
|
{ regex: '^address$', tsType: 'string' },
|
||||||
{regex: '^bool$', tsType: 'boolean'},
|
{ regex: '^bool$', tsType: 'boolean' },
|
||||||
{regex: '^u?int\\d*$', tsType: 'BigNumber'},
|
{ regex: '^u?int\\d*$', tsType: 'BigNumber' },
|
||||||
{regex: '^bytes\\d*$', tsType: 'string'},
|
{ regex: '^bytes\\d*$', tsType: 'string' },
|
||||||
];
|
];
|
||||||
if (paramKind === ParamKind.Input) {
|
if (paramKind === ParamKind.Input) {
|
||||||
// web3 allows to pass those an non-bignumbers and that's nice
|
// web3 allows to pass those an non-bignumbers and that's nice
|
||||||
// but it always returns stuff as BigNumbers
|
// 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) {
|
for (const regexAndTxType of solTypeRegexToTsType) {
|
||||||
const {regex, tsType} = regexAndTxType;
|
const { regex, tsType } = regexAndTxType;
|
||||||
if (solType.match(regex)) {
|
if (solType.match(regex)) {
|
||||||
return tsType;
|
return tsType;
|
||||||
}
|
}
|
||||||
@ -41,7 +45,7 @@ export const utils = {
|
|||||||
const name = path.parse(filename).name;
|
const name = path.parse(filename).name;
|
||||||
return name;
|
return name;
|
||||||
},
|
},
|
||||||
getNamedContent(filename: string): {name: string; content: string} {
|
getNamedContent(filename: string): { name: string; content: string } {
|
||||||
const name = utils.getPartialNameFromFileName(filename);
|
const name = utils.getPartialNameFromFileName(filename);
|
||||||
try {
|
try {
|
||||||
const content = fs.readFileSync(filename).toString();
|
const content = fs.readFileSync(filename).toString();
|
||||||
@ -53,4 +57,12 @@ export const utils = {
|
|||||||
throw new Error(`Failed to read ${filename}: ${err}`);
|
throw new Error(`Failed to read ${filename}: ${err}`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getEmptyConstructor(): Web3.ConstructorAbi {
|
||||||
|
return {
|
||||||
|
type: 'constructor',
|
||||||
|
stateMutability: 'nonpayable',
|
||||||
|
payable: false,
|
||||||
|
inputs: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0xproject/assert",
|
"name": "@0xproject/assert",
|
||||||
"version": "0.0.8",
|
"version": "0.0.9",
|
||||||
"description": "Provides a standard way of performing type and schema validation across 0x projects",
|
"description": "Provides a standard way of performing type and schema validation across 0x projects",
|
||||||
"main": "lib/src/index.js",
|
"main": "lib/src/index.js",
|
||||||
"types": "lib/src/index.d.ts",
|
"types": "lib/src/index.d.ts",
|
||||||
@ -23,7 +23,7 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x.js/packages/assert/README.md",
|
"homepage": "https://github.com/0xProject/0x.js/packages/assert/README.md",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0xproject/tslint-config": "^0.3.0",
|
"@0xproject/tslint-config": "^0.4.0",
|
||||||
"@types/lodash": "^4.14.86",
|
"@types/lodash": "^4.14.86",
|
||||||
"@types/mocha": "^2.2.42",
|
"@types/mocha": "^2.2.42",
|
||||||
"@types/valid-url": "^1.0.2",
|
"@types/valid-url": "^1.0.2",
|
||||||
@ -37,8 +37,8 @@
|
|||||||
"typescript": "~2.6.1"
|
"typescript": "~2.6.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0xproject/json-schemas": "^0.7.0",
|
"@0xproject/json-schemas": "^0.7.1",
|
||||||
"@0xproject/utils": "^0.1.1",
|
"@0xproject/utils": "^0.1.2",
|
||||||
"bignumber.js": "~4.1.0",
|
"bignumber.js": "~4.1.0",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"valid-url": "^1.0.9"
|
"valid-url": "^1.0.9"
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
import {
|
import { Schema, SchemaValidator } from '@0xproject/json-schemas';
|
||||||
Schema,
|
import { addressUtils } from '@0xproject/utils';
|
||||||
SchemaValidator,
|
|
||||||
} from '@0xproject/json-schemas';
|
|
||||||
import {addressUtils} from '@0xproject/utils';
|
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as validUrl from 'valid-url';
|
import * as validUrl from 'valid-url';
|
||||||
@ -18,7 +15,8 @@ export const assert = {
|
|||||||
assert.isBigNumber(variableName, value);
|
assert.isBigNumber(variableName, value);
|
||||||
const hasDecimals = value.decimalPlaces() !== 0;
|
const hasDecimals = value.decimalPlaces() !== 0;
|
||||||
this.assert(
|
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 {
|
isUndefined(value: any, variableName?: string): void {
|
||||||
@ -31,8 +29,10 @@ export const assert = {
|
|||||||
this.assert(_.isFunction(value), this.typeAssertionMessage(variableName, 'function', value));
|
this.assert(_.isFunction(value), this.typeAssertionMessage(variableName, 'function', value));
|
||||||
},
|
},
|
||||||
isHexString(variableName: string, value: string): void {
|
isHexString(variableName: string, value: string): void {
|
||||||
this.assert(_.isString(value) && HEX_REGEX.test(value),
|
this.assert(
|
||||||
this.typeAssertionMessage(variableName, 'HexString', value));
|
_.isString(value) && HEX_REGEX.test(value),
|
||||||
|
this.typeAssertionMessage(variableName, 'HexString', value),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
isETHAddressHex(variableName: string, value: string): void {
|
isETHAddressHex(variableName: string, value: string): void {
|
||||||
this.assert(addressUtils.isAddress(value), this.typeAssertionMessage(variableName, 'ETHAddressHex', value));
|
this.assert(addressUtils.isAddress(value), this.typeAssertionMessage(variableName, 'ETHAddressHex', value));
|
||||||
@ -41,8 +41,11 @@ export const assert = {
|
|||||||
`Checksummed addresses are not supported. Convert ${variableName} to lower case before passing`,
|
`Checksummed addresses are not supported. Convert ${variableName} to lower case before passing`,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
doesBelongToStringEnum(variableName: string, value: string,
|
doesBelongToStringEnum(
|
||||||
stringEnum: any /* There is no base type for every string enum */): void {
|
variableName: string,
|
||||||
|
value: string,
|
||||||
|
stringEnum: any /* There is no base type for every string enum */,
|
||||||
|
): void {
|
||||||
const doesBelongToStringEnum = !_.isUndefined(stringEnum[value]);
|
const doesBelongToStringEnum = !_.isUndefined(stringEnum[value]);
|
||||||
const enumValues = _.keys(stringEnum);
|
const enumValues = _.keys(stringEnum);
|
||||||
const enumValuesAsStrings = _.map(enumValues, enumValue => `'${enumValue}'`);
|
const enumValuesAsStrings = _.map(enumValues, enumValue => `'${enumValue}'`);
|
||||||
@ -62,7 +65,7 @@ export const assert = {
|
|||||||
this.assert(_.isBoolean(value), this.typeAssertionMessage(variableName, 'boolean', value));
|
this.assert(_.isBoolean(value), this.typeAssertionMessage(variableName, 'boolean', value));
|
||||||
},
|
},
|
||||||
isWeb3Provider(variableName: string, value: any): void {
|
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));
|
this.assert(isWeb3Provider, this.typeAssertionMessage(variableName, 'Web3.Provider', value));
|
||||||
},
|
},
|
||||||
doesConformToSchema(variableName: string, value: any, schema: Schema): void {
|
doesConformToSchema(variableName: string, value: any, schema: Schema): void {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import {schemas} from '@0xproject/json-schemas';
|
import { schemas } from '@0xproject/json-schemas';
|
||||||
import {BigNumber} from 'bignumber.js';
|
import { BigNumber } from 'bignumber.js';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import * as dirtyChai from 'dirty-chai';
|
import * as dirtyChai from 'dirty-chai';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
|
|
||||||
import {assert} from '../src/index';
|
import { assert } from '../src/index';
|
||||||
|
|
||||||
chai.config.includeStack = true;
|
chai.config.includeStack = true;
|
||||||
chai.use(dirtyChai);
|
chai.use(dirtyChai);
|
||||||
@ -14,75 +14,41 @@ describe('Assertions', () => {
|
|||||||
const variableName = 'variable';
|
const variableName = 'variable';
|
||||||
describe('#isBigNumber', () => {
|
describe('#isBigNumber', () => {
|
||||||
it('should not throw for valid input', () => {
|
it('should not throw for valid input', () => {
|
||||||
const validInputs = [
|
const validInputs = [new BigNumber(23), new BigNumber('45')];
|
||||||
new BigNumber(23),
|
|
||||||
new BigNumber('45'),
|
|
||||||
];
|
|
||||||
validInputs.forEach(input => expect(assert.isBigNumber.bind(assert, variableName, input)).to.not.throw());
|
validInputs.forEach(input => expect(assert.isBigNumber.bind(assert, variableName, input)).to.not.throw());
|
||||||
});
|
});
|
||||||
it('should throw for invalid input', () => {
|
it('should throw for invalid input', () => {
|
||||||
const invalidInputs = [
|
const invalidInputs = ['test', 42, false, { random: 'test' }, undefined];
|
||||||
'test',
|
|
||||||
42,
|
|
||||||
false,
|
|
||||||
{random: 'test'},
|
|
||||||
undefined,
|
|
||||||
];
|
|
||||||
invalidInputs.forEach(input => expect(assert.isBigNumber.bind(assert, variableName, input)).to.throw());
|
invalidInputs.forEach(input => expect(assert.isBigNumber.bind(assert, variableName, input)).to.throw());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#isUndefined', () => {
|
describe('#isUndefined', () => {
|
||||||
it('should not throw for valid input', () => {
|
it('should not throw for valid input', () => {
|
||||||
const validInputs = [
|
const validInputs = [undefined];
|
||||||
undefined,
|
|
||||||
];
|
|
||||||
validInputs.forEach(input => expect(assert.isUndefined.bind(assert, input, variableName)).to.not.throw());
|
validInputs.forEach(input => expect(assert.isUndefined.bind(assert, input, variableName)).to.not.throw());
|
||||||
});
|
});
|
||||||
it('should throw for invalid input', () => {
|
it('should throw for invalid input', () => {
|
||||||
const invalidInputs = [
|
const invalidInputs = ['test', 42, false, { random: 'test' }];
|
||||||
'test',
|
|
||||||
42,
|
|
||||||
false,
|
|
||||||
{random: 'test'},
|
|
||||||
];
|
|
||||||
invalidInputs.forEach(input => expect(assert.isUndefined.bind(assert, input, variableName)).to.throw());
|
invalidInputs.forEach(input => expect(assert.isUndefined.bind(assert, input, variableName)).to.throw());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#isString', () => {
|
describe('#isString', () => {
|
||||||
it('should not throw for valid input', () => {
|
it('should not throw for valid input', () => {
|
||||||
const validInputs = [
|
const validInputs = ['hello', 'goodbye'];
|
||||||
'hello',
|
|
||||||
'goodbye',
|
|
||||||
];
|
|
||||||
validInputs.forEach(input => expect(assert.isString.bind(assert, variableName, input)).to.not.throw());
|
validInputs.forEach(input => expect(assert.isString.bind(assert, variableName, input)).to.not.throw());
|
||||||
});
|
});
|
||||||
it('should throw for invalid input', () => {
|
it('should throw for invalid input', () => {
|
||||||
const invalidInputs = [
|
const invalidInputs = [42, false, { random: 'test' }, undefined, new BigNumber(45)];
|
||||||
42,
|
|
||||||
false,
|
|
||||||
{random: 'test'},
|
|
||||||
undefined,
|
|
||||||
new BigNumber(45),
|
|
||||||
];
|
|
||||||
invalidInputs.forEach(input => expect(assert.isString.bind(assert, variableName, input)).to.throw());
|
invalidInputs.forEach(input => expect(assert.isString.bind(assert, variableName, input)).to.throw());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#isFunction', () => {
|
describe('#isFunction', () => {
|
||||||
it('should not throw for valid input', () => {
|
it('should not throw for valid input', () => {
|
||||||
const validInputs = [
|
const validInputs = [BigNumber, assert.isString.bind(this)];
|
||||||
BigNumber,
|
|
||||||
assert.isString.bind(this),
|
|
||||||
];
|
|
||||||
validInputs.forEach(input => expect(assert.isFunction.bind(assert, variableName, input)).to.not.throw());
|
validInputs.forEach(input => expect(assert.isFunction.bind(assert, variableName, input)).to.not.throw());
|
||||||
});
|
});
|
||||||
it('should throw for invalid input', () => {
|
it('should throw for invalid input', () => {
|
||||||
const invalidInputs = [
|
const invalidInputs = [42, false, { random: 'test' }, undefined, new BigNumber(45)];
|
||||||
42,
|
|
||||||
false,
|
|
||||||
{random: 'test'},
|
|
||||||
undefined,
|
|
||||||
new BigNumber(45),
|
|
||||||
];
|
|
||||||
invalidInputs.forEach(input => expect(assert.isFunction.bind(assert, variableName, input)).to.throw());
|
invalidInputs.forEach(input => expect(assert.isFunction.bind(assert, variableName, input)).to.throw());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -98,7 +64,7 @@ describe('Assertions', () => {
|
|||||||
const invalidInputs = [
|
const invalidInputs = [
|
||||||
42,
|
42,
|
||||||
false,
|
false,
|
||||||
{random: 'test'},
|
{ random: 'test' },
|
||||||
undefined,
|
undefined,
|
||||||
new BigNumber(45),
|
new BigNumber(45),
|
||||||
'0x61a3ed31B43c8780e905a260a35faYfEc527be7516aa11c0256729b5b351bc33',
|
'0x61a3ed31B43c8780e905a260a35faYfEc527be7516aa11c0256729b5b351bc33',
|
||||||
@ -121,15 +87,13 @@ describe('Assertions', () => {
|
|||||||
const invalidInputs = [
|
const invalidInputs = [
|
||||||
42,
|
42,
|
||||||
false,
|
false,
|
||||||
{random: 'test'},
|
{ random: 'test' },
|
||||||
undefined,
|
undefined,
|
||||||
new BigNumber(45),
|
new BigNumber(45),
|
||||||
'0x6FFFd0ae3f7d88c9b4925323f54c6e4b2918c5fd',
|
'0x6FFFd0ae3f7d88c9b4925323f54c6e4b2918c5fd',
|
||||||
'0x6FFFd0ae3f7d88c9b4925323f54c6e4',
|
'0x6FFFd0ae3f7d88c9b4925323f54c6e4',
|
||||||
];
|
];
|
||||||
invalidInputs.forEach(input =>
|
invalidInputs.forEach(input => expect(assert.isETHAddressHex.bind(assert, variableName, input)).to.throw());
|
||||||
expect(assert.isETHAddressHex.bind(assert, variableName, input)).to.throw(),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#doesBelongToStringEnum', () => {
|
describe('#doesBelongToStringEnum', () => {
|
||||||
@ -138,22 +102,13 @@ describe('Assertions', () => {
|
|||||||
Test2 = 'Test2',
|
Test2 = 'Test2',
|
||||||
}
|
}
|
||||||
it('should not throw for valid input', () => {
|
it('should not throw for valid input', () => {
|
||||||
const validInputs = [
|
const validInputs = [TestEnums.Test1, TestEnums.Test2];
|
||||||
TestEnums.Test1,
|
|
||||||
TestEnums.Test2,
|
|
||||||
];
|
|
||||||
validInputs.forEach(input =>
|
validInputs.forEach(input =>
|
||||||
expect(assert.doesBelongToStringEnum.bind(assert, variableName, input, TestEnums)).to.not.throw(),
|
expect(assert.doesBelongToStringEnum.bind(assert, variableName, input, TestEnums)).to.not.throw(),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should throw for invalid input', () => {
|
it('should throw for invalid input', () => {
|
||||||
const invalidInputs = [
|
const invalidInputs = [42, false, { random: 'test' }, undefined, new BigNumber(45)];
|
||||||
42,
|
|
||||||
false,
|
|
||||||
{random: 'test'},
|
|
||||||
undefined,
|
|
||||||
new BigNumber(45),
|
|
||||||
];
|
|
||||||
invalidInputs.forEach(input =>
|
invalidInputs.forEach(input =>
|
||||||
expect(assert.doesBelongToStringEnum.bind(assert, variableName, input, TestEnums)).to.throw(),
|
expect(assert.doesBelongToStringEnum.bind(assert, variableName, input, TestEnums)).to.throw(),
|
||||||
);
|
);
|
||||||
@ -162,19 +117,13 @@ describe('Assertions', () => {
|
|||||||
describe('#hasAtMostOneUniqueValue', () => {
|
describe('#hasAtMostOneUniqueValue', () => {
|
||||||
const errorMsg = 'more than one unique value';
|
const errorMsg = 'more than one unique value';
|
||||||
it('should not throw for valid input', () => {
|
it('should not throw for valid input', () => {
|
||||||
const validInputs = [
|
const validInputs = [['hello'], ['goodbye', 'goodbye', 'goodbye']];
|
||||||
['hello'],
|
|
||||||
['goodbye', 'goodbye', 'goodbye'],
|
|
||||||
];
|
|
||||||
validInputs.forEach(input =>
|
validInputs.forEach(input =>
|
||||||
expect(assert.hasAtMostOneUniqueValue.bind(assert, input, errorMsg)).to.not.throw(),
|
expect(assert.hasAtMostOneUniqueValue.bind(assert, input, errorMsg)).to.not.throw(),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should throw for invalid input', () => {
|
it('should throw for invalid input', () => {
|
||||||
const invalidInputs = [
|
const invalidInputs = [['hello', 'goodbye'], ['goodbye', 42, false, false]];
|
||||||
['hello', 'goodbye'],
|
|
||||||
['goodbye', 42, false, false],
|
|
||||||
];
|
|
||||||
invalidInputs.forEach(input =>
|
invalidInputs.forEach(input =>
|
||||||
expect(assert.hasAtMostOneUniqueValue.bind(assert, input, errorMsg)).to.throw(),
|
expect(assert.hasAtMostOneUniqueValue.bind(assert, input, errorMsg)).to.throw(),
|
||||||
);
|
);
|
||||||
@ -182,61 +131,34 @@ describe('Assertions', () => {
|
|||||||
});
|
});
|
||||||
describe('#isNumber', () => {
|
describe('#isNumber', () => {
|
||||||
it('should not throw for valid input', () => {
|
it('should not throw for valid input', () => {
|
||||||
const validInputs = [
|
const validInputs = [42, 0, 21e42];
|
||||||
42,
|
|
||||||
0,
|
|
||||||
21e+42,
|
|
||||||
];
|
|
||||||
validInputs.forEach(input => expect(assert.isNumber.bind(assert, variableName, input)).to.not.throw());
|
validInputs.forEach(input => expect(assert.isNumber.bind(assert, variableName, input)).to.not.throw());
|
||||||
});
|
});
|
||||||
it('should throw for invalid input', () => {
|
it('should throw for invalid input', () => {
|
||||||
const invalidInputs = [
|
const invalidInputs = [false, { random: 'test' }, undefined, new BigNumber(45)];
|
||||||
false,
|
|
||||||
{random: 'test'},
|
|
||||||
undefined,
|
|
||||||
new BigNumber(45),
|
|
||||||
];
|
|
||||||
invalidInputs.forEach(input => expect(assert.isNumber.bind(assert, variableName, input)).to.throw());
|
invalidInputs.forEach(input => expect(assert.isNumber.bind(assert, variableName, input)).to.throw());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#isBoolean', () => {
|
describe('#isBoolean', () => {
|
||||||
it('should not throw for valid input', () => {
|
it('should not throw for valid input', () => {
|
||||||
const validInputs = [
|
const validInputs = [true, false];
|
||||||
true,
|
|
||||||
false,
|
|
||||||
];
|
|
||||||
validInputs.forEach(input => expect(assert.isBoolean.bind(assert, variableName, input)).to.not.throw());
|
validInputs.forEach(input => expect(assert.isBoolean.bind(assert, variableName, input)).to.not.throw());
|
||||||
});
|
});
|
||||||
it('should throw for invalid input', () => {
|
it('should throw for invalid input', () => {
|
||||||
const invalidInputs = [
|
const invalidInputs = [42, { random: 'test' }, undefined, new BigNumber(45)];
|
||||||
42,
|
|
||||||
{random: 'test'},
|
|
||||||
undefined,
|
|
||||||
new BigNumber(45),
|
|
||||||
];
|
|
||||||
invalidInputs.forEach(input => expect(assert.isBoolean.bind(assert, variableName, input)).to.throw());
|
invalidInputs.forEach(input => expect(assert.isBoolean.bind(assert, variableName, input)).to.throw());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#isWeb3Provider', () => {
|
describe('#isWeb3Provider', () => {
|
||||||
it('should not throw for valid input', () => {
|
it('should not throw for valid input', () => {
|
||||||
const validInputs = [
|
const validInputs = [{ send: () => 45 }, { sendAsync: () => 45 }];
|
||||||
{send: () => 45},
|
|
||||||
{sendAsync: () => 45},
|
|
||||||
];
|
|
||||||
validInputs.forEach(input =>
|
validInputs.forEach(input =>
|
||||||
expect(assert.isWeb3Provider.bind(assert, variableName, input)).to.not.throw(),
|
expect(assert.isWeb3Provider.bind(assert, variableName, input)).to.not.throw(),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should throw for invalid input', () => {
|
it('should throw for invalid input', () => {
|
||||||
const invalidInputs = [
|
const invalidInputs = [42, { random: 'test' }, undefined, new BigNumber(45)];
|
||||||
42,
|
invalidInputs.forEach(input => expect(assert.isWeb3Provider.bind(assert, variableName, input)).to.throw());
|
||||||
{random: 'test'},
|
|
||||||
undefined,
|
|
||||||
new BigNumber(45),
|
|
||||||
];
|
|
||||||
invalidInputs.forEach(input =>
|
|
||||||
expect(assert.isWeb3Provider.bind(assert, variableName, input)).to.throw(),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#doesConformToSchema', () => {
|
describe('#doesConformToSchema', () => {
|
||||||
@ -251,12 +173,7 @@ describe('Assertions', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should throw for invalid input', () => {
|
it('should throw for invalid input', () => {
|
||||||
const invalidInputs = [
|
const invalidInputs = [42, { random: 'test' }, undefined, new BigNumber(45)];
|
||||||
42,
|
|
||||||
{random: 'test'},
|
|
||||||
undefined,
|
|
||||||
new BigNumber(45),
|
|
||||||
];
|
|
||||||
invalidInputs.forEach(input =>
|
invalidInputs.forEach(input =>
|
||||||
expect(assert.doesConformToSchema.bind(assert, variableName, input, schema)).to.throw(),
|
expect(assert.doesConformToSchema.bind(assert, variableName, input, schema)).to.throw(),
|
||||||
);
|
);
|
||||||
@ -270,14 +187,12 @@ describe('Assertions', () => {
|
|||||||
'https://api.radarrelay.com/0x/v0/',
|
'https://api.radarrelay.com/0x/v0/',
|
||||||
'https://zeroex.beta.radarrelay.com:8000/0x/v0/',
|
'https://zeroex.beta.radarrelay.com:8000/0x/v0/',
|
||||||
];
|
];
|
||||||
validInputs.forEach(input =>
|
validInputs.forEach(input => expect(assert.isHttpUrl.bind(assert, variableName, input)).to.not.throw());
|
||||||
expect(assert.isHttpUrl.bind(assert, variableName, input)).to.not.throw(),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
it('should throw for invalid input', () => {
|
it('should throw for invalid input', () => {
|
||||||
const invalidInputs = [
|
const invalidInputs = [
|
||||||
42,
|
42,
|
||||||
{random: 'test'},
|
{ random: 'test' },
|
||||||
undefined,
|
undefined,
|
||||||
new BigNumber(45),
|
new BigNumber(45),
|
||||||
'ws://www.api.example-relayer.net',
|
'ws://www.api.example-relayer.net',
|
||||||
@ -286,9 +201,7 @@ describe('Assertions', () => {
|
|||||||
'user:password@api.example-relayer.net',
|
'user:password@api.example-relayer.net',
|
||||||
'//api.example-relayer.net',
|
'//api.example-relayer.net',
|
||||||
];
|
];
|
||||||
invalidInputs.forEach(input =>
|
invalidInputs.forEach(input => expect(assert.isHttpUrl.bind(assert, variableName, input)).to.throw());
|
||||||
expect(assert.isHttpUrl.bind(assert, variableName, input)).to.throw(),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#isUri', () => {
|
describe('#isUri', () => {
|
||||||
@ -302,23 +215,19 @@ describe('Assertions', () => {
|
|||||||
'wss://www.api.example-relayer.net',
|
'wss://www.api.example-relayer.net',
|
||||||
'user:password@api.example-relayer.net',
|
'user:password@api.example-relayer.net',
|
||||||
];
|
];
|
||||||
validInputs.forEach(input =>
|
validInputs.forEach(input => expect(assert.isUri.bind(assert, variableName, input)).to.not.throw());
|
||||||
expect(assert.isUri.bind(assert, variableName, input)).to.not.throw(),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
it('should throw for invalid input', () => {
|
it('should throw for invalid input', () => {
|
||||||
const invalidInputs = [
|
const invalidInputs = [
|
||||||
42,
|
42,
|
||||||
{random: 'test'},
|
{ random: 'test' },
|
||||||
undefined,
|
undefined,
|
||||||
new BigNumber(45),
|
new BigNumber(45),
|
||||||
'www.google.com',
|
'www.google.com',
|
||||||
'api.example-relayer.net',
|
'api.example-relayer.net',
|
||||||
'//api.example-relayer.net',
|
'//api.example-relayer.net',
|
||||||
];
|
];
|
||||||
invalidInputs.forEach(input =>
|
invalidInputs.forEach(input => expect(assert.isUri.bind(assert, variableName, input)).to.throw());
|
||||||
expect(assert.isUri.bind(assert, variableName, input)).to.throw(),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#assert', () => {
|
describe('#assert', () => {
|
||||||
@ -332,8 +241,9 @@ describe('Assertions', () => {
|
|||||||
});
|
});
|
||||||
describe('#typeAssertionMessage', () => {
|
describe('#typeAssertionMessage', () => {
|
||||||
it('should render correct message', () => {
|
it('should render correct message', () => {
|
||||||
expect(assert.typeAssertionMessage('variable', 'string', 'number'))
|
expect(assert.typeAssertionMessage('variable', 'string', 'number')).to.equal(
|
||||||
.to.equal(`Expected variable to be of type string, encountered: number`);
|
`Expected variable to be of type string, encountered: number`,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@0xproject/connect",
|
"name": "@0xproject/connect",
|
||||||
"version": "0.3.1",
|
"version": "0.3.2",
|
||||||
"description": "A javascript library for interacting with the standard relayer api",
|
"description": "A javascript library for interacting with the standard relayer api",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"connect",
|
"connect",
|
||||||
@ -36,9 +36,9 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/0xProject/0x.js/packages/connect/README.md",
|
"homepage": "https://github.com/0xProject/0x.js/packages/connect/README.md",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@0xproject/assert": "^0.0.8",
|
"@0xproject/assert": "^0.0.9",
|
||||||
"@0xproject/json-schemas": "^0.7.0",
|
"@0xproject/json-schemas": "^0.7.1",
|
||||||
"@0xproject/utils": "^0.1.1",
|
"@0xproject/utils": "^0.1.2",
|
||||||
"bignumber.js": "~4.1.0",
|
"bignumber.js": "~4.1.0",
|
||||||
"isomorphic-fetch": "^2.2.1",
|
"isomorphic-fetch": "^2.2.1",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
@ -46,7 +46,7 @@
|
|||||||
"websocket": "^1.0.25"
|
"websocket": "^1.0.25"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@0xproject/tslint-config": "^0.3.0",
|
"@0xproject/tslint-config": "^0.4.0",
|
||||||
"@types/fetch-mock": "^5.12.1",
|
"@types/fetch-mock": "^5.12.1",
|
||||||
"@types/lodash": "^4.14.86",
|
"@types/lodash": "^4.14.86",
|
||||||
"@types/mocha": "^2.2.42",
|
"@types/mocha": "^2.2.42",
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import {assert} from '@0xproject/assert';
|
import { assert } from '@0xproject/assert';
|
||||||
import {schemas} from '@0xproject/json-schemas';
|
import { schemas } from '@0xproject/json-schemas';
|
||||||
import 'isomorphic-fetch';
|
import 'isomorphic-fetch';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as queryString from 'query-string';
|
import * as queryString from 'query-string';
|
||||||
|
|
||||||
import {schemas as clientSchemas} from './schemas/schemas';
|
import { schemas as clientSchemas } from './schemas/schemas';
|
||||||
import {
|
import {
|
||||||
Client,
|
Client,
|
||||||
FeesRequest,
|
FeesRequest,
|
||||||
@ -18,7 +18,7 @@ import {
|
|||||||
TokenPairsItem,
|
TokenPairsItem,
|
||||||
TokenPairsRequest,
|
TokenPairsRequest,
|
||||||
} from './types';
|
} from './types';
|
||||||
import {typeConverters} from './utils/type_converters';
|
import { typeConverters } from './utils/type_converters';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class includes all the functionality related to interacting with a set of HTTP endpoints
|
* This class includes all the functionality related to interacting with a set of HTTP endpoints
|
||||||
@ -49,8 +49,7 @@ export class HttpClient implements Client {
|
|||||||
params: request,
|
params: request,
|
||||||
};
|
};
|
||||||
const tokenPairs = await this._requestAsync('/token_pairs', HttpRequestType.Get, requestOpts);
|
const tokenPairs = await this._requestAsync('/token_pairs', HttpRequestType.Get, requestOpts);
|
||||||
assert.doesConformToSchema(
|
assert.doesConformToSchema('tokenPairs', tokenPairs, schemas.relayerApiTokenPairsResponseSchema);
|
||||||
'tokenPairs', tokenPairs, schemas.relayerApiTokenPairsResponseSchema);
|
|
||||||
_.each(tokenPairs, (tokenPair: object) => {
|
_.each(tokenPairs, (tokenPair: object) => {
|
||||||
typeConverters.convertStringsFieldsToBigNumbers(tokenPair, [
|
typeConverters.convertStringsFieldsToBigNumbers(tokenPair, [
|
||||||
'tokenA.minAmount',
|
'tokenA.minAmount',
|
||||||
@ -131,8 +130,11 @@ export class HttpClient implements Client {
|
|||||||
};
|
};
|
||||||
await this._requestAsync('/order', HttpRequestType.Post, requestOpts);
|
await this._requestAsync('/order', HttpRequestType.Post, requestOpts);
|
||||||
}
|
}
|
||||||
private async _requestAsync(path: string, requestType: HttpRequestType,
|
private async _requestAsync(
|
||||||
requestOptions?: HttpRequestOptions): Promise<any> {
|
path: string,
|
||||||
|
requestType: HttpRequestType,
|
||||||
|
requestOptions?: HttpRequestOptions,
|
||||||
|
): Promise<any> {
|
||||||
const params = _.get(requestOptions, 'params');
|
const params = _.get(requestOptions, 'params');
|
||||||
const payload = _.get(requestOptions, 'payload');
|
const payload = _.get(requestOptions, 'payload');
|
||||||
let query = '';
|
let query = '';
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import {bigNumberConfigs} from '@0xproject/utils';
|
import { bigNumberConfigs } from '@0xproject/utils';
|
||||||
|
|
||||||
// Customize our BigNumber instances
|
// Customize our BigNumber instances
|
||||||
bigNumberConfigs.configure();
|
bigNumberConfigs.configure();
|
||||||
|
|
||||||
export {HttpClient} from './http_client';
|
export { HttpClient } from './http_client';
|
||||||
export {WebSocketOrderbookChannel} from './ws_orderbook_channel';
|
export { WebSocketOrderbookChannel } from './ws_orderbook_channel';
|
||||||
export {
|
export {
|
||||||
Client,
|
Client,
|
||||||
ECSignature,
|
ECSignature,
|
||||||
|
@ -2,7 +2,7 @@ export const relayerOrderBookRequestSchema = {
|
|||||||
id: '/RelayerOrderBookRequest',
|
id: '/RelayerOrderBookRequest',
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
baseTokenAddress: {$ref: '/Address'},
|
baseTokenAddress: { $ref: '/Address' },
|
||||||
quoteTokenAddress: {$ref: '/Address'},
|
quoteTokenAddress: { $ref: '/Address' },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -2,7 +2,7 @@ export const relayerOrderBookRequestSchema = {
|
|||||||
id: '/RelayerOrderBookRequest',
|
id: '/RelayerOrderBookRequest',
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
baseTokenAddress: {$ref: '/Address'},
|
baseTokenAddress: { $ref: '/Address' },
|
||||||
quoteTokenAddress: {$ref: '/Address'},
|
quoteTokenAddress: { $ref: '/Address' },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -2,15 +2,15 @@ export const relayerOrdersRequestSchema = {
|
|||||||
id: '/RelayerOrdersRequest',
|
id: '/RelayerOrdersRequest',
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
exchangeContractAddress: {$ref: '/Address'},
|
exchangeContractAddress: { $ref: '/Address' },
|
||||||
tokenAddress: {$ref: '/Address'},
|
tokenAddress: { $ref: '/Address' },
|
||||||
makerTokenAddress: {$ref: '/Address'},
|
makerTokenAddress: { $ref: '/Address' },
|
||||||
takerTokenAddress: {$ref: '/Address'},
|
takerTokenAddress: { $ref: '/Address' },
|
||||||
tokenA: {$ref: '/Address'},
|
tokenA: { $ref: '/Address' },
|
||||||
tokenB: {$ref: '/Address'},
|
tokenB: { $ref: '/Address' },
|
||||||
maker: {$ref: '/Address'},
|
maker: { $ref: '/Address' },
|
||||||
taker: {$ref: '/Address'},
|
taker: { $ref: '/Address' },
|
||||||
trader: {$ref: '/Address'},
|
trader: { $ref: '/Address' },
|
||||||
feeRecipient: {$ref: '/Address'},
|
feeRecipient: { $ref: '/Address' },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -2,7 +2,7 @@ export const relayerTokenPairsRequestSchema = {
|
|||||||
id: '/RelayerTokenPairsRequest',
|
id: '/RelayerTokenPairsRequest',
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
tokenA: {$ref: '/Address'},
|
tokenA: { $ref: '/Address' },
|
||||||
tokenB: {$ref: '/Address'},
|
tokenB: { $ref: '/Address' },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,12 +1,6 @@
|
|||||||
import {
|
import { relayerOrderBookRequestSchema } from './relayer_orderbook_request_schema';
|
||||||
relayerOrderBookRequestSchema,
|
import { relayerOrdersRequestSchema } from './relayer_orders_request_schema';
|
||||||
} from './relayer_orderbook_request_schema';
|
import { relayerTokenPairsRequestSchema } from './relayer_token_pairs_request_schema';
|
||||||
import {
|
|
||||||
relayerOrdersRequestSchema,
|
|
||||||
} from './relayer_orders_request_schema';
|
|
||||||
import {
|
|
||||||
relayerTokenPairsRequestSchema,
|
|
||||||
} from './relayer_token_pairs_request_schema';
|
|
||||||
|
|
||||||
export const schemas = {
|
export const schemas = {
|
||||||
relayerOrderBookRequestSchema,
|
relayerOrderBookRequestSchema,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {BigNumber} from 'bignumber.js';
|
import { BigNumber } from 'bignumber.js';
|
||||||
|
|
||||||
// TODO: Consolidate Order, SignedOrder and ECSignature into a shared package instead of duplicating them from 0x.js
|
// TODO: Consolidate Order, SignedOrder and ECSignature into a shared package instead of duplicating them from 0x.js
|
||||||
export interface Order {
|
export interface Order {
|
||||||
@ -57,19 +57,24 @@ export interface OrderbookChannelSubscriptionOpts {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderbookChannelHandler {
|
export interface OrderbookChannelHandler {
|
||||||
onSnapshot: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts,
|
onSnapshot: (
|
||||||
snapshot: OrderbookResponse) => void;
|
channel: OrderbookChannel,
|
||||||
onUpdate: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts,
|
subscriptionOpts: OrderbookChannelSubscriptionOpts,
|
||||||
order: SignedOrder) => void;
|
snapshot: OrderbookResponse,
|
||||||
onError: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts,
|
) => void;
|
||||||
err: Error) => void;
|
onUpdate: (
|
||||||
|
channel: OrderbookChannel,
|
||||||
|
subscriptionOpts: OrderbookChannelSubscriptionOpts,
|
||||||
|
order: SignedOrder,
|
||||||
|
) => void;
|
||||||
|
onError: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts, err: Error) => void;
|
||||||
onClose: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts) => void;
|
onClose: (channel: OrderbookChannel, subscriptionOpts: OrderbookChannelSubscriptionOpts) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type OrderbookChannelMessage =
|
export type OrderbookChannelMessage =
|
||||||
SnapshotOrderbookChannelMessage |
|
| SnapshotOrderbookChannelMessage
|
||||||
UpdateOrderbookChannelMessage |
|
| UpdateOrderbookChannelMessage
|
||||||
UnknownOrderbookChannelMessage;
|
| UnknownOrderbookChannelMessage;
|
||||||
|
|
||||||
export enum OrderbookChannelMessageTypes {
|
export enum OrderbookChannelMessageTypes {
|
||||||
Snapshot = 'snapshot',
|
Snapshot = 'snapshot',
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
import {assert} from '@0xproject/assert';
|
import { assert } from '@0xproject/assert';
|
||||||
import {schemas} from '@0xproject/json-schemas';
|
import { schemas } from '@0xproject/json-schemas';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {
|
import { OrderbookChannelMessage, OrderbookChannelMessageTypes } from '../types';
|
||||||
OrderbookChannelMessage,
|
|
||||||
OrderbookChannelMessageTypes,
|
|
||||||
} from '../types';
|
|
||||||
|
|
||||||
import {typeConverters} from './type_converters';
|
import { typeConverters } from './type_converters';
|
||||||
|
|
||||||
export const orderbookChannelMessageParsers = {
|
export const orderbookChannelMessageParsers = {
|
||||||
parser(utf8Data: string): OrderbookChannelMessage {
|
parser(utf8Data: string): OrderbookChannelMessage {
|
||||||
@ -16,13 +13,13 @@ export const orderbookChannelMessageParsers = {
|
|||||||
assert.assert(!_.isUndefined(type), `Message is missing a type parameter: ${utf8Data}`);
|
assert.assert(!_.isUndefined(type), `Message is missing a type parameter: ${utf8Data}`);
|
||||||
assert.isString('type', type);
|
assert.isString('type', type);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case (OrderbookChannelMessageTypes.Snapshot): {
|
case OrderbookChannelMessageTypes.Snapshot: {
|
||||||
assert.doesConformToSchema('message', messageObj, schemas.relayerApiOrderbookChannelSnapshotSchema);
|
assert.doesConformToSchema('message', messageObj, schemas.relayerApiOrderbookChannelSnapshotSchema);
|
||||||
const orderbook = messageObj.payload;
|
const orderbook = messageObj.payload;
|
||||||
typeConverters.convertOrderbookStringFieldsToBigNumber(orderbook);
|
typeConverters.convertOrderbookStringFieldsToBigNumber(orderbook);
|
||||||
return messageObj;
|
return messageObj;
|
||||||
}
|
}
|
||||||
case (OrderbookChannelMessageTypes.Update): {
|
case OrderbookChannelMessageTypes.Update: {
|
||||||
assert.doesConformToSchema('message', messageObj, schemas.relayerApiOrderbookChannelUpdateSchema);
|
assert.doesConformToSchema('message', messageObj, schemas.relayerApiOrderbookChannelUpdateSchema);
|
||||||
const order = messageObj.payload;
|
const order = messageObj.payload;
|
||||||
typeConverters.convertOrderStringFieldsToBigNumber(order);
|
typeConverters.convertOrderStringFieldsToBigNumber(order);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {BigNumber} from 'bignumber.js';
|
import { BigNumber } from 'bignumber.js';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
// TODO: convert all of these to non-mutating, pure functions
|
// TODO: convert all of these to non-mutating, pure functions
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import {assert} from '@0xproject/assert';
|
import { assert } from '@0xproject/assert';
|
||||||
import {schemas} from '@0xproject/json-schemas';
|
import { schemas } from '@0xproject/json-schemas';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as WebSocket from 'websocket';
|
import * as WebSocket from 'websocket';
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ import {
|
|||||||
WebsocketClientEventType,
|
WebsocketClientEventType,
|
||||||
WebsocketConnectionEventType,
|
WebsocketConnectionEventType,
|
||||||
} from './types';
|
} from './types';
|
||||||
import {orderbookChannelMessageParsers} from './utils/orderbook_channel_message_parsers';
|
import { orderbookChannelMessageParsers } from './utils/orderbook_channel_message_parsers';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class includes all the functionality related to interacting with a websocket endpoint
|
* This class includes all the functionality related to interacting with a websocket endpoint
|
||||||
@ -41,7 +41,10 @@ export class WebSocketOrderbookChannel implements OrderbookChannel {
|
|||||||
*/
|
*/
|
||||||
public subscribe(subscriptionOpts: OrderbookChannelSubscriptionOpts, handler: OrderbookChannelHandler): void {
|
public subscribe(subscriptionOpts: OrderbookChannelSubscriptionOpts, handler: OrderbookChannelHandler): void {
|
||||||
assert.doesConformToSchema(
|
assert.doesConformToSchema(
|
||||||
'subscriptionOpts', subscriptionOpts, schemas.relayerApiOrderbookChannelSubscribePayload);
|
'subscriptionOpts',
|
||||||
|
subscriptionOpts,
|
||||||
|
schemas.relayerApiOrderbookChannelSubscribePayload,
|
||||||
|
);
|
||||||
assert.isFunction('handler.onSnapshot', _.get(handler, 'onSnapshot'));
|
assert.isFunction('handler.onSnapshot', _.get(handler, 'onSnapshot'));
|
||||||
assert.isFunction('handler.onUpdate', _.get(handler, 'onUpdate'));
|
assert.isFunction('handler.onUpdate', _.get(handler, 'onUpdate'));
|
||||||
assert.isFunction('handler.onError', _.get(handler, 'onError'));
|
assert.isFunction('handler.onError', _.get(handler, 'onError'));
|
||||||
@ -92,25 +95,32 @@ export class WebSocketOrderbookChannel implements OrderbookChannel {
|
|||||||
this._client.connect(this._apiEndpointUrl);
|
this._client.connect(this._apiEndpointUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private _handleWebSocketMessage(requestId: number, subscriptionOpts: OrderbookChannelSubscriptionOpts,
|
private _handleWebSocketMessage(
|
||||||
message: WebSocket.IMessage, handler: OrderbookChannelHandler): void {
|
requestId: number,
|
||||||
|
subscriptionOpts: OrderbookChannelSubscriptionOpts,
|
||||||
|
message: WebSocket.IMessage,
|
||||||
|
handler: OrderbookChannelHandler,
|
||||||
|
): void {
|
||||||
if (!_.isUndefined(message.utf8Data)) {
|
if (!_.isUndefined(message.utf8Data)) {
|
||||||
try {
|
try {
|
||||||
const utf8Data = message.utf8Data;
|
const utf8Data = message.utf8Data;
|
||||||
const parserResult = orderbookChannelMessageParsers.parser(utf8Data);
|
const parserResult = orderbookChannelMessageParsers.parser(utf8Data);
|
||||||
if (parserResult.requestId === requestId) {
|
if (parserResult.requestId === requestId) {
|
||||||
switch (parserResult.type) {
|
switch (parserResult.type) {
|
||||||
case (OrderbookChannelMessageTypes.Snapshot): {
|
case OrderbookChannelMessageTypes.Snapshot: {
|
||||||
handler.onSnapshot(this, subscriptionOpts, parserResult.payload);
|
handler.onSnapshot(this, subscriptionOpts, parserResult.payload);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case (OrderbookChannelMessageTypes.Update): {
|
case OrderbookChannelMessageTypes.Update: {
|
||||||
handler.onUpdate(this, subscriptionOpts, parserResult.payload);
|
handler.onUpdate(this, subscriptionOpts, parserResult.payload);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
handler.onError(
|
handler.onError(
|
||||||
this, subscriptionOpts, new Error(`Message has missing a type parameter: ${utf8Data}`));
|
this,
|
||||||
|
subscriptionOpts,
|
||||||
|
new Error(`Message has missing a type parameter: ${utf8Data}`),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import {BigNumber} from 'bignumber.js';
|
import { BigNumber } from 'bignumber.js';
|
||||||
|
|
||||||
import {FeesResponse} from '../../../src/types';
|
import { FeesResponse } from '../../../src/types';
|
||||||
|
|
||||||
export const feesResponse: FeesResponse = {
|
export const feesResponse: FeesResponse = {
|
||||||
feeRecipient: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
feeRecipient: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {BigNumber} from 'bignumber.js';
|
import { BigNumber } from 'bignumber.js';
|
||||||
|
|
||||||
export const orderResponse = {
|
export const orderResponse = {
|
||||||
maker: '0x9e56625509c2f60af937f23b7b532600390e8c8b',
|
maker: '0x9e56625509c2f60af937f23b7b532600390e8c8b',
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {BigNumber} from 'bignumber.js';
|
import { BigNumber } from 'bignumber.js';
|
||||||
|
|
||||||
export const orderbookResponse = {
|
export const orderbookResponse = {
|
||||||
bids: [
|
bids: [
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {BigNumber} from 'bignumber.js';
|
import { BigNumber } from 'bignumber.js';
|
||||||
|
|
||||||
export const ordersResponse = [
|
export const ordersResponse = [
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import {BigNumber} from 'bignumber.js';
|
import { BigNumber } from 'bignumber.js';
|
||||||
|
|
||||||
import {TokenPairsItem} from '../../../src/types';
|
import { TokenPairsItem } from '../../../src/types';
|
||||||
|
|
||||||
export const tokenPairsResponse: TokenPairsItem[] = [
|
export const tokenPairsResponse: TokenPairsItem[] = [
|
||||||
{
|
{
|
||||||
|
@ -1,24 +1,21 @@
|
|||||||
import {BigNumber} from 'bignumber.js';
|
import { BigNumber } from 'bignumber.js';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import * as chaiAsPromised from 'chai-as-promised';
|
import * as chaiAsPromised from 'chai-as-promised';
|
||||||
import * as dirtyChai from 'dirty-chai';
|
import * as dirtyChai from 'dirty-chai';
|
||||||
import * as fetchMock from 'fetch-mock';
|
import * as fetchMock from 'fetch-mock';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
|
|
||||||
import {HttpClient} from '../src/index';
|
import { HttpClient } from '../src/index';
|
||||||
|
|
||||||
import {feesResponse} from './fixtures/standard_relayer_api/fees';
|
import { feesResponse } from './fixtures/standard_relayer_api/fees';
|
||||||
import * as feesResponseJSON from './fixtures/standard_relayer_api/fees.json';
|
import * as feesResponseJSON from './fixtures/standard_relayer_api/fees.json';
|
||||||
import {
|
import { orderResponse } from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f';
|
||||||
orderResponse,
|
|
||||||
} from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f';
|
|
||||||
// tslint:disable-next-line:max-line-length
|
|
||||||
import * as orderResponseJSON from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f.json';
|
import * as orderResponseJSON from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f.json';
|
||||||
import {orderbookResponse} from './fixtures/standard_relayer_api/orderbook';
|
import { orderbookResponse } from './fixtures/standard_relayer_api/orderbook';
|
||||||
import * as orderbookJSON from './fixtures/standard_relayer_api/orderbook.json';
|
import * as orderbookJSON from './fixtures/standard_relayer_api/orderbook.json';
|
||||||
import {ordersResponse} from './fixtures/standard_relayer_api/orders';
|
import { ordersResponse } from './fixtures/standard_relayer_api/orders';
|
||||||
import * as ordersResponseJSON from './fixtures/standard_relayer_api/orders.json';
|
import * as ordersResponseJSON from './fixtures/standard_relayer_api/orders.json';
|
||||||
import {tokenPairsResponse} from './fixtures/standard_relayer_api/token_pairs';
|
import { tokenPairsResponse } from './fixtures/standard_relayer_api/token_pairs';
|
||||||
import * as tokenPairsResponseJSON from './fixtures/standard_relayer_api/token_pairs.json';
|
import * as tokenPairsResponseJSON from './fixtures/standard_relayer_api/token_pairs.json';
|
||||||
|
|
||||||
chai.config.includeStack = true;
|
chai.config.includeStack = true;
|
||||||
@ -50,7 +47,7 @@ describe('HttpClient', () => {
|
|||||||
expect(tokenPairs).to.be.deep.equal(tokenPairsResponse);
|
expect(tokenPairs).to.be.deep.equal(tokenPairsResponse);
|
||||||
});
|
});
|
||||||
it('throws an error for invalid JSON response', async () => {
|
it('throws an error for invalid JSON response', async () => {
|
||||||
fetchMock.get(url, {test: 'dummy'});
|
fetchMock.get(url, { test: 'dummy' });
|
||||||
expect(relayerClient.getTokenPairsAsync()).to.be.rejected();
|
expect(relayerClient.getTokenPairsAsync()).to.be.rejected();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -72,7 +69,7 @@ describe('HttpClient', () => {
|
|||||||
expect(orders).to.be.deep.equal(ordersResponse);
|
expect(orders).to.be.deep.equal(ordersResponse);
|
||||||
});
|
});
|
||||||
it('throws an error for invalid JSON response', async () => {
|
it('throws an error for invalid JSON response', async () => {
|
||||||
fetchMock.get(url, {test: 'dummy'});
|
fetchMock.get(url, { test: 'dummy' });
|
||||||
expect(relayerClient.getOrdersAsync()).to.be.rejected();
|
expect(relayerClient.getOrdersAsync()).to.be.rejected();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -85,7 +82,7 @@ describe('HttpClient', () => {
|
|||||||
expect(order).to.be.deep.equal(orderResponse);
|
expect(order).to.be.deep.equal(orderResponse);
|
||||||
});
|
});
|
||||||
it('throws an error for invalid JSON response', async () => {
|
it('throws an error for invalid JSON response', async () => {
|
||||||
fetchMock.get(url, {test: 'dummy'});
|
fetchMock.get(url, { test: 'dummy' });
|
||||||
expect(relayerClient.getOrderAsync(orderHash)).to.be.rejected();
|
expect(relayerClient.getOrderAsync(orderHash)).to.be.rejected();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -94,15 +91,16 @@ describe('HttpClient', () => {
|
|||||||
baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
quoteTokenAddress: '0xa2b31dacf30a9c50ca473337c01d8a201ae33e32',
|
quoteTokenAddress: '0xa2b31dacf30a9c50ca473337c01d8a201ae33e32',
|
||||||
};
|
};
|
||||||
// tslint:disable-next-line:max-line-length
|
const url = `${relayUrl}/v0/orderbook?baseTokenAddress=${request.baseTokenAddress}"eTokenAddress=${
|
||||||
const url = `${relayUrl}/v0/orderbook?baseTokenAddress=${request.baseTokenAddress}"eTokenAddress=${request.quoteTokenAddress}`;
|
request.quoteTokenAddress
|
||||||
|
}`;
|
||||||
it('gets order book', async () => {
|
it('gets order book', async () => {
|
||||||
fetchMock.get(url, orderbookJSON);
|
fetchMock.get(url, orderbookJSON);
|
||||||
const orderbook = await relayerClient.getOrderbookAsync(request);
|
const orderbook = await relayerClient.getOrderbookAsync(request);
|
||||||
expect(orderbook).to.be.deep.equal(orderbookResponse);
|
expect(orderbook).to.be.deep.equal(orderbookResponse);
|
||||||
});
|
});
|
||||||
it('throws an error for invalid JSON response', async () => {
|
it('throws an error for invalid JSON response', async () => {
|
||||||
fetchMock.get(url, {test: 'dummy'});
|
fetchMock.get(url, { test: 'dummy' });
|
||||||
expect(relayerClient.getOrderbookAsync(request)).to.be.rejected();
|
expect(relayerClient.getOrderbookAsync(request)).to.be.rejected();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -137,7 +135,7 @@ describe('HttpClient', () => {
|
|||||||
expect(expirationUnixTimestampSecBefore).to.be.deep.equal(request.expirationUnixTimestampSec);
|
expect(expirationUnixTimestampSecBefore).to.be.deep.equal(request.expirationUnixTimestampSec);
|
||||||
});
|
});
|
||||||
it('throws an error for invalid JSON response', async () => {
|
it('throws an error for invalid JSON response', async () => {
|
||||||
fetchMock.post(url, {test: 'dummy'});
|
fetchMock.post(url, { test: 'dummy' });
|
||||||
expect(relayerClient.getFeesAsync(request)).to.be.rejected();
|
expect(relayerClient.getFeesAsync(request)).to.be.rejected();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -2,16 +2,15 @@ import * as chai from 'chai';
|
|||||||
import * as dirtyChai from 'dirty-chai';
|
import * as dirtyChai from 'dirty-chai';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
|
|
||||||
import {orderbookChannelMessageParsers} from '../src/utils/orderbook_channel_message_parsers';
|
import { orderbookChannelMessageParsers } from '../src/utils/orderbook_channel_message_parsers';
|
||||||
|
|
||||||
// tslint:disable-next-line:max-line-length
|
import { orderResponse } from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f';
|
||||||
import {orderResponse} from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f';
|
import { orderbookResponse } from './fixtures/standard_relayer_api/orderbook';
|
||||||
import {orderbookResponse} from './fixtures/standard_relayer_api/orderbook';
|
|
||||||
import {
|
import {
|
||||||
malformedSnapshotOrderbookChannelMessage,
|
malformedSnapshotOrderbookChannelMessage,
|
||||||
snapshotOrderbookChannelMessage,
|
snapshotOrderbookChannelMessage,
|
||||||
} from './fixtures/standard_relayer_api/snapshot_orderbook_channel_message';
|
} from './fixtures/standard_relayer_api/snapshot_orderbook_channel_message';
|
||||||
import {unknownOrderbookChannelMessage} from './fixtures/standard_relayer_api/unknown_orderbook_channel_message';
|
import { unknownOrderbookChannelMessage } from './fixtures/standard_relayer_api/unknown_orderbook_channel_message';
|
||||||
import {
|
import {
|
||||||
malformedUpdateOrderbookChannelMessage,
|
malformedUpdateOrderbookChannelMessage,
|
||||||
updateOrderbookChannelMessage,
|
updateOrderbookChannelMessage,
|
||||||
@ -58,15 +57,13 @@ describe('orderbookChannelMessageParsers', () => {
|
|||||||
expect(badCall).throws('Expected type to be of type string, encountered: 1');
|
expect(badCall).throws('Expected type to be of type string, encountered: 1');
|
||||||
});
|
});
|
||||||
it('throws when snapshot message has malformed payload', () => {
|
it('throws when snapshot message has malformed payload', () => {
|
||||||
const badCall = () =>
|
const badCall = () => orderbookChannelMessageParsers.parser(malformedSnapshotOrderbookChannelMessage);
|
||||||
orderbookChannelMessageParsers.parser(malformedSnapshotOrderbookChannelMessage);
|
const errMsg =
|
||||||
// tslint:disable-next-line:max-line-length
|
'Validation errors: instance.payload requires property "bids", instance.payload requires property "asks"';
|
||||||
const errMsg = 'Validation errors: instance.payload requires property "bids", instance.payload requires property "asks"';
|
|
||||||
expect(badCall).throws(errMsg);
|
expect(badCall).throws(errMsg);
|
||||||
});
|
});
|
||||||
it('throws when update message has malformed payload', () => {
|
it('throws when update message has malformed payload', () => {
|
||||||
const badCall = () =>
|
const badCall = () => orderbookChannelMessageParsers.parser(malformedUpdateOrderbookChannelMessage);
|
||||||
orderbookChannelMessageParsers.parser(malformedUpdateOrderbookChannelMessage);
|
|
||||||
expect(badCall).throws(/^Expected message to conform to schema/);
|
expect(badCall).throws(/^Expected message to conform to schema/);
|
||||||
});
|
});
|
||||||
it('throws when input message is not valid JSON', () => {
|
it('throws when input message is not valid JSON', () => {
|
||||||
|
@ -3,9 +3,7 @@ import * as dirtyChai from 'dirty-chai';
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
|
|
||||||
import {
|
import { WebSocketOrderbookChannel } from '../src/ws_orderbook_channel';
|
||||||
WebSocketOrderbookChannel,
|
|
||||||
} from '../src/ws_orderbook_channel';
|
|
||||||
|
|
||||||
chai.config.includeStack = true;
|
chai.config.includeStack = true;
|
||||||
chai.use(dirtyChai);
|
chai.use(dirtyChai);
|
||||||
@ -21,26 +19,42 @@ describe('WebSocketOrderbookChannel', () => {
|
|||||||
limit: 100,
|
limit: 100,
|
||||||
};
|
};
|
||||||
const emptyOrderbookChannelHandler = {
|
const emptyOrderbookChannelHandler = {
|
||||||
onSnapshot: () => { _.noop(); },
|
onSnapshot: () => {
|
||||||
onUpdate: () => { _.noop(); },
|
_.noop();
|
||||||
onError: () => { _.noop(); },
|
},
|
||||||
onClose: () => { _.noop(); },
|
onUpdate: () => {
|
||||||
|
_.noop();
|
||||||
|
},
|
||||||
|
onError: () => {
|
||||||
|
_.noop();
|
||||||
|
},
|
||||||
|
onClose: () => {
|
||||||
|
_.noop();
|
||||||
|
},
|
||||||
};
|
};
|
||||||
describe('#subscribe', () => {
|
describe('#subscribe', () => {
|
||||||
it('throws when subscriptionOpts does not conform to schema', () => {
|
it('throws when subscriptionOpts does not conform to schema', () => {
|
||||||
const badSubscribeCall = orderbookChannel.subscribe.bind(
|
const badSubscribeCall = orderbookChannel.subscribe.bind(
|
||||||
orderbookChannel, {}, emptyOrderbookChannelHandler);
|
orderbookChannel,
|
||||||
// tslint:disable-next-line:max-line-length
|
{},
|
||||||
expect(badSubscribeCall).throws('Expected subscriptionOpts to conform to schema /RelayerApiOrderbookChannelSubscribePayload\nEncountered: {}\nValidation errors: instance requires property "baseTokenAddress", instance requires property "quoteTokenAddress"');
|
emptyOrderbookChannelHandler,
|
||||||
|
);
|
||||||
|
expect(badSubscribeCall).throws(
|
||||||
|
'Expected subscriptionOpts to conform to schema /RelayerApiOrderbookChannelSubscribePayload\nEncountered: {}\nValidation errors: instance requires property "baseTokenAddress", instance requires property "quoteTokenAddress"',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('throws when handler has the incorrect members', () => {
|
it('throws when handler has the incorrect members', () => {
|
||||||
const badSubscribeCall = orderbookChannel.subscribe.bind(orderbookChannel, subscriptionOpts, {});
|
const badSubscribeCall = orderbookChannel.subscribe.bind(orderbookChannel, subscriptionOpts, {});
|
||||||
expect(badSubscribeCall)
|
expect(badSubscribeCall).throws(
|
||||||
.throws('Expected handler.onSnapshot to be of type function, encountered: undefined');
|
'Expected handler.onSnapshot to be of type function, encountered: undefined',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('does not throw when inputs are of correct types', () => {
|
it('does not throw when inputs are of correct types', () => {
|
||||||
const goodSubscribeCall = orderbookChannel.subscribe.bind(
|
const goodSubscribeCall = orderbookChannel.subscribe.bind(
|
||||||
orderbookChannel, subscriptionOpts, emptyOrderbookChannelHandler);
|
orderbookChannel,
|
||||||
|
subscriptionOpts,
|
||||||
|
emptyOrderbookChannelHandler,
|
||||||
|
);
|
||||||
expect(goodSubscribeCall).to.not.throw();
|
expect(goodSubscribeCall).to.not.throw();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,23 +1,19 @@
|
|||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import {BigNumber} from 'bignumber.js';
|
import { BigNumber } from 'bignumber.js';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
import * as yargs from 'yargs';
|
import * as yargs from 'yargs';
|
||||||
|
|
||||||
import {commands} from './src/commands';
|
import { commands } from './src/commands';
|
||||||
import {
|
import { CliOptions, CompilerOptions, DeployerOptions } from './src/utils/types';
|
||||||
CliOptions,
|
|
||||||
CompilerOptions,
|
|
||||||
DeployerOptions,
|
|
||||||
} from './src/utils/types';
|
|
||||||
|
|
||||||
const DEFAULT_OPTIMIZER_ENABLED = false;
|
const DEFAULT_OPTIMIZER_ENABLED = false;
|
||||||
const DEFAULT_CONTRACTS_DIR = path.resolve('contracts');
|
const DEFAULT_CONTRACTS_DIR = path.resolve('contracts');
|
||||||
const DEFAULT_ARTIFACTS_DIR = `${path.resolve('build')}/artifacts/`;
|
const DEFAULT_ARTIFACTS_DIR = `${path.resolve('build')}/artifacts/`;
|
||||||
const DEFAULT_NETWORK_ID = 50;
|
const DEFAULT_NETWORK_ID = 50;
|
||||||
const DEFAULT_JSONRPC_PORT = 8545;
|
const DEFAULT_JSONRPC_PORT = 8545;
|
||||||
const DEFAULT_GAS_PRICE = ((10 ** 9) * 2).toString();
|
const DEFAULT_GAS_PRICE = (10 ** 9 * 2).toString();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compiles all contracts with options passed in through CLI.
|
* Compiles all contracts with options passed in through CLI.
|
||||||
@ -108,8 +104,7 @@ function deployCommandBuilder(yargsInstance: any) {
|
|||||||
description: 'comma separated list of constructor args to deploy contract with',
|
description: 'comma separated list of constructor args to deploy contract with',
|
||||||
})
|
})
|
||||||
.demandOption(['contract', 'args'])
|
.demandOption(['contract', 'args'])
|
||||||
.help()
|
.help().argv;
|
||||||
.argv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(() => {
|
(() => {
|
||||||
@ -149,18 +144,13 @@ function deployCommandBuilder(yargsInstance: any) {
|
|||||||
type: 'string',
|
type: 'string',
|
||||||
description: 'account to use for deploying contracts',
|
description: 'account to use for deploying contracts',
|
||||||
})
|
})
|
||||||
.command('compile',
|
.command('compile', 'compile contracts', identityCommandBuilder, onCompileCommand)
|
||||||
'compile contracts',
|
.command(
|
||||||
identityCommandBuilder,
|
'migrate',
|
||||||
onCompileCommand)
|
'compile and deploy contracts using migration scripts',
|
||||||
.command('migrate',
|
identityCommandBuilder,
|
||||||
'compile and deploy contracts using migration scripts',
|
onMigrateCommand,
|
||||||
identityCommandBuilder,
|
)
|
||||||
onMigrateCommand)
|
.command('deploy', 'deploy a single contract with provided arguments', deployCommandBuilder, onDeployCommand)
|
||||||
.command('deploy',
|
.help().argv;
|
||||||
'deploy a single contract with provided arguments',
|
|
||||||
deployCommandBuilder,
|
|
||||||
onDeployCommand)
|
|
||||||
.help()
|
|
||||||
.argv;
|
|
||||||
})();
|
})();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import {constants} from './../../src/utils/constants';
|
import { constants } from './../../src/utils/constants';
|
||||||
import {Token} from './../../src/utils/types';
|
import { Token } from './../../src/utils/types';
|
||||||
|
|
||||||
export const tokenInfo: Token[] = [
|
export const tokenInfo: Token[] = [
|
||||||
{
|
{
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import {BigNumber} from 'bignumber.js';
|
import { BigNumber } from 'bignumber.js';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import {Deployer} from './../src/deployer';
|
import { Deployer } from './../src/deployer';
|
||||||
import {constants} from './../src/utils/constants';
|
import { constants } from './../src/utils/constants';
|
||||||
import {tokenInfo} from './config/token_info';
|
import { tokenInfo } from './config/token_info';
|
||||||
|
|
||||||
export const migrator = {
|
export const migrator = {
|
||||||
/**
|
/**
|
||||||
@ -29,12 +29,13 @@ export const migrator = {
|
|||||||
const multiSigArgs = [owners, confirmationsRequired, secondsRequired, tokenTransferProxy.address];
|
const multiSigArgs = [owners, confirmationsRequired, secondsRequired, tokenTransferProxy.address];
|
||||||
const exchange = await deployer.deployAndSaveAsync('Exchange', exchangeArgs);
|
const exchange = await deployer.deployAndSaveAsync('Exchange', exchangeArgs);
|
||||||
const multiSig = await deployer.deployAndSaveAsync(
|
const multiSig = await deployer.deployAndSaveAsync(
|
||||||
'MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', multiSigArgs,
|
'MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress',
|
||||||
|
multiSigArgs,
|
||||||
);
|
);
|
||||||
|
|
||||||
const owner = accounts[0];
|
const owner = accounts[0];
|
||||||
await tokenTransferProxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {from: owner});
|
await tokenTransferProxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: owner });
|
||||||
await tokenTransferProxy.transferOwnership.sendTransactionAsync(multiSig.address, {from: owner});
|
await tokenTransferProxy.transferOwnership.sendTransactionAsync(multiSig.address, { from: owner });
|
||||||
const addTokenGasEstimate = await tokenReg.addToken.estimateGasAsync(
|
const addTokenGasEstimate = await tokenReg.addToken.estimateGasAsync(
|
||||||
zrxToken.address,
|
zrxToken.address,
|
||||||
tokenInfo[0].name,
|
tokenInfo[0].name,
|
||||||
@ -42,7 +43,7 @@ export const migrator = {
|
|||||||
tokenInfo[0].decimals,
|
tokenInfo[0].decimals,
|
||||||
tokenInfo[0].ipfsHash,
|
tokenInfo[0].ipfsHash,
|
||||||
tokenInfo[0].swarmHash,
|
tokenInfo[0].swarmHash,
|
||||||
{from: owner},
|
{ from: owner },
|
||||||
);
|
);
|
||||||
await tokenReg.addToken.sendTransactionAsync(
|
await tokenReg.addToken.sendTransactionAsync(
|
||||||
zrxToken.address,
|
zrxToken.address,
|
||||||
@ -70,12 +71,7 @@ export const migrator = {
|
|||||||
);
|
);
|
||||||
for (const token of tokenInfo) {
|
for (const token of tokenInfo) {
|
||||||
const totalSupply = new BigNumber(0);
|
const totalSupply = new BigNumber(0);
|
||||||
const args = [
|
const args = [token.name, token.symbol, token.decimals, totalSupply];
|
||||||
token.name,
|
|
||||||
token.symbol,
|
|
||||||
token.decimals,
|
|
||||||
totalSupply,
|
|
||||||
];
|
|
||||||
const dummyToken = await deployer.deployAsync('DummyToken', args);
|
const dummyToken = await deployer.deployAsync('DummyToken', args);
|
||||||
await tokenReg.addToken.sendTransactionAsync(
|
await tokenReg.addToken.sendTransactionAsync(
|
||||||
dummyToken.address,
|
dummyToken.address,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import {migrator} from './../migrations/migrate';
|
import { migrator } from './../migrations/migrate';
|
||||||
import {Compiler} from './compiler';
|
import { Compiler } from './compiler';
|
||||||
import {Deployer} from './deployer';
|
import { Deployer } from './deployer';
|
||||||
import {CompilerOptions, DeployerOptions} from './utils/types';
|
import { CompilerOptions, DeployerOptions } from './utils/types';
|
||||||
|
|
||||||
export const commands = {
|
export const commands = {
|
||||||
async compileAsync(opts: CompilerOptions): Promise<void> {
|
async compileAsync(opts: CompilerOptions): Promise<void> {
|
||||||
|
@ -4,8 +4,8 @@ import * as path from 'path';
|
|||||||
import solc = require('solc');
|
import solc = require('solc');
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import {binPaths} from './../solc/bin_paths';
|
import { binPaths } from './../solc/bin_paths';
|
||||||
import {fsWrapper} from './utils/fs_wrapper';
|
import { fsWrapper } from './utils/fs_wrapper';
|
||||||
import {
|
import {
|
||||||
CompilerOptions,
|
CompilerOptions,
|
||||||
ContractArtifact,
|
ContractArtifact,
|
||||||
@ -14,7 +14,7 @@ import {
|
|||||||
ContractSources,
|
ContractSources,
|
||||||
ImportContents,
|
ImportContents,
|
||||||
} from './utils/types';
|
} from './utils/types';
|
||||||
import {utils} from './utils/utils';
|
import { utils } from './utils/utils';
|
||||||
|
|
||||||
const SOLIDITY_FILE_EXTENSION = '.sol';
|
const SOLIDITY_FILE_EXTENSION = '.sol';
|
||||||
|
|
||||||
@ -150,9 +150,10 @@ export class Compiler {
|
|||||||
currentArtifact = JSON.parse(currentArtifactString);
|
currentArtifact = JSON.parse(currentArtifactString);
|
||||||
oldNetworks = currentArtifact.networks;
|
oldNetworks = currentArtifact.networks;
|
||||||
const oldNetwork: ContractData = oldNetworks[this._networkId];
|
const oldNetwork: ContractData = oldNetworks[this._networkId];
|
||||||
shouldCompile = _.isUndefined(oldNetwork) ||
|
shouldCompile =
|
||||||
oldNetwork.keccak256 !== sourceHash ||
|
_.isUndefined(oldNetwork) ||
|
||||||
oldNetwork.optimizer_enabled !== this._optimizerEnabled;
|
oldNetwork.keccak256 !== sourceHash ||
|
||||||
|
oldNetwork.optimizer_enabled !== this._optimizerEnabled;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
shouldCompile = true;
|
shouldCompile = true;
|
||||||
}
|
}
|
||||||
@ -174,9 +175,11 @@ export class Compiler {
|
|||||||
const sourcesToCompile = {
|
const sourcesToCompile = {
|
||||||
sources: input,
|
sources: input,
|
||||||
};
|
};
|
||||||
const compiled = solcInstance.compile(sourcesToCompile,
|
const compiled = solcInstance.compile(
|
||||||
this._optimizerEnabled,
|
sourcesToCompile,
|
||||||
this._findImportsIfSourcesExist.bind(this));
|
this._optimizerEnabled,
|
||||||
|
this._findImportsIfSourcesExist.bind(this),
|
||||||
|
);
|
||||||
|
|
||||||
if (!_.isUndefined(compiled.errors)) {
|
if (!_.isUndefined(compiled.errors)) {
|
||||||
_.each(compiled.errors, errMsg => {
|
_.each(compiled.errors, errMsg => {
|
||||||
|
@ -1,17 +1,13 @@
|
|||||||
import {TxData} from '@0xproject/types';
|
import { TxData } from '@0xproject/types';
|
||||||
import {Web3Wrapper} from '@0xproject/web3-wrapper';
|
import { Web3Wrapper } from '@0xproject/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import {Contract} from './utils/contract';
|
import { Contract } from './utils/contract';
|
||||||
import {encoder} from './utils/encoder';
|
import { encoder } from './utils/encoder';
|
||||||
import {fsWrapper} from './utils/fs_wrapper';
|
import { fsWrapper } from './utils/fs_wrapper';
|
||||||
import {
|
import { ContractArtifact, ContractData, DeployerOptions } from './utils/types';
|
||||||
ContractArtifact,
|
import { utils } from './utils/utils';
|
||||||
ContractData,
|
|
||||||
DeployerOptions,
|
|
||||||
} from './utils/types';
|
|
||||||
import {utils} from './utils/utils';
|
|
||||||
|
|
||||||
// Gas added to gas estimate to make sure there is sufficient gas for deployment.
|
// Gas added to gas estimate to make sure there is sufficient gas for deployment.
|
||||||
const EXTRA_GAS = 200000;
|
const EXTRA_GAS = 200000;
|
||||||
@ -99,8 +95,11 @@ export class Deployer {
|
|||||||
* @param contractAddress Contract address to save to artifact.
|
* @param contractAddress Contract address to save to artifact.
|
||||||
* @param args Contract constructor arguments that will be encoded and saved to artifact.
|
* @param args Contract constructor arguments that will be encoded and saved to artifact.
|
||||||
*/
|
*/
|
||||||
private async _saveContractDataToArtifactAsync(contractName: string,
|
private async _saveContractDataToArtifactAsync(
|
||||||
contractAddress: string, args: any[]): Promise<void> {
|
contractName: string,
|
||||||
|
contractAddress: string,
|
||||||
|
args: any[],
|
||||||
|
): Promise<void> {
|
||||||
const contractArtifact: ContractArtifact = this._loadContractArtifactIfExists(contractName);
|
const contractArtifact: ContractArtifact = this._loadContractArtifactIfExists(contractName);
|
||||||
const contractData: ContractData = this._getContractDataFromArtifactIfExists(contractArtifact);
|
const contractData: ContractData = this._getContractDataFromArtifactIfExists(contractArtifact);
|
||||||
const abi = contractData.abi;
|
const abi = contractData.abi;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import {schemas, SchemaValidator} from '@0xproject/json-schemas';
|
import { schemas, SchemaValidator } from '@0xproject/json-schemas';
|
||||||
import {promisify} from '@0xproject/utils';
|
import { promisify } from '@0xproject/utils';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
|
|
||||||
import {AbiType} from './types';
|
import { AbiType } from './types';
|
||||||
|
|
||||||
export class Contract implements Web3.ContractInstance {
|
export class Contract implements Web3.ContractInstance {
|
||||||
public address: string;
|
public address: string;
|
||||||
|
@ -2,7 +2,7 @@ import * as _ from 'lodash';
|
|||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
import * as web3Abi from 'web3-eth-abi';
|
import * as web3Abi from 'web3-eth-abi';
|
||||||
|
|
||||||
import {AbiType} from './types';
|
import { AbiType } from './types';
|
||||||
|
|
||||||
export const encoder = {
|
export const encoder = {
|
||||||
encodeConstructorArgsFromAbi(args: any[], abi: Web3.ContractAbi): string {
|
encodeConstructorArgsFromAbi(args: any[], abi: Web3.ContractAbi): string {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {promisify} from '@0xproject/utils';
|
import { promisify } from '@0xproject/utils';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
|
||||||
export const fsWrapper = {
|
export const fsWrapper = {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {TxData} from '@0xproject/types';
|
import { TxData } from '@0xproject/types';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
import * as yargs from 'yargs';
|
import * as yargs from 'yargs';
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
|
|
||||||
import {Compiler} from './../src/compiler';
|
import { Compiler } from './../src/compiler';
|
||||||
import {Deployer} from './../src/deployer';
|
import { Deployer } from './../src/deployer';
|
||||||
import {fsWrapper} from './../src/utils/fs_wrapper';
|
import { fsWrapper } from './../src/utils/fs_wrapper';
|
||||||
import {CompilerOptions, ContractArtifact, ContractData, DoneCallback} from './../src/utils/types';
|
import { CompilerOptions, ContractArtifact, ContractData, DoneCallback } from './../src/utils/types';
|
||||||
import {constructor_args, exchange_binary} from './fixtures/exchange_bin';
|
import { constructor_args, exchange_binary } from './fixtures/exchange_bin';
|
||||||
import {constants} from './util/constants';
|
import { constants } from './util/constants';
|
||||||
|
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
const artifactsDir = `${__dirname}/fixtures/artifacts`;
|
const artifactsDir = `${__dirname}/fixtures/artifacts`;
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1,4 +1,4 @@
|
|||||||
import {BigNumber} from 'bignumber.js';
|
import { BigNumber } from 'bignumber.js';
|
||||||
|
|
||||||
export const constants = {
|
export const constants = {
|
||||||
networkId: 0,
|
networkId: 0,
|
||||||
|
4
packages/contracts/globalsAugment.d.ts
vendored
4
packages/contracts/globalsAugment.d.ts
vendored
@ -1,4 +1,4 @@
|
|||||||
import {BigNumber} from 'bignumber.js';
|
import { BigNumber } from 'bignumber.js';
|
||||||
|
|
||||||
// HACK: This module overrides the Chai namespace so that we can use BigNumber types inside.
|
// 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
|
// Source: https://github.com/Microsoft/TypeScript/issues/7352#issuecomment-191547232
|
||||||
@ -16,4 +16,4 @@ declare global {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* tslint:enable */
|
/* tslint:enable */
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user