Merge branch 'development' into feature/orderExpired
This commit is contained in:
commit
d39c0bee39
35
README.md
35
README.md
@ -6,33 +6,22 @@
|
|||||||
|
|
||||||
This repository contains all the 0x developer tools written in TypeScript. Our hope is that these tools make it easy to build Relayers and other DApps that use the 0x protocol.
|
This repository contains all the 0x developer tools written in TypeScript. Our hope is that these tools make it easy to build Relayers and other DApps that use the 0x protocol.
|
||||||
|
|
||||||
|
[website-url]: https://0xproject.com/
|
||||||
|
[whitepaper-url]: https://0xproject.com/pdfs/0x_white_paper.pdf
|
||||||
|
|
||||||
[](https://circleci.com/gh/0xProject/0x.js)
|
[](https://circleci.com/gh/0xProject/0x.js)
|
||||||
[](https://badge.fury.io/js/0x.js)
|
|
||||||
[](https://coveralls.io/github/0xProject/0x.js?branch=master)
|
[](https://coveralls.io/github/0xProject/0x.js?branch=master)
|
||||||
[](http://slack.0xProject.com)
|
[](https://chat.0xproject.com)
|
||||||
[](https://gitter.im/0xProject/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[](https://gitter.im/0xProject/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
[](https://opensource.org/licenses/Apache-2.0)
|
[](https://opensource.org/licenses/Apache-2.0)
|
||||||
[](https://greenkeeper.io/)
|
[](https://greenkeeper.io/)
|
||||||
|
|
||||||
Instructions
|
### Core Packages
|
||||||
------------
|
|
||||||
|
|
||||||
Make sure you have `yarn@1.x` installed locally.
|
| Package | Version | Description |
|
||||||
|
|--------|-------|------------|
|
||||||
### Creating a new sub-package
|
| [`0x.js`](/packages/0x.js) | [](https://www.npmjs.com/package/0x.js) | A Javascript library for interacting with the 0x protocol |
|
||||||
|
| [`@0xproject/assert`](/packages/assert) | [](https://www.npmjs.com/package/@0xproject/assert) | Standard type and schema assertions |
|
||||||
1. Make sure the `name` field in the sub-package's `package.json` starts with `@0xproject/` and has a unique name (e.g `@0xproject/assert`).
|
| [`@0xproject/json-schemas`](/packages/json-schemas) | [](https://www.npmjs.com/package/@0xproject/json-schemas) | 0x-related json schemas |
|
||||||
|
| [`@0xproject/tslint-config`](/packages/tslint-config) | [](https://www.npmjs.com/package/@0xproject/tslint-config) | Custom 0x project TSLint rules |
|
||||||
2. Run `yarn install` to install all it's dependencies.
|
|
||||||
|
|
||||||
### How to add a sub-package as a dependency to another sub-package:
|
|
||||||
|
|
||||||
1. Add the sub-packages name (declared in it's `package.json`) to your sub-packages `package.json` under `dependencies` or `devDependencies`.
|
|
||||||
|
|
||||||
2. Run `yarn install` from anywhere in the mono repo.
|
|
||||||
|
|
||||||
3. Import the sub-package as:
|
|
||||||
|
|
||||||
```
|
|
||||||
import {myPkg} from '@0xproject/myPkg';
|
|
||||||
```
|
|
||||||
|
@ -6,12 +6,17 @@
|
|||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"testrpc": "testrpc -p 8545 --networkId 50 -m \"${npm_package_config_mnemonic}\"",
|
"testrpc": "testrpc -p 8545 --networkId 50 -m \"${npm_package_config_mnemonic}\"",
|
||||||
"lerna:run": "lerna run"
|
"lerna:run": "lerna run",
|
||||||
|
"lerna:publish": "lerna run clean; lerna run build; lerna publish"
|
||||||
},
|
},
|
||||||
"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"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"lerna": "^2.5.1"
|
"lerna": "^2.5.1",
|
||||||
|
"async-child-process": "^1.1.1",
|
||||||
|
"semver-sort": "^0.0.4",
|
||||||
|
"publish-release": "0xproject/publish-release",
|
||||||
|
"es6-promisify": "^5.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,15 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
v0.24.0 - _November 13, 2017_
|
vx.x.x
|
||||||
|
------------------------
|
||||||
|
* Remove support for Async callback types when used in Subscribe functions
|
||||||
|
* In OrderWatcher subscribe to ZRX Token Transfer and Approval events when maker token is different (#225)
|
||||||
|
|
||||||
|
v0.25.1 - _November 13, 2017_
|
||||||
------------------------
|
------------------------
|
||||||
* Standardise on Cancelled over Canceled
|
* Standardise on Cancelled over Canceled
|
||||||
|
* Add missing `DecodedLogEvent` type to exported types
|
||||||
|
* Normalized the transactionReceipt status to be `null|0|1`, 1 meaning transaction execution successful, 0 unsuccessful and `null` if it is a pre-byzantinium transaction.
|
||||||
|
|
||||||
v0.23.0 - _November 12, 2017_
|
v0.23.0 - _November 12, 2017_
|
||||||
------------------------
|
------------------------
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
0x.js
|
||||||
|
-----
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
0x.js ships as both a [UMD](https://github.com/umdjs/umd) module and a [CommonJS](https://en.wikipedia.org/wiki/CommonJS) package.
|
0x.js ships as both a [UMD](https://github.com/umdjs/umd) module and a [CommonJS](https://en.wikipedia.org/wiki/CommonJS) package.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "0x.js",
|
"name": "0x.js",
|
||||||
"version": "0.23.0",
|
"version": "0.25.1",
|
||||||
"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",
|
||||||
@ -13,11 +13,9 @@
|
|||||||
"types": "lib/src/index.d.ts",
|
"types": "lib/src/index.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prebuild": "npm run clean",
|
"prebuild": "npm run clean",
|
||||||
"build": "run-p build:umd:prod build:commonjs",
|
"build": "run-p build:umd:prod build:commonjs; exit 0;",
|
||||||
"prepublishOnly": "run-p build",
|
"docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_DIR",
|
||||||
"postpublish": "run-s release docs:json upload_docs_json",
|
"upload_docs_json": "aws s3 cp docs/index.json $S3_URL --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type aplication/json",
|
||||||
"release": "publish-release --assets _bundles/index.js,_bundles/index.min.js --tag $(git describe --tags) --owner 0xProject --repo 0x.js",
|
|
||||||
"upload_docs_json": "aws s3 cp docs/index.json s3://0xjs-docs-jsons/$(git describe --tags).json --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type aplication/json",
|
|
||||||
"lint": "tslint src/**/*.ts test/**/*.ts",
|
"lint": "tslint src/**/*.ts test/**/*.ts",
|
||||||
"test:circleci": "run-s test:coverage report_test_coverage; if [ $CIRCLE_BRANCH = \"development\" ]; then yarn test:umd; fi",
|
"test:circleci": "run-s test:coverage report_test_coverage; if [ $CIRCLE_BRANCH = \"development\" ]; then yarn test:umd; fi",
|
||||||
"test": "run-s clean test:commonjs",
|
"test": "run-s clean test:commonjs",
|
||||||
@ -25,9 +23,6 @@
|
|||||||
"test:coverage": "nyc npm run test --all",
|
"test:coverage": "nyc npm run test --all",
|
||||||
"report_test_coverage": "nyc report --reporter=text-lcov | coveralls",
|
"report_test_coverage": "nyc report --reporter=text-lcov | coveralls",
|
||||||
"update_contracts": "for i in ${npm_package_config_artifacts}; do copyfiles -u 4 ../contracts/build/contracts/$i.json ../0x.js/src/artifacts; done;",
|
"update_contracts": "for i in ${npm_package_config_artifacts}; do copyfiles -u 4 ../contracts/build/contracts/$i.json ../0x.js/src/artifacts; done;",
|
||||||
"docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json docs/index.json .",
|
|
||||||
"docs:generate": "typedoc --out docs .",
|
|
||||||
"docs:open": "opn docs/index.html",
|
|
||||||
"clean": "shx rm -rf _bundles lib test_temp",
|
"clean": "shx rm -rf _bundles lib test_temp",
|
||||||
"build:umd:dev": "webpack",
|
"build:umd:dev": "webpack",
|
||||||
"build:umd:prod": "NODE_ENV=production webpack",
|
"build:umd:prod": "NODE_ENV=production webpack",
|
||||||
@ -49,6 +44,7 @@
|
|||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@0xproject/tslint-config": "^0.1.0",
|
||||||
"@types/bintrees": "^1.0.2",
|
"@types/bintrees": "^1.0.2",
|
||||||
"@types/jsonschema": "^1.1.1",
|
"@types/jsonschema": "^1.1.1",
|
||||||
"@types/lodash": "^4.14.64",
|
"@types/lodash": "^4.14.64",
|
||||||
@ -77,8 +73,7 @@
|
|||||||
"sinon": "^4.0.0",
|
"sinon": "^4.0.0",
|
||||||
"source-map-support": "^0.5.0",
|
"source-map-support": "^0.5.0",
|
||||||
"truffle-hdwallet-provider": "^0.0.3",
|
"truffle-hdwallet-provider": "^0.0.3",
|
||||||
"tslint": "~5.5.0",
|
"tslint": "5.8.0",
|
||||||
"tslint-config-0xproject": "^0.0.2",
|
|
||||||
"typedoc": "~0.8.0",
|
"typedoc": "~0.8.0",
|
||||||
"types-bn": "^0.0.1",
|
"types-bn": "^0.0.1",
|
||||||
"types-ethereumjs-util": "0xProject/types-ethereumjs-util",
|
"types-ethereumjs-util": "0xProject/types-ethereumjs-util",
|
||||||
@ -88,10 +83,11 @@
|
|||||||
"webpack": "^3.1.0"
|
"webpack": "^3.1.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"0x-json-schemas": "^0.6.1",
|
"@0xproject/assert": "^0.0.4",
|
||||||
"@0xproject/assert": "0.0.3",
|
"@0xproject/json-schemas": "^0.6.7",
|
||||||
"bignumber.js": "~4.1.0",
|
"bignumber.js": "~4.1.0",
|
||||||
"bintrees": "^1.0.2",
|
"bintrees": "^1.0.2",
|
||||||
|
"bn.js": "4.11.8",
|
||||||
"compare-versions": "^3.0.1",
|
"compare-versions": "^3.0.1",
|
||||||
"es6-promisify": "^5.0.0",
|
"es6-promisify": "^5.0.0",
|
||||||
"ethereumjs-abi": "^0.6.4",
|
"ethereumjs-abi": "^0.6.4",
|
||||||
@ -100,7 +96,6 @@
|
|||||||
"find-versions": "^2.0.0",
|
"find-versions": "^2.0.0",
|
||||||
"js-sha3": "^0.6.1",
|
"js-sha3": "^0.6.1",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"publish-release": "^1.3.3",
|
|
||||||
"uuid": "^3.1.0",
|
"uuid": "^3.1.0",
|
||||||
"web3": "^0.20.0"
|
"web3": "^0.20.0"
|
||||||
}
|
}
|
||||||
|
43
packages/0x.js/scripts/postpublish.js
Normal file
43
packages/0x.js/scripts/postpublish.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
const execAsync = require('async-child-process').execAsync;
|
||||||
|
const postpublish_utils = require('../../../scripts/postpublish_utils');
|
||||||
|
const packageJSON = require('../package.json');
|
||||||
|
|
||||||
|
const cwd = __dirname + '/..';
|
||||||
|
const subPackageName = packageJSON.name;
|
||||||
|
const S3BucketPath = 's3://0xjs-docs-jsons/';
|
||||||
|
|
||||||
|
let tag;
|
||||||
|
let version;
|
||||||
|
postpublish_utils.getLatestTagAndVersionAsync(subPackageName)
|
||||||
|
.then(function(result) {
|
||||||
|
tag = result.tag;
|
||||||
|
version = result.version;
|
||||||
|
const releaseName = postpublish_utils.getReleaseName(subPackageName, version);
|
||||||
|
const assets = [
|
||||||
|
__dirname + '/../_bundles/index.js',
|
||||||
|
__dirname + '/../_bundles/index.min.js',
|
||||||
|
];
|
||||||
|
return postpublish_utils.publishReleaseNotes(tag, releaseName, assets);
|
||||||
|
})
|
||||||
|
.then(function(release) {
|
||||||
|
console.log('POSTPUBLISH: Release successful, generating docs...');
|
||||||
|
return execAsync(
|
||||||
|
'JSON_FILE_PATH=' + __dirname + '/../docs/index.json PROJECT_DIR=' + __dirname + '/.. yarn docs:json',
|
||||||
|
{
|
||||||
|
cwd,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.then(function(result) {
|
||||||
|
if (result.stderr !== '') {
|
||||||
|
throw new Error(result.stderr);
|
||||||
|
}
|
||||||
|
const fileName = 'v' + version + '.json';
|
||||||
|
console.log('POSTPUBLISH: Doc generation successful, uploading docs... as ', fileName);
|
||||||
|
const s3Url = S3BucketPath + fileName;
|
||||||
|
return execAsync('S3_URL=' + s3Url + ' yarn upload_docs_json', {
|
||||||
|
cwd,
|
||||||
|
});
|
||||||
|
}).catch (function(err) {
|
||||||
|
throw err;
|
||||||
|
});
|
@ -3,5 +3,4 @@
|
|||||||
# UMD tests should only be run after building the commonjs because they reuse some of the commonjs build artifacts
|
# UMD tests should only be run after building the commonjs because they reuse some of the commonjs build artifacts
|
||||||
run-s substitute_umd_bundle run_mocha
|
run-s substitute_umd_bundle run_mocha
|
||||||
return_code=$?
|
return_code=$?
|
||||||
npm run clean
|
|
||||||
exit $return_code
|
exit $return_code
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import {SchemaValidator, schemas} from '0x-json-schemas';
|
import {SchemaValidator, schemas} from '@0xproject/json-schemas';
|
||||||
import {bigNumberConfigs} from './bignumber_config';
|
import {bigNumberConfigs} from './bignumber_config';
|
||||||
import * as ethUtil from 'ethereumjs-util';
|
import * as ethUtil from 'ethereumjs-util';
|
||||||
import {Web3Wrapper} from './web3_wrapper';
|
import {Web3Wrapper} from './web3_wrapper';
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import promisify = require('es6-promisify');
|
import promisify = require('es6-promisify');
|
||||||
import {SchemaValidator, schemas} from '0x-json-schemas';
|
import {SchemaValidator, schemas} from '@0xproject/json-schemas';
|
||||||
import {AbiType} from './types';
|
import {AbiType} from './types';
|
||||||
|
|
||||||
export class Contract implements Web3.ContractInstance {
|
export class Contract implements Web3.ContractInstance {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import {schemas} from '0x-json-schemas';
|
import {schemas} from '@0xproject/json-schemas';
|
||||||
import {Web3Wrapper} from '../web3_wrapper';
|
import {Web3Wrapper} from '../web3_wrapper';
|
||||||
import {
|
import {
|
||||||
ECSignature,
|
ECSignature,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import {schemas} from '0x-json-schemas';
|
import {schemas} from '@0xproject/json-schemas';
|
||||||
import {Web3Wrapper} from '../web3_wrapper';
|
import {Web3Wrapper} from '../web3_wrapper';
|
||||||
import {assert} from '../utils/assert';
|
import {assert} from '../utils/assert';
|
||||||
import {constants} from '../utils/constants';
|
import {constants} from '../utils/constants';
|
||||||
|
@ -6,8 +6,6 @@ export {
|
|||||||
ECSignature,
|
ECSignature,
|
||||||
ZeroExError,
|
ZeroExError,
|
||||||
EventCallback,
|
EventCallback,
|
||||||
EventCallbackAsync,
|
|
||||||
EventCallbackSync,
|
|
||||||
ExchangeContractErrs,
|
ExchangeContractErrs,
|
||||||
ContractEvent,
|
ContractEvent,
|
||||||
Token,
|
Token,
|
||||||
|
@ -81,7 +81,7 @@ export class EventWatcher {
|
|||||||
...log,
|
...log,
|
||||||
};
|
};
|
||||||
if (!_.isUndefined(this._intervalIdIfExists)) {
|
if (!_.isUndefined(this._intervalIdIfExists)) {
|
||||||
await callback(logEvent);
|
callback(logEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import {schemas} from '0x-json-schemas';
|
import {schemas} from '@0xproject/json-schemas';
|
||||||
import {ZeroEx} from '../0x';
|
import {ZeroEx} from '../0x';
|
||||||
import {EventWatcher} from './event_watcher';
|
import {EventWatcher} from './event_watcher';
|
||||||
import {assert} from '../utils/assert';
|
import {assert} from '../utils/assert';
|
||||||
@ -53,7 +53,7 @@ interface OrderByOrderHash {
|
|||||||
export class OrderStateWatcher {
|
export class OrderStateWatcher {
|
||||||
private _orderByOrderHash: OrderByOrderHash = {};
|
private _orderByOrderHash: OrderByOrderHash = {};
|
||||||
private _dependentOrderHashes: DependentOrderHashes = {};
|
private _dependentOrderHashes: DependentOrderHashes = {};
|
||||||
private _callbackIfExistsAsync?: OnOrderStateChangeCallback;
|
private _callbackIfExists?: OnOrderStateChangeCallback;
|
||||||
private _eventWatcher: EventWatcher;
|
private _eventWatcher: EventWatcher;
|
||||||
private _web3Wrapper: Web3Wrapper;
|
private _web3Wrapper: Web3Wrapper;
|
||||||
private _abiDecoder: AbiDecoder;
|
private _abiDecoder: AbiDecoder;
|
||||||
@ -89,12 +89,12 @@ export class OrderStateWatcher {
|
|||||||
* signature is verified.
|
* signature is verified.
|
||||||
* @param signedOrder The order you wish to start watching.
|
* @param signedOrder The order you wish to start watching.
|
||||||
*/
|
*/
|
||||||
public addOrder(signedOrder: SignedOrder): void {
|
public async addOrderAsync(signedOrder: SignedOrder): Promise<void> {
|
||||||
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
assert.isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker);
|
assert.isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker);
|
||||||
this._orderByOrderHash[orderHash] = signedOrder;
|
this._orderByOrderHash[orderHash] = signedOrder;
|
||||||
this.addToDependentOrderHashes(signedOrder, orderHash);
|
await this.addToDependentOrderHashesAsync(signedOrder, orderHash);
|
||||||
const expirationUnixTimestampMs = signedOrder.expirationUnixTimestampSec.times(1000);
|
const expirationUnixTimestampMs = signedOrder.expirationUnixTimestampSec.times(1000);
|
||||||
this._expirationWatcher.addOrder(orderHash, expirationUnixTimestampMs);
|
this._expirationWatcher.addOrder(orderHash, expirationUnixTimestampMs);
|
||||||
}
|
}
|
||||||
@ -102,13 +102,16 @@ export class OrderStateWatcher {
|
|||||||
* Removes an order from the orderStateWatcher
|
* Removes an order from the orderStateWatcher
|
||||||
* @param orderHash The orderHash of the order you wish to stop watching.
|
* @param orderHash The orderHash of the order you wish to stop watching.
|
||||||
*/
|
*/
|
||||||
public removeOrder(orderHash: string): void {
|
public async removeOrderAsync(orderHash: string): Promise<void> {
|
||||||
assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
|
assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
|
||||||
const signedOrder = this._orderByOrderHash[orderHash];
|
const signedOrder = this._orderByOrderHash[orderHash];
|
||||||
if (_.isUndefined(signedOrder)) {
|
if (_.isUndefined(signedOrder)) {
|
||||||
return; // noop
|
return; // noop
|
||||||
}
|
}
|
||||||
delete this._orderByOrderHash[orderHash];
|
delete this._orderByOrderHash[orderHash];
|
||||||
|
const exchange = (this._orderFilledCancelledLazyStore as any).exchange as ExchangeWrapper;
|
||||||
|
const zrxTokenAddress = await exchange.getZRXTokenAddressAsync();
|
||||||
|
this.removeFromDependentOrderHashes(signedOrder.maker, zrxTokenAddress, orderHash);
|
||||||
this.removeFromDependentOrderHashes(signedOrder.maker, signedOrder.makerTokenAddress, orderHash);
|
this.removeFromDependentOrderHashes(signedOrder.maker, signedOrder.makerTokenAddress, orderHash);
|
||||||
this._expirationWatcher.removeOrder(orderHash);
|
this._expirationWatcher.removeOrder(orderHash);
|
||||||
}
|
}
|
||||||
@ -120,10 +123,10 @@ export class OrderStateWatcher {
|
|||||||
*/
|
*/
|
||||||
public subscribe(callback: OnOrderStateChangeCallback): void {
|
public subscribe(callback: OnOrderStateChangeCallback): void {
|
||||||
assert.isFunction('callback', callback);
|
assert.isFunction('callback', callback);
|
||||||
if (!_.isUndefined(this._callbackIfExistsAsync)) {
|
if (!_.isUndefined(this._callbackIfExists)) {
|
||||||
throw new Error(ZeroExError.SubscriptionAlreadyPresent);
|
throw new Error(ZeroExError.SubscriptionAlreadyPresent);
|
||||||
}
|
}
|
||||||
this._callbackIfExistsAsync = callback;
|
this._callbackIfExists = callback;
|
||||||
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));
|
||||||
}
|
}
|
||||||
@ -131,12 +134,12 @@ export class OrderStateWatcher {
|
|||||||
* Ends an orderStateWatcher subscription.
|
* Ends an orderStateWatcher subscription.
|
||||||
*/
|
*/
|
||||||
public unsubscribe(): void {
|
public unsubscribe(): void {
|
||||||
if (_.isUndefined(this._callbackIfExistsAsync)) {
|
if (_.isUndefined(this._callbackIfExists)) {
|
||||||
throw new Error(ZeroExError.SubscriptionNotFound);
|
throw new Error(ZeroExError.SubscriptionNotFound);
|
||||||
}
|
}
|
||||||
this._balanceAndProxyAllowanceLazyStore.deleteAll();
|
this._balanceAndProxyAllowanceLazyStore.deleteAll();
|
||||||
this._orderFilledCancelledLazyStore.deleteAll();
|
this._orderFilledCancelledLazyStore.deleteAll();
|
||||||
delete this._callbackIfExistsAsync;
|
delete this._callbackIfExists;
|
||||||
this._eventWatcher.unsubscribe();
|
this._eventWatcher.unsubscribe();
|
||||||
this._expirationWatcher.unsubscribe();
|
this._expirationWatcher.unsubscribe();
|
||||||
}
|
}
|
||||||
@ -232,13 +235,13 @@ export class OrderStateWatcher {
|
|||||||
// Most of these calls will never reach the network because the data is fetched from stores
|
// Most of these calls will never reach the network because the data is fetched from stores
|
||||||
// and only updated when cache is invalidated
|
// and only updated when cache is invalidated
|
||||||
const orderState = await this._orderStateUtils.getOrderStateAsync(signedOrder);
|
const orderState = await this._orderStateUtils.getOrderStateAsync(signedOrder);
|
||||||
if (_.isUndefined(this._callbackIfExistsAsync)) {
|
if (_.isUndefined(this._callbackIfExists)) {
|
||||||
break; // Unsubscribe was called
|
break; // Unsubscribe was called
|
||||||
}
|
}
|
||||||
await this._callbackIfExistsAsync(orderState);
|
this._callbackIfExists(orderState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private addToDependentOrderHashes(signedOrder: SignedOrder, orderHash: string) {
|
private async addToDependentOrderHashesAsync(signedOrder: SignedOrder, orderHash: string): Promise<void> {
|
||||||
if (_.isUndefined(this._dependentOrderHashes[signedOrder.maker])) {
|
if (_.isUndefined(this._dependentOrderHashes[signedOrder.maker])) {
|
||||||
this._dependentOrderHashes[signedOrder.maker] = {};
|
this._dependentOrderHashes[signedOrder.maker] = {};
|
||||||
}
|
}
|
||||||
@ -246,11 +249,17 @@ export class OrderStateWatcher {
|
|||||||
this._dependentOrderHashes[signedOrder.maker][signedOrder.makerTokenAddress] = new Set();
|
this._dependentOrderHashes[signedOrder.maker][signedOrder.makerTokenAddress] = new Set();
|
||||||
}
|
}
|
||||||
this._dependentOrderHashes[signedOrder.maker][signedOrder.makerTokenAddress].add(orderHash);
|
this._dependentOrderHashes[signedOrder.maker][signedOrder.makerTokenAddress].add(orderHash);
|
||||||
|
const exchange = (this._orderFilledCancelledLazyStore as any).exchange as ExchangeWrapper;
|
||||||
|
const zrxTokenAddress = await exchange.getZRXTokenAddressAsync();
|
||||||
|
if (_.isUndefined(this._dependentOrderHashes[signedOrder.maker][zrxTokenAddress])) {
|
||||||
|
this._dependentOrderHashes[signedOrder.maker][zrxTokenAddress] = new Set();
|
||||||
}
|
}
|
||||||
private removeFromDependentOrderHashes(makerAddress: string, makerTokenAddress: string, orderHash: string) {
|
this._dependentOrderHashes[signedOrder.maker][zrxTokenAddress].add(orderHash);
|
||||||
this._dependentOrderHashes[makerAddress][makerTokenAddress].delete(orderHash);
|
}
|
||||||
if (this._dependentOrderHashes[makerAddress][makerTokenAddress].size === 0) {
|
private removeFromDependentOrderHashes(makerAddress: string, tokenAddress: string, orderHash: string) {
|
||||||
delete this._dependentOrderHashes[makerAddress][makerTokenAddress];
|
this._dependentOrderHashes[makerAddress][tokenAddress].delete(orderHash);
|
||||||
|
if (this._dependentOrderHashes[makerAddress][tokenAddress].size === 0) {
|
||||||
|
delete this._dependentOrderHashes[makerAddress][tokenAddress];
|
||||||
}
|
}
|
||||||
if (_.isEmpty(this._dependentOrderHashes[makerAddress])) {
|
if (_.isEmpty(this._dependentOrderHashes[makerAddress])) {
|
||||||
delete this._dependentOrderHashes[makerAddress];
|
delete this._dependentOrderHashes[makerAddress];
|
||||||
|
@ -42,13 +42,8 @@ export type OrderValues = [BigNumber, BigNumber, BigNumber,
|
|||||||
export type LogEvent = Web3.LogEntryEvent;
|
export type LogEvent = Web3.LogEntryEvent;
|
||||||
export type DecodedLogEvent<ArgsType> = Web3.DecodedLogEntryEvent<ArgsType>;
|
export type DecodedLogEvent<ArgsType> = Web3.DecodedLogEntryEvent<ArgsType>;
|
||||||
|
|
||||||
export type EventCallbackAsync<ArgsType> = (err: null|Error, log?: DecodedLogEvent<ArgsType>) => Promise<void>;
|
export type EventCallback<ArgsType> = (err: null|Error, log?: DecodedLogEvent<ArgsType>) => void;
|
||||||
export type EventCallbackSync<ArgsType> = (err: null|Error, log?: DecodedLogEvent<ArgsType>) => void;
|
export type EventWatcherCallback = (log: LogEvent) => void;
|
||||||
export type EventCallback<ArgsType> = EventCallbackSync<ArgsType>|EventCallbackAsync<ArgsType>;
|
|
||||||
|
|
||||||
export type EventWatcherCallbackSync = (log: LogEvent) => void;
|
|
||||||
export type EventWatcherCallbackAsync = (log: LogEvent) => Promise<void>;
|
|
||||||
export type EventWatcherCallback = EventWatcherCallbackSync|EventWatcherCallbackAsync;
|
|
||||||
|
|
||||||
export interface ExchangeContract extends Web3.ContractInstance {
|
export interface ExchangeContract extends Web3.ContractInstance {
|
||||||
isValidSignature: {
|
isValidSignature: {
|
||||||
@ -496,6 +491,7 @@ export interface OrderRelevantState {
|
|||||||
filledTakerTokenAmount: BigNumber;
|
filledTakerTokenAmount: BigNumber;
|
||||||
cancelledTakerTokenAmount: BigNumber;
|
cancelledTakerTokenAmount: BigNumber;
|
||||||
remainingFillableMakerTokenAmount: BigNumber;
|
remainingFillableMakerTokenAmount: BigNumber;
|
||||||
|
remainingFillableTakerTokenAmount: BigNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderStateValid {
|
export interface OrderStateValid {
|
||||||
@ -512,9 +508,7 @@ export interface OrderStateInvalid {
|
|||||||
|
|
||||||
export type OrderState = OrderStateValid|OrderStateInvalid;
|
export type OrderState = OrderStateValid|OrderStateInvalid;
|
||||||
|
|
||||||
export type OnOrderStateChangeCallbackSync = (orderState: OrderState) => void;
|
export type OnOrderStateChangeCallback = (orderState: OrderState) => void;
|
||||||
export type OnOrderStateChangeCallbackAsync = (orderState: OrderState) => Promise<void>;
|
|
||||||
export type OnOrderStateChangeCallback = OnOrderStateChangeCallbackAsync|OnOrderStateChangeCallbackSync;
|
|
||||||
|
|
||||||
export interface TransactionReceipt {
|
export interface TransactionReceipt {
|
||||||
blockHash: string;
|
blockHash: string;
|
||||||
|
@ -34,7 +34,7 @@ export class AbiDecoder {
|
|||||||
value = this.padZeros(new BigNumber(value).toString(16));
|
value = this.padZeros(new BigNumber(value).toString(16));
|
||||||
} else if (param.type === SolidityTypes.Uint256 ||
|
} else if (param.type === SolidityTypes.Uint256 ||
|
||||||
param.type === SolidityTypes.Uint8 ||
|
param.type === SolidityTypes.Uint8 ||
|
||||||
param.type === SolidityTypes.Uint ) {
|
param.type === SolidityTypes.Uint) {
|
||||||
value = new BigNumber(value);
|
value = new BigNumber(value);
|
||||||
}
|
}
|
||||||
decodedParams[param.name] = value;
|
decodedParams[param.name] = value;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as Web3 from 'web3';
|
import * as Web3 from 'web3';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import {SchemaValidator, Schema} from '0x-json-schemas';
|
import {SchemaValidator, Schema} from '@0xproject/json-schemas';
|
||||||
import {assert as sharedAssert} from '@0xproject/assert';
|
import {assert as sharedAssert} from '@0xproject/assert';
|
||||||
import {Web3Wrapper} from '../web3_wrapper';
|
import {Web3Wrapper} from '../web3_wrapper';
|
||||||
import {signatureUtils} from '../utils/signature_utils';
|
import {signatureUtils} from '../utils/signature_utils';
|
||||||
@ -9,7 +9,8 @@ import {ECSignature} from '../types';
|
|||||||
|
|
||||||
const HEX_REGEX = /^0x[0-9A-F]*$/i;
|
const HEX_REGEX = /^0x[0-9A-F]*$/i;
|
||||||
|
|
||||||
export const assert = _.extend({}, sharedAssert, {
|
export const assert = {
|
||||||
|
...sharedAssert,
|
||||||
isValidSignature(orderHash: string, ecSignature: ECSignature, signerAddress: string) {
|
isValidSignature(orderHash: string, ecSignature: ECSignature, signerAddress: string) {
|
||||||
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`);
|
||||||
@ -26,4 +27,4 @@ export const assert = _.extend({}, sharedAssert, {
|
|||||||
const availableAddresses = await web3Wrapper.getAvailableAddressesAsync();
|
const availableAddresses = await web3Wrapper.getAvailableAddressesAsync();
|
||||||
this.assert(!_.isEmpty(availableAddresses), 'No addresses were available on the provided web3 provider');
|
this.assert(!_.isEmpty(availableAddresses), 'No addresses were available on the provided web3 provider');
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
|
@ -18,6 +18,8 @@ import {constants} from '../utils/constants';
|
|||||||
import {OrderFilledCancelledLazyStore} from '../stores/order_filled_cancelled_lazy_store';
|
import {OrderFilledCancelledLazyStore} from '../stores/order_filled_cancelled_lazy_store';
|
||||||
import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store';
|
import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store';
|
||||||
|
|
||||||
|
const ACCEPTABLE_RELATIVE_ROUNDING_ERROR = 0.0001;
|
||||||
|
|
||||||
export class OrderStateUtils {
|
export class OrderStateUtils {
|
||||||
private balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore;
|
private balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore;
|
||||||
private orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore;
|
private orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore;
|
||||||
@ -78,6 +80,9 @@ export class OrderStateUtils {
|
|||||||
.dividedToIntegerBy(totalTakerTokenAmount);
|
.dividedToIntegerBy(totalTakerTokenAmount);
|
||||||
const fillableMakerTokenAmount = BigNumber.min([makerProxyAllowance, makerBalance]);
|
const fillableMakerTokenAmount = BigNumber.min([makerProxyAllowance, makerBalance]);
|
||||||
const remainingFillableMakerTokenAmount = BigNumber.min(fillableMakerTokenAmount, remainingMakerTokenAmount);
|
const remainingFillableMakerTokenAmount = BigNumber.min(fillableMakerTokenAmount, remainingMakerTokenAmount);
|
||||||
|
const remainingFillableTakerTokenAmount = remainingFillableMakerTokenAmount
|
||||||
|
.times(totalTakerTokenAmount)
|
||||||
|
.dividedToIntegerBy(totalMakerTokenAmount);
|
||||||
// TODO: Handle edge case where maker token is ZRX with fee
|
// TODO: Handle edge case where maker token is ZRX with fee
|
||||||
const orderRelevantState = {
|
const orderRelevantState = {
|
||||||
makerBalance,
|
makerBalance,
|
||||||
@ -87,6 +92,7 @@ export class OrderStateUtils {
|
|||||||
filledTakerTokenAmount,
|
filledTakerTokenAmount,
|
||||||
cancelledTakerTokenAmount,
|
cancelledTakerTokenAmount,
|
||||||
remainingFillableMakerTokenAmount,
|
remainingFillableMakerTokenAmount,
|
||||||
|
remainingFillableTakerTokenAmount,
|
||||||
};
|
};
|
||||||
return orderRelevantState;
|
return orderRelevantState;
|
||||||
}
|
}
|
||||||
@ -113,6 +119,13 @@ export class OrderStateUtils {
|
|||||||
throw new Error(ExchangeContractErrs.InsufficientMakerFeeAllowance);
|
throw new Error(ExchangeContractErrs.InsufficientMakerFeeAllowance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const minFillableTakerTokenAmountWithinNoRoundingErrorRange = signedOrder.takerTokenAmount
|
||||||
|
.dividedBy(ACCEPTABLE_RELATIVE_ROUNDING_ERROR)
|
||||||
|
.dividedBy(signedOrder.makerTokenAmount);
|
||||||
|
if (orderRelevantState.remainingFillableTakerTokenAmount
|
||||||
|
.lessThan(minFillableTakerTokenAmountWithinNoRoundingErrorRange)) {
|
||||||
|
throw new Error(ExchangeContractErrs.OrderFillRoundingError);
|
||||||
|
}
|
||||||
// TODO Add linear function solver when maker token is ZRX #badass
|
// TODO Add linear function solver when maker token is ZRX #badass
|
||||||
// Return the max amount that's fillable
|
// Return the max amount that's fillable
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ describe('OrderStateWatcher', () => {
|
|||||||
let taker: string;
|
let taker: string;
|
||||||
let web3Wrapper: Web3Wrapper;
|
let web3Wrapper: Web3Wrapper;
|
||||||
let signedOrder: SignedOrder;
|
let signedOrder: SignedOrder;
|
||||||
const fillableAmount = new BigNumber(5);
|
const fillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(5), 18);
|
||||||
before(async () => {
|
before(async () => {
|
||||||
web3 = web3Factory.create();
|
web3 = web3Factory.create();
|
||||||
zeroEx = new ZeroEx(web3.currentProvider);
|
zeroEx = new ZeroEx(web3.currentProvider);
|
||||||
@ -61,19 +61,25 @@ describe('OrderStateWatcher', () => {
|
|||||||
[makerToken, takerToken] = tokenUtils.getNonProtocolTokens();
|
[makerToken, takerToken] = tokenUtils.getNonProtocolTokens();
|
||||||
web3Wrapper = (zeroEx as any)._web3Wrapper;
|
web3Wrapper = (zeroEx as any)._web3Wrapper;
|
||||||
});
|
});
|
||||||
|
beforeEach(async () => {
|
||||||
|
await blockchainLifecycle.startAsync();
|
||||||
|
});
|
||||||
|
afterEach(async () => {
|
||||||
|
await blockchainLifecycle.revertAsync();
|
||||||
|
});
|
||||||
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);
|
await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
|
||||||
expect((zeroEx.orderStateWatcher as any)._orderByOrderHash).to.include({
|
expect((zeroEx.orderStateWatcher as any)._orderByOrderHash).to.include({
|
||||||
[orderHash]: signedOrder,
|
[orderHash]: signedOrder,
|
||||||
});
|
});
|
||||||
let dependentOrderHashes = (zeroEx.orderStateWatcher as any)._dependentOrderHashes;
|
let dependentOrderHashes = (zeroEx.orderStateWatcher as any)._dependentOrderHashes;
|
||||||
expect(dependentOrderHashes[signedOrder.maker][signedOrder.makerTokenAddress]).to.have.keys(orderHash);
|
expect(dependentOrderHashes[signedOrder.maker][signedOrder.makerTokenAddress]).to.have.keys(orderHash);
|
||||||
zeroEx.orderStateWatcher.removeOrder(orderHash);
|
await zeroEx.orderStateWatcher.removeOrderAsync(orderHash);
|
||||||
expect((zeroEx.orderStateWatcher as any)._orderByOrderHash).to.not.include({
|
expect((zeroEx.orderStateWatcher as any)._orderByOrderHash).to.not.include({
|
||||||
[orderHash]: signedOrder,
|
[orderHash]: signedOrder,
|
||||||
});
|
});
|
||||||
@ -86,7 +92,7 @@ describe('OrderStateWatcher', () => {
|
|||||||
);
|
);
|
||||||
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);
|
await zeroEx.orderStateWatcher.removeOrderAsync(nonExistentOrderHash);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#subscribe', async () => {
|
describe('#subscribe', async () => {
|
||||||
@ -103,7 +109,7 @@ describe('OrderStateWatcher', () => {
|
|||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
zeroEx.orderStateWatcher.unsubscribe();
|
zeroEx.orderStateWatcher.unsubscribe();
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
zeroEx.orderStateWatcher.removeOrder(orderHash);
|
await zeroEx.orderStateWatcher.removeOrderAsync(orderHash);
|
||||||
});
|
});
|
||||||
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 () => {
|
||||||
@ -111,7 +117,7 @@ describe('OrderStateWatcher', () => {
|
|||||||
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);
|
await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||||
expect(orderState.isValid).to.be.false();
|
expect(orderState.isValid).to.be.false();
|
||||||
const invalidOrderState = orderState as OrderStateInvalid;
|
const invalidOrderState = orderState as OrderStateInvalid;
|
||||||
@ -129,7 +135,7 @@ describe('OrderStateWatcher', () => {
|
|||||||
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);
|
await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||||
throw new Error('OrderState callback fired for irrelevant order');
|
throw new Error('OrderState callback fired for irrelevant order');
|
||||||
});
|
});
|
||||||
@ -150,7 +156,7 @@ describe('OrderStateWatcher', () => {
|
|||||||
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);
|
await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||||
expect(orderState.isValid).to.be.false();
|
expect(orderState.isValid).to.be.false();
|
||||||
const invalidOrderState = orderState as OrderStateInvalid;
|
const invalidOrderState = orderState as OrderStateInvalid;
|
||||||
@ -170,7 +176,7 @@ describe('OrderStateWatcher', () => {
|
|||||||
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);
|
await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
|
||||||
|
|
||||||
let eventCount = 0;
|
let eventCount = 0;
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||||
@ -202,7 +208,7 @@ describe('OrderStateWatcher', () => {
|
|||||||
|
|
||||||
const fillAmountInBaseUnits = new BigNumber(2);
|
const fillAmountInBaseUnits = new BigNumber(2);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
|
||||||
|
|
||||||
let eventCount = 0;
|
let eventCount = 0;
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||||
@ -215,6 +221,8 @@ describe('OrderStateWatcher', () => {
|
|||||||
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(
|
||||||
|
remainingFillable);
|
||||||
expect(orderRelevantState.makerBalance).to.be.bignumber.equal(remainingMakerBalance);
|
expect(orderRelevantState.makerBalance).to.be.bignumber.equal(remainingMakerBalance);
|
||||||
if (eventCount === 2) {
|
if (eventCount === 2) {
|
||||||
done();
|
done();
|
||||||
@ -227,18 +235,36 @@ describe('OrderStateWatcher', () => {
|
|||||||
);
|
);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
describe('remainingFillableMakerTokenAmount', () => {
|
it('should trigger the callback when orders backing ZRX allowance changes', (done: DoneCallback) => {
|
||||||
|
(async () => {
|
||||||
|
const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(2), 18);
|
||||||
|
const takerFee = ZeroEx.toBaseUnitAmount(new BigNumber(0), 18);
|
||||||
|
signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
|
||||||
|
makerToken.address, takerToken.address, makerFee, takerFee, maker, taker, fillableAmount,
|
||||||
|
taker);
|
||||||
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
|
await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
|
||||||
|
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
|
await zeroEx.token.setProxyAllowanceAsync(zrxTokenAddress, maker, new BigNumber(0));
|
||||||
|
})().catch(done);
|
||||||
|
});
|
||||||
|
describe('remainingFillable(M|T)akerTokenAmount', () => {
|
||||||
it('should calculate correct remaining fillable', (done: DoneCallback) => {
|
it('should calculate correct remaining fillable', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const takerFillableAmount = new BigNumber(10);
|
const takerFillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(10), 18);
|
||||||
const makerFillableAmount = new BigNumber(20);
|
const makerFillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(20), 18);
|
||||||
signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
|
||||||
makerToken.address, takerToken.address, maker, taker, makerFillableAmount, takerFillableAmount);
|
makerToken.address, takerToken.address, maker, taker, makerFillableAmount,
|
||||||
|
takerFillableAmount,
|
||||||
|
);
|
||||||
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
|
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
|
||||||
const takerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, taker);
|
const takerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, taker);
|
||||||
const fillAmountInBaseUnits = new BigNumber(2);
|
const fillAmountInBaseUnits = ZeroEx.toBaseUnitAmount(new BigNumber(2), 18);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
|
||||||
let eventCount = 0;
|
let eventCount = 0;
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||||
eventCount++;
|
eventCount++;
|
||||||
@ -247,7 +273,9 @@ 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(
|
||||||
new BigNumber(16));
|
ZeroEx.toBaseUnitAmount(new BigNumber(16), 18));
|
||||||
|
expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
|
||||||
|
ZeroEx.toBaseUnitAmount(new BigNumber(8), 18));
|
||||||
if (eventCount === 2) {
|
if (eventCount === 2) {
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
@ -267,14 +295,16 @@ describe('OrderStateWatcher', () => {
|
|||||||
|
|
||||||
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
|
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
|
||||||
|
|
||||||
const changedMakerApprovalAmount = new BigNumber(3);
|
const changedMakerApprovalAmount = ZeroEx.toBaseUnitAmount(new BigNumber(3), 18);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
|
||||||
|
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||||
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(
|
||||||
|
changedMakerApprovalAmount);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
@ -289,15 +319,17 @@ describe('OrderStateWatcher', () => {
|
|||||||
|
|
||||||
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
|
const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
|
||||||
|
|
||||||
const remainingAmount = new BigNumber(1);
|
const remainingAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), 18);
|
||||||
const transferAmount = makerBalance.sub(remainingAmount);
|
const transferAmount = makerBalance.sub(remainingAmount);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
|
||||||
|
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||||
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(
|
||||||
|
remainingAmount);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
zeroEx.orderStateWatcher.subscribe(callback);
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
@ -312,7 +344,7 @@ describe('OrderStateWatcher', () => {
|
|||||||
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);
|
await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
|
||||||
|
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||||
expect(orderState.isValid).to.be.false();
|
expect(orderState.isValid).to.be.false();
|
||||||
@ -327,6 +359,28 @@ describe('OrderStateWatcher', () => {
|
|||||||
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
|
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
|
||||||
})().catch(done);
|
})().catch(done);
|
||||||
});
|
});
|
||||||
|
it('should emit orderStateInvalid when within rounding error range', (done: DoneCallback) => {
|
||||||
|
(async () => {
|
||||||
|
const remainingFillableAmountInBaseUnits = new BigNumber(100);
|
||||||
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
|
makerToken.address, takerToken.address, maker, taker, fillableAmount,
|
||||||
|
);
|
||||||
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
|
await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
|
||||||
|
|
||||||
|
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||||
|
expect(orderState.isValid).to.be.false();
|
||||||
|
const invalidOrderState = orderState as OrderStateInvalid;
|
||||||
|
expect(invalidOrderState.orderHash).to.be.equal(orderHash);
|
||||||
|
expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderFillRoundingError);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
zeroEx.orderStateWatcher.subscribe(callback);
|
||||||
|
await zeroEx.exchange.cancelOrderAsync(
|
||||||
|
signedOrder, fillableAmount.minus(remainingFillableAmountInBaseUnits),
|
||||||
|
);
|
||||||
|
})().catch(done);
|
||||||
|
});
|
||||||
it('should emit orderStateValid when watched order partially cancelled', (done: DoneCallback) => {
|
it('should emit orderStateValid when watched order partially cancelled', (done: DoneCallback) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
|
||||||
@ -338,7 +392,7 @@ describe('OrderStateWatcher', () => {
|
|||||||
|
|
||||||
const cancelAmountInBaseUnits = new BigNumber(2);
|
const cancelAmountInBaseUnits = new BigNumber(2);
|
||||||
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
|
||||||
zeroEx.orderStateWatcher.addOrder(signedOrder);
|
await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
|
||||||
|
|
||||||
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
|
||||||
expect(orderState.isValid).to.be.true();
|
expect(orderState.isValid).to.be.true();
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import {SchemaValidator, schemas} from '0x-json-schemas';
|
import {SchemaValidator, schemas} from '@0xproject/json-schemas';
|
||||||
import {chaiSetup} from './utils/chai_setup';
|
import {chaiSetup} from './utils/chai_setup';
|
||||||
import {web3Factory} from './utils/web3_factory';
|
import {web3Factory} from './utils/web3_factory';
|
||||||
import {ZeroEx, Token} from '../src';
|
import {ZeroEx, Token} from '../src';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"extends": [
|
"extends": [
|
||||||
"tslint-config-0xproject"
|
"@0xproject/tslint-config"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
6
packages/assert/CHANGELOG.md
Normal file
6
packages/assert/CHANGELOG.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# CHANGELOG
|
||||||
|
|
||||||
|
v0.0.4 - _Nov. 14, 2017_
|
||||||
|
------------------------
|
||||||
|
* Re-publish Assert previously published under NPM package @0xproject/0x-assert
|
||||||
|
* Added assertion isValidBaseUnitAmount which checks both that the value is a valid bigNumber and that it does not contain decimals.
|
@ -1 +1,10 @@
|
|||||||
|
assert
|
||||||
|
------
|
||||||
|
|
||||||
Standard type and schema assertions to be used across all 0x projects and packages
|
Standard type and schema assertions to be used across all 0x projects and packages
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install @0xproject/assert --save
|
||||||
|
```
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
|
||||||
"name": "@0xproject/assert",
|
"name": "@0xproject/assert",
|
||||||
"version": "0.0.3",
|
"version": "0.0.4",
|
||||||
"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",
|
||||||
@ -24,6 +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.1.0",
|
||||||
"@types/lodash": "^4.14.78",
|
"@types/lodash": "^4.14.78",
|
||||||
"@types/mocha": "^2.2.42",
|
"@types/mocha": "^2.2.42",
|
||||||
"@types/valid-url": "^1.0.2",
|
"@types/valid-url": "^1.0.2",
|
||||||
@ -33,12 +33,11 @@
|
|||||||
"mocha": "^4.0.1",
|
"mocha": "^4.0.1",
|
||||||
"npm-run-all": "^4.1.1",
|
"npm-run-all": "^4.1.1",
|
||||||
"shx": "^0.2.2",
|
"shx": "^0.2.2",
|
||||||
"tslint": "~5.5.0",
|
"tslint": "5.8.0",
|
||||||
"tslint-config-0xproject": "^0.0.2",
|
|
||||||
"typescript": "^2.4.2"
|
"typescript": "^2.4.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"0x-json-schemas": "^0.6.5",
|
"@0xproject/json-schemas": "^0.6.7",
|
||||||
"bignumber.js": "~4.1.0",
|
"bignumber.js": "~4.1.0",
|
||||||
"ethereum-address": "^0.0.4",
|
"ethereum-address": "^0.0.4",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
|
14
packages/assert/scripts/postpublish.js
Normal file
14
packages/assert/scripts/postpublish.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
const postpublish_utils = require('../../../scripts/postpublish_utils');
|
||||||
|
const packageJSON = require('../package.json');
|
||||||
|
|
||||||
|
const subPackageName = packageJSON.name;
|
||||||
|
|
||||||
|
postpublish_utils.getLatestTagAndVersionAsync(subPackageName)
|
||||||
|
.then(function(result) {
|
||||||
|
const releaseName = postpublish_utils.getReleaseName(subPackageName, result.version);
|
||||||
|
const assets = [];
|
||||||
|
return postpublish_utils.publishReleaseNotes(result.tag, releaseName, assets);
|
||||||
|
})
|
||||||
|
.catch (function(err) {
|
||||||
|
throw err;
|
||||||
|
});
|
@ -2,7 +2,10 @@ import BigNumber from 'bignumber.js';
|
|||||||
import * as ethereum_address from 'ethereum-address';
|
import * as ethereum_address from 'ethereum-address';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import * as validUrl from 'valid-url';
|
import * as validUrl from 'valid-url';
|
||||||
import {SchemaValidator, Schema} from '0x-json-schemas';
|
import {
|
||||||
|
SchemaValidator,
|
||||||
|
Schema,
|
||||||
|
} from '@0xproject/json-schemas';
|
||||||
|
|
||||||
const HEX_REGEX = /^0x[0-9A-F]*$/i;
|
const HEX_REGEX = /^0x[0-9A-F]*$/i;
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import 'mocha';
|
|||||||
import * as dirtyChai from 'dirty-chai';
|
import * as dirtyChai from 'dirty-chai';
|
||||||
import * as chai from 'chai';
|
import * as chai from 'chai';
|
||||||
import {BigNumber} from 'bignumber.js';
|
import {BigNumber} from 'bignumber.js';
|
||||||
import {schemas} from '0x-json-schemas';
|
import {schemas} from '@0xproject/json-schemas';
|
||||||
import {assert} from '../src/index';
|
import {assert} from '../src/index';
|
||||||
|
|
||||||
chai.config.includeStack = true;
|
chai.config.includeStack = true;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"extends": [
|
"extends": [
|
||||||
"tslint-config-0xproject"
|
"@0xproject/tslint-config"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
4
packages/connect/CHANGELOG.md
Normal file
4
packages/connect/CHANGELOG.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# CHANGELOG
|
||||||
|
|
||||||
|
v0.0.0 - _Nov. 15, 2017_
|
||||||
|
------------------------
|
1
packages/connect/README.md
Normal file
1
packages/connect/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
This repository contains a Javascript library that makes it easy to interact with Relayers that conform to the [Standard Relayer API](https://github.com/0xProject/standard-relayer-api)
|
68
packages/connect/package.json
Normal file
68
packages/connect/package.json
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
{
|
||||||
|
"name": "@0xproject/connect",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "A javascript library for interacting with the standard relayer api",
|
||||||
|
"keywords": [
|
||||||
|
"0x-connect",
|
||||||
|
"0xproject",
|
||||||
|
"ethereum",
|
||||||
|
"tokens",
|
||||||
|
"exchange"
|
||||||
|
],
|
||||||
|
"main": "lib/src/index.js",
|
||||||
|
"types": "lib/src/index.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"clean": "shx rm -rf _bundles lib test_temp",
|
||||||
|
"copy_test_fixtures": "copyfiles -u 2 './test/fixtures/**/*.json' ./lib/test/fixtures",
|
||||||
|
"lint": "tslint src/**/*.ts test/**/*.ts",
|
||||||
|
"prepublishOnly": "run-p build",
|
||||||
|
"run_mocha": "mocha lib/test/**/*_test.js",
|
||||||
|
"test": "run-s clean build copy_test_fixtures run_mocha",
|
||||||
|
"test:circleci": "yarn test"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/0xProject/0x.js.git"
|
||||||
|
},
|
||||||
|
"author": "Brandon Millman",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/0xProject/0x.js/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/0xProject/0x.js/packages/connect/README.md",
|
||||||
|
"dependencies": {
|
||||||
|
"@0xproject/assert": "0.0.4",
|
||||||
|
"@0xproject/json-schemas": "0.6.7",
|
||||||
|
"0x.js": "~0.25.1",
|
||||||
|
"bignumber.js": "~4.1.0",
|
||||||
|
"isomorphic-fetch": "^2.2.1",
|
||||||
|
"lodash": "^4.17.4",
|
||||||
|
"query-string": "^5.0.1",
|
||||||
|
"websocket": "^1.0.25"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@0xproject/tslint-config": "0.1.0",
|
||||||
|
"@types/fetch-mock": "^5.12.1",
|
||||||
|
"@types/lodash": "^4.14.77",
|
||||||
|
"@types/mocha": "^2.2.42",
|
||||||
|
"@types/query-string": "^5.0.1",
|
||||||
|
"@types/websocket": "^0.0.34",
|
||||||
|
"chai": "^4.0.1",
|
||||||
|
"chai-as-promised": "^7.1.0",
|
||||||
|
"chai-as-promised-typescript-typings": "0.0.3",
|
||||||
|
"chai-typescript-typings": "^0.0.1",
|
||||||
|
"copyfiles": "^1.2.0",
|
||||||
|
"dirty-chai": "^2.0.1",
|
||||||
|
"fetch-mock": "^5.13.1",
|
||||||
|
"mocha": "^4.0.0",
|
||||||
|
"npm-run-all": "^4.0.2",
|
||||||
|
"shx": "^0.2.2",
|
||||||
|
"tslint": "5.8.0",
|
||||||
|
"typescript": "~2.6.1",
|
||||||
|
"web3-typescript-typings": "^0.7.1"
|
||||||
|
}
|
||||||
|
}
|
14
packages/connect/scripts/postpublish.js
Normal file
14
packages/connect/scripts/postpublish.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
const postpublish_utils = require('../../../scripts/postpublish_utils');
|
||||||
|
const packageJSON = require('../package.json');
|
||||||
|
|
||||||
|
const subPackageName = packageJSON.name;
|
||||||
|
|
||||||
|
postpublish_utils.getLatestTagAndVersionAsync(subPackageName)
|
||||||
|
.then(function(result) {
|
||||||
|
const releaseName = postpublish_utils.getReleaseName(subPackageName, result.version);
|
||||||
|
const assets = [];
|
||||||
|
return postpublish_utils.publishReleaseNotes(result.tag, releaseName, assets);
|
||||||
|
})
|
||||||
|
.catch (function(err) {
|
||||||
|
throw err;
|
||||||
|
});
|
6
packages/connect/src/globals.d.ts
vendored
Normal file
6
packages/connect/src/globals.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
declare module 'dirty-chai';
|
||||||
|
|
||||||
|
declare module '*.json' {
|
||||||
|
const value: any;
|
||||||
|
export default value;
|
||||||
|
}
|
171
packages/connect/src/http_client.ts
Normal file
171
packages/connect/src/http_client.ts
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
import 'isomorphic-fetch';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
import {BigNumber} from 'bignumber.js';
|
||||||
|
import * as queryString from 'query-string';
|
||||||
|
import {assert} from '@0xproject/assert';
|
||||||
|
import {schemas} from '@0xproject/json-schemas';
|
||||||
|
import {SignedOrder} from '0x.js';
|
||||||
|
import {
|
||||||
|
Client,
|
||||||
|
FeesRequest,
|
||||||
|
FeesResponse,
|
||||||
|
OrderbookRequest,
|
||||||
|
OrderbookResponse,
|
||||||
|
OrdersRequest,
|
||||||
|
TokenPairsItem,
|
||||||
|
TokenPairsRequest,
|
||||||
|
} from './types';
|
||||||
|
import {schemas as clientSchemas} from './schemas/schemas';
|
||||||
|
import {typeConverters} from './utils/type_converters';
|
||||||
|
|
||||||
|
interface RequestOptions {
|
||||||
|
params?: object;
|
||||||
|
payload?: object;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum RequestType {
|
||||||
|
Get = 'GET',
|
||||||
|
Post = 'POST',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class includes all the functionality related to interacting with a set of HTTP endpoints
|
||||||
|
* that implement the standard relayer API v0
|
||||||
|
*/
|
||||||
|
export class HttpClient implements Client {
|
||||||
|
private apiEndpointUrl: string;
|
||||||
|
/**
|
||||||
|
* Instantiates a new HttpClient instance
|
||||||
|
* @param url The base url for making API calls
|
||||||
|
* @return An instance of HttpClient
|
||||||
|
*/
|
||||||
|
constructor(url: string) {
|
||||||
|
assert.isHttpUrl('url', url);
|
||||||
|
this.apiEndpointUrl = url;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Retrieve token pair info from the API
|
||||||
|
* @param request A TokenPairsRequest instance describing specific token information
|
||||||
|
* to retrieve
|
||||||
|
* @return The resulting TokenPairsItems that match the request
|
||||||
|
*/
|
||||||
|
public async getTokenPairsAsync(request?: TokenPairsRequest): Promise<TokenPairsItem[]> {
|
||||||
|
if (!_.isUndefined(request)) {
|
||||||
|
assert.doesConformToSchema('request', request, clientSchemas.relayerTokenPairsRequestSchema);
|
||||||
|
}
|
||||||
|
const requestOpts = {
|
||||||
|
params: request,
|
||||||
|
};
|
||||||
|
const tokenPairs = await this._requestAsync('/token_pairs', RequestType.Get, requestOpts);
|
||||||
|
assert.doesConformToSchema(
|
||||||
|
'tokenPairs', tokenPairs, schemas.relayerApiTokenPairsResponseSchema);
|
||||||
|
_.each(tokenPairs, (tokenPair: object) => {
|
||||||
|
typeConverters.convertStringsFieldsToBigNumbers(tokenPair, [
|
||||||
|
'tokenA.minAmount',
|
||||||
|
'tokenA.maxAmount',
|
||||||
|
'tokenB.minAmount',
|
||||||
|
'tokenB.maxAmount',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
return tokenPairs;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Retrieve orders from the API
|
||||||
|
* @param request An OrdersRequest instance describing specific orders to retrieve
|
||||||
|
* @return The resulting SignedOrders that match the request
|
||||||
|
*/
|
||||||
|
public async getOrdersAsync(request?: OrdersRequest): Promise<SignedOrder[]> {
|
||||||
|
if (!_.isUndefined(request)) {
|
||||||
|
assert.doesConformToSchema('request', request, clientSchemas.relayerOrdersRequestSchema);
|
||||||
|
}
|
||||||
|
const requestOpts = {
|
||||||
|
params: request,
|
||||||
|
};
|
||||||
|
const orders = await this._requestAsync(`/orders`, RequestType.Get, requestOpts);
|
||||||
|
assert.doesConformToSchema('orders', orders, schemas.signedOrdersSchema);
|
||||||
|
_.each(orders, (order: object) => typeConverters.convertOrderStringFieldsToBigNumber(order));
|
||||||
|
return orders;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Retrieve a specific order from the API
|
||||||
|
* @param orderHash An orderHash generated from the desired order
|
||||||
|
* @return The SignedOrder that matches the supplied orderHash
|
||||||
|
*/
|
||||||
|
public async getOrderAsync(orderHash: string): Promise<SignedOrder> {
|
||||||
|
assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
|
||||||
|
const order = await this._requestAsync(`/order/${orderHash}`, RequestType.Get);
|
||||||
|
assert.doesConformToSchema('order', order, schemas.signedOrderSchema);
|
||||||
|
typeConverters.convertOrderStringFieldsToBigNumber(order);
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Retrieve an orderbook from the API
|
||||||
|
* @param request An OrderbookRequest instance describing the specific orderbook to retrieve
|
||||||
|
* @return The resulting OrderbookResponse that matches the request
|
||||||
|
*/
|
||||||
|
public async getOrderbookAsync(request: OrderbookRequest): Promise<OrderbookResponse> {
|
||||||
|
assert.doesConformToSchema('request', request, clientSchemas.relayerOrderBookRequestSchema);
|
||||||
|
const requestOpts = {
|
||||||
|
params: request,
|
||||||
|
};
|
||||||
|
const orderBook = await this._requestAsync('/orderbook', RequestType.Get, requestOpts);
|
||||||
|
assert.doesConformToSchema('orderBook', orderBook, schemas.relayerApiOrderBookResponseSchema);
|
||||||
|
typeConverters.convertOrderbookStringFieldsToBigNumber(orderBook);
|
||||||
|
return orderBook;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Retrieve fee information from the API
|
||||||
|
* @param request A FeesRequest instance describing the specific fees to retrieve
|
||||||
|
* @return The resulting FeesResponse that matches the request
|
||||||
|
*/
|
||||||
|
public async getFeesAsync(request: FeesRequest): Promise<FeesResponse> {
|
||||||
|
assert.doesConformToSchema('request', request, schemas.relayerApiFeesPayloadSchema);
|
||||||
|
typeConverters.convertBigNumberFieldsToStrings(request, [
|
||||||
|
'makerTokenAmount',
|
||||||
|
'takerTokenAmount',
|
||||||
|
'expirationUnixTimestampSec',
|
||||||
|
'salt',
|
||||||
|
]);
|
||||||
|
const requestOpts = {
|
||||||
|
payload: request,
|
||||||
|
};
|
||||||
|
const fees = await this._requestAsync('/fees', RequestType.Post, requestOpts);
|
||||||
|
assert.doesConformToSchema('fees', fees, schemas.relayerApiFeesResponseSchema);
|
||||||
|
typeConverters.convertStringsFieldsToBigNumbers(fees, ['makerFee', 'takerFee']);
|
||||||
|
return fees;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Submit a signed order to the API
|
||||||
|
* @param signedOrder A SignedOrder instance to submit
|
||||||
|
*/
|
||||||
|
public async submitOrderAsync(signedOrder: SignedOrder): Promise<void> {
|
||||||
|
assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
|
||||||
|
const requestOpts = {
|
||||||
|
payload: signedOrder,
|
||||||
|
};
|
||||||
|
await this._requestAsync('/order', RequestType.Post, requestOpts);
|
||||||
|
}
|
||||||
|
private async _requestAsync(path: string, requestType: RequestType, requestOptions?: RequestOptions): Promise<any> {
|
||||||
|
const params = _.get(requestOptions, 'params');
|
||||||
|
const payload = _.get(requestOptions, 'payload');
|
||||||
|
let query = '';
|
||||||
|
if (!_.isUndefined(params) && !_.isEmpty(params)) {
|
||||||
|
const stringifiedParams = queryString.stringify(params);
|
||||||
|
query = `?${stringifiedParams}`;
|
||||||
|
}
|
||||||
|
const url = `${this.apiEndpointUrl}/v0${path}${query}`;
|
||||||
|
const headers = new Headers({
|
||||||
|
'content-type': 'application/json',
|
||||||
|
});
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: requestType,
|
||||||
|
body: payload,
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
throw Error(response.statusText);
|
||||||
|
}
|
||||||
|
const json = await response.json();
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
}
|
15
packages/connect/src/index.ts
Normal file
15
packages/connect/src/index.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
export {HttpClient} from './http_client';
|
||||||
|
export {WebSocketOrderbookChannel} from './ws_orderbook_channel';
|
||||||
|
export {
|
||||||
|
Client,
|
||||||
|
FeesRequest,
|
||||||
|
FeesResponse,
|
||||||
|
OrderbookChannel,
|
||||||
|
OrderbookChannelHandler,
|
||||||
|
OrderbookChannelSubscriptionOpts,
|
||||||
|
OrderbookRequest,
|
||||||
|
OrderbookResponse,
|
||||||
|
OrdersRequest,
|
||||||
|
TokenPairsItem,
|
||||||
|
TokenPairsRequest,
|
||||||
|
} from './types';
|
@ -0,0 +1,8 @@
|
|||||||
|
export const relayerOrderBookRequestSchema = {
|
||||||
|
id: '/RelayerOrderBookRequest',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
baseTokenAddress: {$ref: '/Address'},
|
||||||
|
quoteTokenAddress: {$ref: '/Address'},
|
||||||
|
},
|
||||||
|
};
|
@ -0,0 +1,8 @@
|
|||||||
|
export const relayerOrderBookRequestSchema = {
|
||||||
|
id: '/RelayerOrderBookRequest',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
baseTokenAddress: {$ref: '/Address'},
|
||||||
|
quoteTokenAddress: {$ref: '/Address'},
|
||||||
|
},
|
||||||
|
};
|
@ -0,0 +1,16 @@
|
|||||||
|
export const relayerOrdersRequestSchema = {
|
||||||
|
id: '/RelayerOrdersRequest',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
exchangeContractAddress: {$ref: '/Address'},
|
||||||
|
tokenAddress: {$ref: '/Address'},
|
||||||
|
makerTokenAddress: {$ref: '/Address'},
|
||||||
|
takerTokenAddress: {$ref: '/Address'},
|
||||||
|
tokenA: {$ref: '/Address'},
|
||||||
|
tokenB: {$ref: '/Address'},
|
||||||
|
maker: {$ref: '/Address'},
|
||||||
|
taker: {$ref: '/Address'},
|
||||||
|
trader: {$ref: '/Address'},
|
||||||
|
feeRecipient: {$ref: '/Address'},
|
||||||
|
},
|
||||||
|
};
|
@ -0,0 +1,8 @@
|
|||||||
|
export const relayerTokenPairsRequestSchema = {
|
||||||
|
id: '/RelayerTokenPairsRequest',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
tokenA: {$ref: '/Address'},
|
||||||
|
tokenB: {$ref: '/Address'},
|
||||||
|
},
|
||||||
|
};
|
15
packages/connect/src/schemas/schemas.ts
Normal file
15
packages/connect/src/schemas/schemas.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import {
|
||||||
|
relayerOrderBookRequestSchema,
|
||||||
|
} from './relayer_orderbook_request_schema';
|
||||||
|
import {
|
||||||
|
relayerOrdersRequestSchema,
|
||||||
|
} from './relayer_orders_request_schema';
|
||||||
|
import {
|
||||||
|
relayerTokenPairsRequestSchema,
|
||||||
|
} from './relayer_token_pairs_request_schema';
|
||||||
|
|
||||||
|
export const schemas = {
|
||||||
|
relayerOrderBookRequestSchema,
|
||||||
|
relayerOrdersRequestSchema,
|
||||||
|
relayerTokenPairsRequestSchema,
|
||||||
|
};
|
120
packages/connect/src/types.ts
Normal file
120
packages/connect/src/types.ts
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
import {SignedOrder} from '0x.js';
|
||||||
|
import {BigNumber} from 'bignumber.js';
|
||||||
|
|
||||||
|
export interface Client {
|
||||||
|
getTokenPairsAsync: (request?: TokenPairsRequest) => Promise<TokenPairsItem[]>;
|
||||||
|
getOrdersAsync: (request?: OrdersRequest) => Promise<SignedOrder[]>;
|
||||||
|
getOrderAsync: (orderHash: string) => Promise<SignedOrder>;
|
||||||
|
getOrderbookAsync: (request: OrderbookRequest) => Promise<OrderbookResponse>;
|
||||||
|
getFeesAsync: (request: FeesRequest) => Promise<FeesResponse>;
|
||||||
|
submitOrderAsync: (signedOrder: SignedOrder) => Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OrderbookChannel {
|
||||||
|
subscribe: (subscriptionOpts: OrderbookChannelSubscriptionOpts, handler: OrderbookChannelHandler) => void;
|
||||||
|
close: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OrderbookChannelHandler {
|
||||||
|
onSnapshot: (channel: OrderbookChannel, snapshot: OrderbookResponse) => void;
|
||||||
|
onUpdate: (channel: OrderbookChannel, order: SignedOrder) => void;
|
||||||
|
onError: (channel: OrderbookChannel, err: Error) => void;
|
||||||
|
onClose: (channel: OrderbookChannel) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type OrderbookChannelMessage =
|
||||||
|
SnapshotOrderbookChannelMessage |
|
||||||
|
UpdateOrderbookChannelMessage |
|
||||||
|
UnknownOrderbookChannelMessage;
|
||||||
|
|
||||||
|
export enum OrderbookChannelMessageTypes {
|
||||||
|
Snapshot = 'snapshot',
|
||||||
|
Update = 'update',
|
||||||
|
Unknown = 'unknown',
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SnapshotOrderbookChannelMessage {
|
||||||
|
type: OrderbookChannelMessageTypes.Snapshot;
|
||||||
|
payload: OrderbookResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdateOrderbookChannelMessage {
|
||||||
|
type: OrderbookChannelMessageTypes.Update;
|
||||||
|
payload: SignedOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UnknownOrderbookChannelMessage {
|
||||||
|
type: OrderbookChannelMessageTypes.Unknown;
|
||||||
|
payload: undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* baseTokenAddress: The address of token designated as the baseToken in the currency pair calculation of price
|
||||||
|
* quoteTokenAddress: The address of token designated as the quoteToken in the currency pair calculation of price
|
||||||
|
* snapshot: If true, a snapshot of the orderbook will be sent before the updates to the orderbook
|
||||||
|
* limit: Maximum number of bids and asks in orderbook snapshot
|
||||||
|
*/
|
||||||
|
export interface OrderbookChannelSubscriptionOpts {
|
||||||
|
baseTokenAddress: string;
|
||||||
|
quoteTokenAddress: string;
|
||||||
|
snapshot: boolean;
|
||||||
|
limit: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TokenPairsRequest {
|
||||||
|
tokenA?: string;
|
||||||
|
tokenB?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TokenPairsItem {
|
||||||
|
tokenA: TokenTradeInfo;
|
||||||
|
tokenB: TokenTradeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TokenTradeInfo {
|
||||||
|
address: string;
|
||||||
|
minAmount: BigNumber;
|
||||||
|
maxAmount: BigNumber;
|
||||||
|
precision: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OrdersRequest {
|
||||||
|
exchangeContractAddress?: string;
|
||||||
|
tokenAddress?: string;
|
||||||
|
makerTokenAddress?: string;
|
||||||
|
takerTokenAddress?: string;
|
||||||
|
tokenA?: string;
|
||||||
|
tokenB?: string;
|
||||||
|
maker?: string;
|
||||||
|
taker?: string;
|
||||||
|
trader?: string;
|
||||||
|
feeRecipient?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OrderbookRequest {
|
||||||
|
baseTokenAddress: string;
|
||||||
|
quoteTokenAddress: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OrderbookResponse {
|
||||||
|
bids: SignedOrder[];
|
||||||
|
asks: SignedOrder[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FeesRequest {
|
||||||
|
exchangeContractAddress: string;
|
||||||
|
maker: string;
|
||||||
|
taker: string;
|
||||||
|
makerTokenAddress: string;
|
||||||
|
takerTokenAddress: string;
|
||||||
|
makerTokenAmount: BigNumber;
|
||||||
|
takerTokenAmount: BigNumber;
|
||||||
|
expirationUnixTimestampSec: BigNumber;
|
||||||
|
salt: BigNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FeesResponse {
|
||||||
|
feeRecipient: string;
|
||||||
|
makerFee: BigNumber;
|
||||||
|
takerFee: BigNumber;
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
import * as _ from 'lodash';
|
||||||
|
import {SignedOrder} from '0x.js';
|
||||||
|
import {assert} from '@0xproject/assert';
|
||||||
|
import {schemas} from '@0xproject/json-schemas';
|
||||||
|
import {
|
||||||
|
OrderbookChannelMessage,
|
||||||
|
OrderbookChannelMessageTypes,
|
||||||
|
} from '../types';
|
||||||
|
import {typeConverters} from './type_converters';
|
||||||
|
|
||||||
|
export const orderbookChannelMessageParsers = {
|
||||||
|
parser(utf8Data: string): OrderbookChannelMessage {
|
||||||
|
const messageObj = JSON.parse(utf8Data);
|
||||||
|
const type: string = _.get(messageObj, 'type');
|
||||||
|
assert.assert(!_.isUndefined(type), `Message is missing a type parameter: ${utf8Data}`);
|
||||||
|
switch (type) {
|
||||||
|
case (OrderbookChannelMessageTypes.Snapshot): {
|
||||||
|
assert.doesConformToSchema('message', messageObj, schemas.relayerApiOrderbookChannelSnapshotSchema);
|
||||||
|
const orderbook = messageObj.payload;
|
||||||
|
typeConverters.convertOrderbookStringFieldsToBigNumber(orderbook);
|
||||||
|
return {
|
||||||
|
type,
|
||||||
|
payload: orderbook,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case (OrderbookChannelMessageTypes.Update): {
|
||||||
|
assert.doesConformToSchema('message', messageObj, schemas.relayerApiOrderbookChannelUpdateSchema);
|
||||||
|
const order = messageObj.payload;
|
||||||
|
typeConverters.convertOrderStringFieldsToBigNumber(order);
|
||||||
|
return {
|
||||||
|
type,
|
||||||
|
payload: order,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return {
|
||||||
|
type: OrderbookChannelMessageTypes.Unknown,
|
||||||
|
payload: undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
31
packages/connect/src/utils/type_converters.ts
Normal file
31
packages/connect/src/utils/type_converters.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import * as _ from 'lodash';
|
||||||
|
import {BigNumber} from 'bignumber.js';
|
||||||
|
|
||||||
|
// TODO: convert all of these to non-mutating, pure functions
|
||||||
|
export const typeConverters = {
|
||||||
|
convertOrderbookStringFieldsToBigNumber(orderbook: object): void {
|
||||||
|
_.each(orderbook, (orders: object[]) => {
|
||||||
|
_.each(orders, (order: object) => this.convertOrderStringFieldsToBigNumber(order));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
convertOrderStringFieldsToBigNumber(order: object): void {
|
||||||
|
this.convertStringsFieldsToBigNumbers(order, [
|
||||||
|
'makerTokenAmount',
|
||||||
|
'takerTokenAmount',
|
||||||
|
'makerFee',
|
||||||
|
'takerFee',
|
||||||
|
'expirationUnixTimestampSec',
|
||||||
|
'salt',
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
convertBigNumberFieldsToStrings(obj: object, fields: string[]): void {
|
||||||
|
_.each(fields, field => {
|
||||||
|
_.update(obj, field, (value: BigNumber) => value.toString());
|
||||||
|
});
|
||||||
|
},
|
||||||
|
convertStringsFieldsToBigNumbers(obj: object, fields: string[]): void {
|
||||||
|
_.each(fields, field => {
|
||||||
|
_.update(obj, field, (value: string) => new BigNumber(value));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
127
packages/connect/src/ws_orderbook_channel.ts
Normal file
127
packages/connect/src/ws_orderbook_channel.ts
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
import * as _ from 'lodash';
|
||||||
|
import * as WebSocket from 'websocket';
|
||||||
|
import {assert} from '@0xproject/assert';
|
||||||
|
import {schemas} from '@0xproject/json-schemas';
|
||||||
|
import {SignedOrder} from '0x.js';
|
||||||
|
import {
|
||||||
|
OrderbookChannel,
|
||||||
|
OrderbookChannelHandler,
|
||||||
|
OrderbookChannelMessageTypes,
|
||||||
|
OrderbookChannelSubscriptionOpts,
|
||||||
|
} from './types';
|
||||||
|
import {orderbookChannelMessageParsers} from './utils/orderbook_channel_message_parsers';
|
||||||
|
|
||||||
|
enum ConnectionEventType {
|
||||||
|
Close = 'close',
|
||||||
|
Error = 'error',
|
||||||
|
Message = 'message',
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ClientEventType {
|
||||||
|
Connect = 'connect',
|
||||||
|
ConnectFailed = 'connectFailed',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class includes all the functionality related to interacting with a websocket endpoint
|
||||||
|
* that implements the standard relayer API v0
|
||||||
|
*/
|
||||||
|
export class WebSocketOrderbookChannel implements OrderbookChannel {
|
||||||
|
private apiEndpointUrl: string;
|
||||||
|
private client: WebSocket.client;
|
||||||
|
private connectionIfExists?: WebSocket.connection;
|
||||||
|
/**
|
||||||
|
* Instantiates a new WebSocketOrderbookChannel instance
|
||||||
|
* @param url The base url for making API calls
|
||||||
|
* @return An instance of WebSocketOrderbookChannel
|
||||||
|
*/
|
||||||
|
constructor(url: string) {
|
||||||
|
assert.isUri('url', url);
|
||||||
|
this.apiEndpointUrl = url;
|
||||||
|
this.client = new WebSocket.client();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Subscribe to orderbook snapshots and updates from the websocket
|
||||||
|
* @param subscriptionOpts An OrderbookChannelSubscriptionOpts instance describing which
|
||||||
|
* token pair to subscribe to
|
||||||
|
* @param handler An OrderbookChannelHandler instance that responds to various
|
||||||
|
* channel updates
|
||||||
|
*/
|
||||||
|
public subscribe(subscriptionOpts: OrderbookChannelSubscriptionOpts, handler: OrderbookChannelHandler): void {
|
||||||
|
assert.doesConformToSchema(
|
||||||
|
'subscriptionOpts', subscriptionOpts, schemas.relayerApiOrderbookChannelSubscribePayload);
|
||||||
|
assert.isFunction('handler.onSnapshot', _.get(handler, 'onSnapshot'));
|
||||||
|
assert.isFunction('handler.onUpdate', _.get(handler, 'onUpdate'));
|
||||||
|
assert.isFunction('handler.onError', _.get(handler, 'onError'));
|
||||||
|
assert.isFunction('handler.onClose', _.get(handler, 'onClose'));
|
||||||
|
const subscribeMessage = {
|
||||||
|
type: 'subscribe',
|
||||||
|
channel: 'orderbook',
|
||||||
|
payload: subscriptionOpts,
|
||||||
|
};
|
||||||
|
this._getConnection((error, connection) => {
|
||||||
|
if (!_.isUndefined(error)) {
|
||||||
|
handler.onError(this, error);
|
||||||
|
} else if (!_.isUndefined(connection) && connection.connected) {
|
||||||
|
connection.on(ConnectionEventType.Error, wsError => {
|
||||||
|
handler.onError(this, wsError);
|
||||||
|
});
|
||||||
|
connection.on(ConnectionEventType.Close, () => {
|
||||||
|
handler.onClose(this);
|
||||||
|
});
|
||||||
|
connection.on(ConnectionEventType.Message, message => {
|
||||||
|
this._handleWebSocketMessage(message, handler);
|
||||||
|
});
|
||||||
|
connection.sendUTF(JSON.stringify(subscribeMessage));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Close the websocket and stop receiving updates
|
||||||
|
*/
|
||||||
|
public close() {
|
||||||
|
if (!_.isUndefined(this.connectionIfExists)) {
|
||||||
|
this.connectionIfExists.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private _getConnection(callback: (error?: Error, connection?: WebSocket.connection) => void) {
|
||||||
|
if (!_.isUndefined(this.connectionIfExists) && this.connectionIfExists.connected) {
|
||||||
|
callback(undefined, this.connectionIfExists);
|
||||||
|
} else {
|
||||||
|
this.client.on(ClientEventType.Connect, connection => {
|
||||||
|
this.connectionIfExists = connection;
|
||||||
|
callback(undefined, this.connectionIfExists);
|
||||||
|
});
|
||||||
|
this.client.on(ClientEventType.ConnectFailed, error => {
|
||||||
|
callback(error, undefined);
|
||||||
|
});
|
||||||
|
this.client.connect(this.apiEndpointUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private _handleWebSocketMessage(message: WebSocket.IMessage, handler: OrderbookChannelHandler): void {
|
||||||
|
if (!_.isUndefined(message.utf8Data)) {
|
||||||
|
try {
|
||||||
|
const utf8Data = message.utf8Data;
|
||||||
|
const parserResult = orderbookChannelMessageParsers.parser(utf8Data);
|
||||||
|
const type = parserResult.type;
|
||||||
|
switch (parserResult.type) {
|
||||||
|
case (OrderbookChannelMessageTypes.Snapshot): {
|
||||||
|
handler.onSnapshot(this, parserResult.payload);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case (OrderbookChannelMessageTypes.Update): {
|
||||||
|
handler.onUpdate(this, parserResult.payload);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
handler.onError(this, new Error(`Message has missing a type parameter: ${utf8Data}`));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
handler.onError(this, error);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
handler.onError(this, new Error(`Message does not contain utf8Data`));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
5
packages/connect/test/fixtures/standard_relayer_api/fees.json
vendored
Normal file
5
packages/connect/test/fixtures/standard_relayer_api/fees.json
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"feeRecipient": "0x323b5d4c32345ced77393b3530b1eed0f346429d",
|
||||||
|
"makerFee": "10000000000000000",
|
||||||
|
"takerFee": "30000000000000000"
|
||||||
|
}
|
8
packages/connect/test/fixtures/standard_relayer_api/fees.ts
vendored
Normal file
8
packages/connect/test/fixtures/standard_relayer_api/fees.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import {BigNumber} from 'bignumber.js';
|
||||||
|
import {FeesResponse} from '../../../src/types';
|
||||||
|
|
||||||
|
export const feesResponse: FeesResponse = {
|
||||||
|
feeRecipient: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
makerFee: new BigNumber('10000000000000000'),
|
||||||
|
takerFee: new BigNumber('30000000000000000'),
|
||||||
|
};
|
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"maker": "0x9e56625509c2f60af937f23b7b532600390e8c8b",
|
||||||
|
"taker": "0xa2b31dacf30a9c50ca473337c01d8a201ae33e32",
|
||||||
|
"makerFee": "100000000000000",
|
||||||
|
"takerFee": "200000000000000",
|
||||||
|
"makerTokenAmount": "10000000000000000",
|
||||||
|
"takerTokenAmount": "20000000000000000",
|
||||||
|
"makerTokenAddress": "0x323b5d4c32345ced77393b3530b1eed0f346429d",
|
||||||
|
"takerTokenAddress": "0xef7fff64389b814a946f3e92105513705ca6b990",
|
||||||
|
"salt": "256",
|
||||||
|
"feeRecipient": "0xb046140686d052fff581f63f8136cce132e857da",
|
||||||
|
"exchangeContractAddress": "0x12459c951127e0c374ff9105dda097662a027093",
|
||||||
|
"expirationUnixTimestampSec": "42",
|
||||||
|
"ecSignature": {
|
||||||
|
"v": 27,
|
||||||
|
"r": "0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33",
|
||||||
|
"s": "0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
import {BigNumber} from 'bignumber.js';
|
||||||
|
|
||||||
|
export const orderResponse = {
|
||||||
|
maker: '0x9e56625509c2f60af937f23b7b532600390e8c8b',
|
||||||
|
taker: '0xa2b31dacf30a9c50ca473337c01d8a201ae33e32',
|
||||||
|
makerFee: new BigNumber('100000000000000'),
|
||||||
|
takerFee: new BigNumber('200000000000000'),
|
||||||
|
makerTokenAmount: new BigNumber('10000000000000000'),
|
||||||
|
takerTokenAmount: new BigNumber('20000000000000000'),
|
||||||
|
makerTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
takerTokenAddress: '0xef7fff64389b814a946f3e92105513705ca6b990',
|
||||||
|
salt: new BigNumber('256'),
|
||||||
|
feeRecipient: '0xb046140686d052fff581f63f8136cce132e857da',
|
||||||
|
exchangeContractAddress: '0x12459c951127e0c374ff9105dda097662a027093',
|
||||||
|
expirationUnixTimestampSec: new BigNumber('42'),
|
||||||
|
ecSignature: {
|
||||||
|
v: 27,
|
||||||
|
r: '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33',
|
||||||
|
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
|
||||||
|
},
|
||||||
|
};
|
44
packages/connect/test/fixtures/standard_relayer_api/orderbook.json
vendored
Normal file
44
packages/connect/test/fixtures/standard_relayer_api/orderbook.json
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"bids": [
|
||||||
|
{
|
||||||
|
"maker": "0x9e56625509c2f60af937f23b7b532600390e8c8b",
|
||||||
|
"taker": "0xa2b31dacf30a9c50ca473337c01d8a201ae33e32",
|
||||||
|
"makerFee": "100000000000000",
|
||||||
|
"takerFee": "200000000000000",
|
||||||
|
"makerTokenAmount": "10000000000000000",
|
||||||
|
"takerTokenAmount": "20000000000000000",
|
||||||
|
"makerTokenAddress": "0x323b5d4c32345ced77393b3530b1eed0f346429d",
|
||||||
|
"takerTokenAddress": "0xef7fff64389b814a946f3e92105513705ca6b990",
|
||||||
|
"salt": "256",
|
||||||
|
"feeRecipient": "0xb046140686d052fff581f63f8136cce132e857da",
|
||||||
|
"exchangeContractAddress": "0x12459c951127e0c374ff9105dda097662a027093",
|
||||||
|
"expirationUnixTimestampSec": "42",
|
||||||
|
"ecSignature": {
|
||||||
|
"v": 27,
|
||||||
|
"r": "0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33",
|
||||||
|
"s": "0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"asks": [
|
||||||
|
{
|
||||||
|
"maker": "0x9e56625509c2f60af937f23b7b532600390e8c8b",
|
||||||
|
"taker": "0xa2b31dacf30a9c50ca473337c01d8a201ae33e32",
|
||||||
|
"makerFee": "100000000000000",
|
||||||
|
"takerFee": "200000000000000",
|
||||||
|
"makerTokenAmount": "10000000000000000",
|
||||||
|
"takerTokenAmount": "20000000000000000",
|
||||||
|
"makerTokenAddress": "0x323b5d4c32345ced77393b3530b1eed0f346429d",
|
||||||
|
"takerTokenAddress": "0xef7fff64389b814a946f3e92105513705ca6b990",
|
||||||
|
"salt": "256",
|
||||||
|
"feeRecipient": "0xb046140686d052fff581f63f8136cce132e857da",
|
||||||
|
"exchangeContractAddress": "0x12459c951127e0c374ff9105dda097662a027093",
|
||||||
|
"expirationUnixTimestampSec": "42",
|
||||||
|
"ecSignature": {
|
||||||
|
"v": 27,
|
||||||
|
"r": "0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33",
|
||||||
|
"s": "0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
46
packages/connect/test/fixtures/standard_relayer_api/orderbook.ts
vendored
Normal file
46
packages/connect/test/fixtures/standard_relayer_api/orderbook.ts
vendored
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import {BigNumber} from 'bignumber.js';
|
||||||
|
|
||||||
|
export const orderbookResponse = {
|
||||||
|
bids: [
|
||||||
|
{
|
||||||
|
maker: '0x9e56625509c2f60af937f23b7b532600390e8c8b',
|
||||||
|
taker: '0xa2b31dacf30a9c50ca473337c01d8a201ae33e32',
|
||||||
|
makerFee: new BigNumber('100000000000000'),
|
||||||
|
takerFee: new BigNumber('200000000000000'),
|
||||||
|
makerTokenAmount: new BigNumber('10000000000000000'),
|
||||||
|
takerTokenAmount: new BigNumber('20000000000000000'),
|
||||||
|
makerTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
takerTokenAddress: '0xef7fff64389b814a946f3e92105513705ca6b990',
|
||||||
|
salt: new BigNumber('256'),
|
||||||
|
feeRecipient: '0xb046140686d052fff581f63f8136cce132e857da',
|
||||||
|
exchangeContractAddress: '0x12459c951127e0c374ff9105dda097662a027093',
|
||||||
|
expirationUnixTimestampSec: new BigNumber('42'),
|
||||||
|
ecSignature: {
|
||||||
|
v: 27,
|
||||||
|
r: '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33',
|
||||||
|
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
asks: [
|
||||||
|
{
|
||||||
|
maker: '0x9e56625509c2f60af937f23b7b532600390e8c8b',
|
||||||
|
taker: '0xa2b31dacf30a9c50ca473337c01d8a201ae33e32',
|
||||||
|
makerFee: new BigNumber('100000000000000'),
|
||||||
|
takerFee: new BigNumber('200000000000000'),
|
||||||
|
makerTokenAmount: new BigNumber('10000000000000000'),
|
||||||
|
takerTokenAmount: new BigNumber('20000000000000000'),
|
||||||
|
makerTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
takerTokenAddress: '0xef7fff64389b814a946f3e92105513705ca6b990',
|
||||||
|
salt: new BigNumber('256'),
|
||||||
|
feeRecipient: '0xb046140686d052fff581f63f8136cce132e857da',
|
||||||
|
exchangeContractAddress: '0x12459c951127e0c374ff9105dda097662a027093',
|
||||||
|
expirationUnixTimestampSec: new BigNumber('42'),
|
||||||
|
ecSignature: {
|
||||||
|
v: 27,
|
||||||
|
r: '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33',
|
||||||
|
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
21
packages/connect/test/fixtures/standard_relayer_api/orders.json
vendored
Normal file
21
packages/connect/test/fixtures/standard_relayer_api/orders.json
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"maker": "0x9e56625509c2f60af937f23b7b532600390e8c8b",
|
||||||
|
"taker": "0xa2b31dacf30a9c50ca473337c01d8a201ae33e32",
|
||||||
|
"makerFee": "100000000000000",
|
||||||
|
"takerFee": "200000000000000",
|
||||||
|
"makerTokenAmount": "10000000000000000",
|
||||||
|
"takerTokenAmount": "20000000000000000",
|
||||||
|
"makerTokenAddress": "0x323b5d4c32345ced77393b3530b1eed0f346429d",
|
||||||
|
"takerTokenAddress": "0xef7fff64389b814a946f3e92105513705ca6b990",
|
||||||
|
"salt": "256",
|
||||||
|
"feeRecipient": "0x9e56625509c2f60af937f23b7b532600390e8c8b",
|
||||||
|
"exchangeContractAddress": "0x9e56625509c2f60af937f23b7b532600390e8c8b",
|
||||||
|
"expirationUnixTimestampSec": "42",
|
||||||
|
"ecSignature": {
|
||||||
|
"v": 27,
|
||||||
|
"r": "0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33",
|
||||||
|
"s": "0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
23
packages/connect/test/fixtures/standard_relayer_api/orders.ts
vendored
Normal file
23
packages/connect/test/fixtures/standard_relayer_api/orders.ts
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import {BigNumber} from 'bignumber.js';
|
||||||
|
|
||||||
|
export const ordersResponse = [
|
||||||
|
{
|
||||||
|
maker: '0x9e56625509c2f60af937f23b7b532600390e8c8b',
|
||||||
|
taker: '0xa2b31dacf30a9c50ca473337c01d8a201ae33e32',
|
||||||
|
makerFee: new BigNumber('100000000000000'),
|
||||||
|
takerFee: new BigNumber('200000000000000'),
|
||||||
|
makerTokenAmount: new BigNumber('10000000000000000'),
|
||||||
|
takerTokenAmount: new BigNumber('20000000000000000'),
|
||||||
|
makerTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
takerTokenAddress: '0xef7fff64389b814a946f3e92105513705ca6b990',
|
||||||
|
salt: new BigNumber('256'),
|
||||||
|
feeRecipient: '0x9e56625509c2f60af937f23b7b532600390e8c8b',
|
||||||
|
exchangeContractAddress: '0x9e56625509c2f60af937f23b7b532600390e8c8b',
|
||||||
|
expirationUnixTimestampSec: new BigNumber('42'),
|
||||||
|
ecSignature: {
|
||||||
|
v: 27,
|
||||||
|
r: '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33',
|
||||||
|
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
17
packages/connect/test/fixtures/standard_relayer_api/snapshot_orderbook_channel_message.ts
vendored
Normal file
17
packages/connect/test/fixtures/standard_relayer_api/snapshot_orderbook_channel_message.ts
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import * as orderbookJSON from './orderbook.json';
|
||||||
|
|
||||||
|
const orderbookJsonString = JSON.stringify(orderbookJSON);
|
||||||
|
|
||||||
|
export const snapshotOrderbookChannelMessage = `{
|
||||||
|
"type": "snapshot",
|
||||||
|
"channel": "orderbook",
|
||||||
|
"channelId": 1,
|
||||||
|
"payload": ${orderbookJsonString}
|
||||||
|
}`;
|
||||||
|
|
||||||
|
export const malformedSnapshotOrderbookChannelMessage = `{
|
||||||
|
"type": "snapshot",
|
||||||
|
"channel": "orderbook",
|
||||||
|
"channelId": 1,
|
||||||
|
"payload": {}
|
||||||
|
}`;
|
16
packages/connect/test/fixtures/standard_relayer_api/token_pairs.json
vendored
Normal file
16
packages/connect/test/fixtures/standard_relayer_api/token_pairs.json
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"tokenA": {
|
||||||
|
"address": "0x323b5d4c32345ced77393b3530b1eed0f346429d",
|
||||||
|
"minAmount": "0",
|
||||||
|
"maxAmount": "10000000000000000000",
|
||||||
|
"precision": 5
|
||||||
|
},
|
||||||
|
"tokenB": {
|
||||||
|
"address": "0xef7fff64389b814a946f3e92105513705ca6b990",
|
||||||
|
"minAmount": "0",
|
||||||
|
"maxAmount": "50000000000000000000",
|
||||||
|
"precision": 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
19
packages/connect/test/fixtures/standard_relayer_api/token_pairs.ts
vendored
Normal file
19
packages/connect/test/fixtures/standard_relayer_api/token_pairs.ts
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import {BigNumber} from 'bignumber.js';
|
||||||
|
import {TokenPairsItem} from '../../../src/types';
|
||||||
|
|
||||||
|
export const tokenPairsResponse: TokenPairsItem[] = [
|
||||||
|
{
|
||||||
|
tokenA: {
|
||||||
|
address: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
minAmount: new BigNumber(0),
|
||||||
|
maxAmount: new BigNumber('10000000000000000000'),
|
||||||
|
precision: 5,
|
||||||
|
},
|
||||||
|
tokenB: {
|
||||||
|
address: '0xef7fff64389b814a946f3e92105513705ca6b990',
|
||||||
|
minAmount: new BigNumber(0),
|
||||||
|
maxAmount: new BigNumber('50000000000000000000'),
|
||||||
|
precision: 5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
10
packages/connect/test/fixtures/standard_relayer_api/unknown_orderbook_channel_message.ts
vendored
Normal file
10
packages/connect/test/fixtures/standard_relayer_api/unknown_orderbook_channel_message.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import * as orderResponseJSON from './order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f.json';
|
||||||
|
|
||||||
|
const orderJSONString = JSON.stringify(orderResponseJSON);
|
||||||
|
|
||||||
|
export const unknownOrderbookChannelMessage = `{
|
||||||
|
"type": "superGoodUpdate",
|
||||||
|
"channel": "orderbook",
|
||||||
|
"channelId": 1,
|
||||||
|
"payload": ${orderJSONString}
|
||||||
|
}`;
|
17
packages/connect/test/fixtures/standard_relayer_api/update_orderbook_channel_message.ts
vendored
Normal file
17
packages/connect/test/fixtures/standard_relayer_api/update_orderbook_channel_message.ts
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import * as orderResponseJSON from './order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f.json';
|
||||||
|
|
||||||
|
const orderJSONString = JSON.stringify(orderResponseJSON);
|
||||||
|
|
||||||
|
export const updateOrderbookChannelMessage = `{
|
||||||
|
"type": "update",
|
||||||
|
"channel": "orderbook",
|
||||||
|
"channelId": 1,
|
||||||
|
"payload": ${orderJSONString}
|
||||||
|
}`;
|
||||||
|
|
||||||
|
export const malformedUpdateOrderbookChannelMessage = `{
|
||||||
|
"type": "update",
|
||||||
|
"channel": "orderbook",
|
||||||
|
"channelId": 1,
|
||||||
|
"payload": {}
|
||||||
|
}`;
|
130
packages/connect/test/http_client_test.ts
Normal file
130
packages/connect/test/http_client_test.ts
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
import 'mocha';
|
||||||
|
import * as dirtyChai from 'dirty-chai';
|
||||||
|
import * as chai from 'chai';
|
||||||
|
import * as chaiAsPromised from 'chai-as-promised';
|
||||||
|
import * as fetchMock from 'fetch-mock';
|
||||||
|
import {BigNumber} from 'bignumber.js';
|
||||||
|
import {HttpClient} from '../src/index';
|
||||||
|
import {feesResponse} from './fixtures/standard_relayer_api/fees';
|
||||||
|
import {
|
||||||
|
orderResponse,
|
||||||
|
} from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f';
|
||||||
|
import {ordersResponse} from './fixtures/standard_relayer_api/orders';
|
||||||
|
import {tokenPairsResponse} from './fixtures/standard_relayer_api/token_pairs';
|
||||||
|
import {orderbookResponse} from './fixtures/standard_relayer_api/orderbook';
|
||||||
|
import * as feesResponseJSON from './fixtures/standard_relayer_api/fees.json';
|
||||||
|
// tslint:disable-next-line:max-line-length
|
||||||
|
import * as orderResponseJSON from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f.json';
|
||||||
|
import * as ordersResponseJSON from './fixtures/standard_relayer_api/orders.json';
|
||||||
|
import * as tokenPairsResponseJSON from './fixtures/standard_relayer_api/token_pairs.json';
|
||||||
|
import * as orderbookJSON from './fixtures/standard_relayer_api/orderbook.json';
|
||||||
|
|
||||||
|
chai.config.includeStack = true;
|
||||||
|
chai.use(dirtyChai);
|
||||||
|
chai.use(chaiAsPromised);
|
||||||
|
const expect = chai.expect;
|
||||||
|
|
||||||
|
describe('HttpClient', () => {
|
||||||
|
const relayUrl = 'https://example.com';
|
||||||
|
const relayerClient = new HttpClient(relayUrl);
|
||||||
|
afterEach(() => {
|
||||||
|
fetchMock.restore();
|
||||||
|
});
|
||||||
|
describe('#getTokenPairsAsync', () => {
|
||||||
|
const url = `${relayUrl}/v0/token_pairs`;
|
||||||
|
it('gets token pairs', async () => {
|
||||||
|
fetchMock.get(url, tokenPairsResponseJSON);
|
||||||
|
const tokenPairs = await relayerClient.getTokenPairsAsync();
|
||||||
|
expect(tokenPairs).to.be.deep.equal(tokenPairsResponse);
|
||||||
|
});
|
||||||
|
it('gets specfic token pairs for request', async () => {
|
||||||
|
const tokenAddress = '0x323b5d4c32345ced77393b3530b1eed0f346429d';
|
||||||
|
const tokenPairsRequest = {
|
||||||
|
tokenA: tokenAddress,
|
||||||
|
};
|
||||||
|
const urlWithQuery = `${url}?tokenA=${tokenAddress}`;
|
||||||
|
fetchMock.get(urlWithQuery, tokenPairsResponseJSON);
|
||||||
|
const tokenPairs = await relayerClient.getTokenPairsAsync(tokenPairsRequest);
|
||||||
|
expect(tokenPairs).to.be.deep.equal(tokenPairsResponse);
|
||||||
|
});
|
||||||
|
it('throws an error for invalid JSON response', async () => {
|
||||||
|
fetchMock.get(url, {test: 'dummy'});
|
||||||
|
expect(relayerClient.getTokenPairsAsync()).to.be.rejected();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#getOrdersAsync', () => {
|
||||||
|
const url = `${relayUrl}/v0/orders`;
|
||||||
|
it('gets orders', async () => {
|
||||||
|
fetchMock.get(url, ordersResponseJSON);
|
||||||
|
const orders = await relayerClient.getOrdersAsync();
|
||||||
|
expect(orders).to.be.deep.equal(ordersResponse);
|
||||||
|
});
|
||||||
|
it('gets specfic orders for request', async () => {
|
||||||
|
const tokenAddress = '0x323b5d4c32345ced77393b3530b1eed0f346429d';
|
||||||
|
const ordersRequest = {
|
||||||
|
tokenA: tokenAddress,
|
||||||
|
};
|
||||||
|
const urlWithQuery = `${url}?tokenA=${tokenAddress}`;
|
||||||
|
fetchMock.get(urlWithQuery, ordersResponseJSON);
|
||||||
|
const orders = await relayerClient.getOrdersAsync(ordersRequest);
|
||||||
|
expect(orders).to.be.deep.equal(ordersResponse);
|
||||||
|
});
|
||||||
|
it('throws an error for invalid JSON response', async () => {
|
||||||
|
fetchMock.get(url, {test: 'dummy'});
|
||||||
|
expect(relayerClient.getOrdersAsync()).to.be.rejected();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#getOrderAsync', () => {
|
||||||
|
const orderHash = '0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f';
|
||||||
|
const url = `${relayUrl}/v0/order/${orderHash}`;
|
||||||
|
it('gets order', async () => {
|
||||||
|
fetchMock.get(url, orderResponseJSON);
|
||||||
|
const order = await relayerClient.getOrderAsync(orderHash);
|
||||||
|
expect(order).to.be.deep.equal(orderResponse);
|
||||||
|
});
|
||||||
|
it('throws an error for invalid JSON response', async () => {
|
||||||
|
fetchMock.get(url, {test: 'dummy'});
|
||||||
|
expect(relayerClient.getOrderAsync(orderHash)).to.be.rejected();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#getOrderBookAsync', () => {
|
||||||
|
const request = {
|
||||||
|
baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
quoteTokenAddress: '0xa2b31dacf30a9c50ca473337c01d8a201ae33e32',
|
||||||
|
};
|
||||||
|
// tslint:disable-next-line:max-line-length
|
||||||
|
const url = `${relayUrl}/v0/orderbook?baseTokenAddress=${request.baseTokenAddress}"eTokenAddress=${request.quoteTokenAddress}`;
|
||||||
|
it('gets order book', async () => {
|
||||||
|
fetchMock.get(url, orderbookJSON);
|
||||||
|
const orderbook = await relayerClient.getOrderbookAsync(request);
|
||||||
|
expect(orderbook).to.be.deep.equal(orderbookResponse);
|
||||||
|
});
|
||||||
|
it('throws an error for invalid JSON response', async () => {
|
||||||
|
fetchMock.get(url, {test: 'dummy'});
|
||||||
|
expect(relayerClient.getOrderbookAsync(request)).to.be.rejected();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#getFeesAsync', () => {
|
||||||
|
const request = {
|
||||||
|
exchangeContractAddress: '0x12459c951127e0c374ff9105dda097662a027093',
|
||||||
|
maker: '0x9e56625509c2f60af937f23b7b532600390e8c8b',
|
||||||
|
taker: '0xa2b31dacf30a9c50ca473337c01d8a201ae33e32',
|
||||||
|
makerTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
takerTokenAddress: '0xef7fff64389b814a946f3e92105513705ca6b990',
|
||||||
|
makerTokenAmount: new BigNumber('10000000000000000000'),
|
||||||
|
takerTokenAmount: new BigNumber('30000000000000000000'),
|
||||||
|
salt: new BigNumber('256'),
|
||||||
|
expirationUnixTimestampSec: new BigNumber('42'),
|
||||||
|
};
|
||||||
|
const url = `${relayUrl}/v0/fees`;
|
||||||
|
it('gets fees', async () => {
|
||||||
|
fetchMock.post(url, feesResponseJSON);
|
||||||
|
const fees = await relayerClient.getFeesAsync(request);
|
||||||
|
expect(fees).to.be.deep.equal(feesResponse);
|
||||||
|
});
|
||||||
|
it('throws an error for invalid JSON response', async () => {
|
||||||
|
fetchMock.post(url, {test: 'dummy'});
|
||||||
|
expect(relayerClient.getFeesAsync(request)).to.be.rejected();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,66 @@
|
|||||||
|
import 'mocha';
|
||||||
|
import * as dirtyChai from 'dirty-chai';
|
||||||
|
import * as chai from 'chai';
|
||||||
|
import {orderbookChannelMessageParsers} from '../src/utils/orderbook_channel_message_parsers';
|
||||||
|
import {
|
||||||
|
snapshotOrderbookChannelMessage,
|
||||||
|
malformedSnapshotOrderbookChannelMessage,
|
||||||
|
} from './fixtures/standard_relayer_api/snapshot_orderbook_channel_message';
|
||||||
|
import {
|
||||||
|
updateOrderbookChannelMessage,
|
||||||
|
malformedUpdateOrderbookChannelMessage,
|
||||||
|
} from './fixtures/standard_relayer_api/update_orderbook_channel_message';
|
||||||
|
import {unknownOrderbookChannelMessage} from './fixtures/standard_relayer_api/unknown_orderbook_channel_message';
|
||||||
|
import {orderbookResponse} from './fixtures/standard_relayer_api/orderbook';
|
||||||
|
// tslint:disable-next-line:max-line-length
|
||||||
|
import {orderResponse} from './fixtures/standard_relayer_api/order/0xabc67323774bdbd24d94f977fa9ac94a50f016026fd13f42990861238897721f';
|
||||||
|
|
||||||
|
chai.config.includeStack = true;
|
||||||
|
chai.use(dirtyChai);
|
||||||
|
const expect = chai.expect;
|
||||||
|
|
||||||
|
describe('orderbookChannelMessageParsers', () => {
|
||||||
|
describe('#parser', () => {
|
||||||
|
it('parses snapshot messages', () => {
|
||||||
|
const snapshotMessage = orderbookChannelMessageParsers.parser(snapshotOrderbookChannelMessage);
|
||||||
|
expect(snapshotMessage.type).to.be.equal('snapshot');
|
||||||
|
expect(snapshotMessage.payload).to.be.deep.equal(orderbookResponse);
|
||||||
|
});
|
||||||
|
it('parses update messages', () => {
|
||||||
|
const updateMessage = orderbookChannelMessageParsers.parser(updateOrderbookChannelMessage);
|
||||||
|
expect(updateMessage.type).to.be.equal('update');
|
||||||
|
expect(updateMessage.payload).to.be.deep.equal(orderResponse);
|
||||||
|
});
|
||||||
|
it('returns unknown message for messages with unsupported types', () => {
|
||||||
|
const unknownMessage = orderbookChannelMessageParsers.parser(unknownOrderbookChannelMessage);
|
||||||
|
expect(unknownMessage.type).to.be.equal('unknown');
|
||||||
|
expect(unknownMessage.payload).to.be.undefined();
|
||||||
|
});
|
||||||
|
it('throws when message does not include a type', () => {
|
||||||
|
const typelessMessage = `{
|
||||||
|
"channel": "orderbook",
|
||||||
|
"channelId": 1,
|
||||||
|
"payload": {}
|
||||||
|
}`;
|
||||||
|
const badCall = () => orderbookChannelMessageParsers.parser(typelessMessage);
|
||||||
|
expect(badCall).throws(`Message is missing a type parameter: ${typelessMessage}`);
|
||||||
|
});
|
||||||
|
it('throws when snapshot message has malformed payload', () => {
|
||||||
|
const badCall = () =>
|
||||||
|
orderbookChannelMessageParsers.parser(malformedSnapshotOrderbookChannelMessage);
|
||||||
|
// tslint:disable-next-line:max-line-length
|
||||||
|
const errMsg = 'Validation errors: instance.payload requires property "bids", instance.payload requires property "asks"';
|
||||||
|
expect(badCall).throws(errMsg);
|
||||||
|
});
|
||||||
|
it('throws when update message has malformed payload', () => {
|
||||||
|
const badCall = () =>
|
||||||
|
orderbookChannelMessageParsers.parser(malformedUpdateOrderbookChannelMessage);
|
||||||
|
expect(badCall).throws(/^Expected message to conform to schema/);
|
||||||
|
});
|
||||||
|
it('throws when input message is not valid JSON', () => {
|
||||||
|
const nonJsonString = 'h93b{sdfs9fsd f';
|
||||||
|
const badCall = () => orderbookChannelMessageParsers.parser(nonJsonString);
|
||||||
|
expect(badCall).throws('Unexpected token h in JSON at position 0');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
46
packages/connect/test/ws_orderbook_channel_test.ts
Normal file
46
packages/connect/test/ws_orderbook_channel_test.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import 'mocha';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
import * as dirtyChai from 'dirty-chai';
|
||||||
|
import * as chai from 'chai';
|
||||||
|
import {
|
||||||
|
WebSocketOrderbookChannel,
|
||||||
|
} from '../src/index';
|
||||||
|
|
||||||
|
chai.config.includeStack = true;
|
||||||
|
chai.use(dirtyChai);
|
||||||
|
const expect = chai.expect;
|
||||||
|
|
||||||
|
describe('WebSocketOrderbookChannel', () => {
|
||||||
|
const websocketUrl = 'ws://localhost:8080';
|
||||||
|
const orderbookChannel = new WebSocketOrderbookChannel(websocketUrl);
|
||||||
|
const subscriptionOpts = {
|
||||||
|
baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
quoteTokenAddress: '0xef7fff64389b814a946f3e92105513705ca6b990',
|
||||||
|
snapshot: true,
|
||||||
|
limit: 100,
|
||||||
|
};
|
||||||
|
const emptyOrderbookChannelHandler = {
|
||||||
|
onSnapshot: () => { _.noop(); },
|
||||||
|
onUpdate: () => { _.noop(); },
|
||||||
|
onError: () => { _.noop(); },
|
||||||
|
onClose: () => { _.noop(); },
|
||||||
|
};
|
||||||
|
describe('#subscribe', () => {
|
||||||
|
it('throws when subscriptionOpts does not conform to schema', () => {
|
||||||
|
const badSubscribeCall = orderbookChannel.subscribe.bind(
|
||||||
|
orderbookChannel, {}, emptyOrderbookChannelHandler);
|
||||||
|
// 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"');
|
||||||
|
});
|
||||||
|
it('throws when handler has the incorrect members', () => {
|
||||||
|
const badSubscribeCall = orderbookChannel.subscribe.bind(orderbookChannel, subscriptionOpts, {});
|
||||||
|
expect(badSubscribeCall)
|
||||||
|
.throws('Expected handler.onSnapshot to be of type function, encountered: undefined');
|
||||||
|
});
|
||||||
|
it('does not throw when inputs are of correct types', () => {
|
||||||
|
const goodSubscribeCall = orderbookChannel.subscribe.bind(
|
||||||
|
orderbookChannel, subscriptionOpts, emptyOrderbookChannelHandler);
|
||||||
|
expect(goodSubscribeCall).to.not.throw();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
19
packages/connect/tsconfig.json
Normal file
19
packages/connect/tsconfig.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "es5",
|
||||||
|
"lib": [ "es2015", "dom" ],
|
||||||
|
"outDir": "lib",
|
||||||
|
"sourceMap": true,
|
||||||
|
"declaration": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"strictNullChecks": true
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"./src/**/*",
|
||||||
|
"./test/**/*",
|
||||||
|
"../../node_modules/chai-as-promised-typescript-typings/index.d.ts",
|
||||||
|
"../../node_modules/chai-typescript-typings/index.d.ts",
|
||||||
|
"../../node_modules/web3-typescript-typings/index.d.ts"
|
||||||
|
]
|
||||||
|
}
|
5
packages/connect/tslint.json
Normal file
5
packages/connect/tslint.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"extends": [
|
||||||
|
"@0xproject/tslint-config"
|
||||||
|
]
|
||||||
|
}
|
5
packages/json-schemas/CHANGELOG.md
Normal file
5
packages/json-schemas/CHANGELOG.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# CHANGELOG
|
||||||
|
|
||||||
|
v0.6.7 - _Nov. 14, 2017_
|
||||||
|
------------------------
|
||||||
|
* Re-publish JSON-schema previously published under NPM package 0x-json-schemas
|
24
packages/json-schemas/README.md
Normal file
24
packages/json-schemas/README.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
json-schemas
|
||||||
|
------------
|
||||||
|
|
||||||
|
Contains 0x-related json schemas
|
||||||
|
|
||||||
|
## Install:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install @0xproject/json-schemas --save
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage:
|
||||||
|
```
|
||||||
|
import {SchemaValidator, ValidatorResult, schemas} from '@0xproject/json-schemas';
|
||||||
|
|
||||||
|
const {orderSchema} = schemas;
|
||||||
|
const validator = new SchemaValidator();
|
||||||
|
|
||||||
|
const order = {
|
||||||
|
...
|
||||||
|
};
|
||||||
|
const validatorResult: ValidatorResult = validator.validate(order, orderSchema); // Contains all errors
|
||||||
|
const isValid: boolean = validator.isValid(order, orderSchema); // Only returns boolean
|
||||||
|
```
|
46
packages/json-schemas/package.json
Normal file
46
packages/json-schemas/package.json
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"name": "@0xproject/json-schemas",
|
||||||
|
"version": "0.6.7",
|
||||||
|
"description": "0x-related json schemas",
|
||||||
|
"main": "lib/src/index.js",
|
||||||
|
"types": "lib/src/index.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"lint": "tslint src/*.ts test/*.ts",
|
||||||
|
"test": "run-s clean build run_mocha",
|
||||||
|
"test:circleci": "yarn test",
|
||||||
|
"run_mocha": "mocha lib/test/**/*_test.js",
|
||||||
|
"clean": "shx rm -rf _bundles lib test_temp",
|
||||||
|
"build": "tsc"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/0xProject/0x.js.git"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/0xProject/0x.js/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/0xProject/0x.js/packages/json-schemas/README.md",
|
||||||
|
"dependencies": {
|
||||||
|
"es6-promisify": "^5.0.0",
|
||||||
|
"jsonschema": "^1.2.0",
|
||||||
|
"lodash.values": "^4.3.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@0xproject/tslint-config": "^0.1.0",
|
||||||
|
"@types/lodash.foreach": "^4.5.3",
|
||||||
|
"@types/lodash.values": "^4.3.3",
|
||||||
|
"@types/mocha": "^2.2.42",
|
||||||
|
"bignumber.js": "^4.0.2",
|
||||||
|
"chai": "^4.1.1",
|
||||||
|
"chai-typescript-typings": "^0.0.1",
|
||||||
|
"dirty-chai": "^2.0.1",
|
||||||
|
"lodash.foreach": "^4.5.0",
|
||||||
|
"mocha": "^4.0.1",
|
||||||
|
"npm-run-all": "^4.1.1",
|
||||||
|
"shx": "^0.2.2",
|
||||||
|
"tslint": "5.8.0",
|
||||||
|
"typescript": "~2.6.1"
|
||||||
|
}
|
||||||
|
}
|
11
packages/json-schemas/schemas/basic_type_schemas.ts
Normal file
11
packages/json-schemas/schemas/basic_type_schemas.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
export const addressSchema = {
|
||||||
|
id: '/Address',
|
||||||
|
type: 'string',
|
||||||
|
pattern: '^0x[0-9a-f]{40}$',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const numberSchema = {
|
||||||
|
id: '/Number',
|
||||||
|
type: 'string',
|
||||||
|
pattern: '^\\d+(\\.\\d+)?$',
|
||||||
|
};
|
20
packages/json-schemas/schemas/ec_signature_schema.ts
Normal file
20
packages/json-schemas/schemas/ec_signature_schema.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
export const ecSignatureParameterSchema = {
|
||||||
|
id: '/ECSignatureParameter',
|
||||||
|
type: 'string',
|
||||||
|
pattern: '^0[xX][0-9A-Fa-f]{64}$',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ecSignatureSchema = {
|
||||||
|
id: '/ECSignature',
|
||||||
|
properties: {
|
||||||
|
v: {
|
||||||
|
type: 'number',
|
||||||
|
minimum: 27,
|
||||||
|
maximum: 28,
|
||||||
|
},
|
||||||
|
r: {$ref: '/ECSignatureParameter'},
|
||||||
|
s: {$ref: '/ECSignatureParameter'},
|
||||||
|
},
|
||||||
|
required: ['v', 'r', 's'],
|
||||||
|
type: 'object',
|
||||||
|
};
|
11
packages/json-schemas/schemas/index_filter_values_schema.ts
Normal file
11
packages/json-schemas/schemas/index_filter_values_schema.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
export const indexFilterValuesSchema = {
|
||||||
|
id: '/IndexFilterValues',
|
||||||
|
additionalProperties: {
|
||||||
|
oneOf: [
|
||||||
|
{$ref: '/Number'},
|
||||||
|
{$ref: '/Address'},
|
||||||
|
{$ref: '/OrderHashSchema'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
type: 'object',
|
||||||
|
};
|
12
packages/json-schemas/schemas/order_cancel_schema.ts
Normal file
12
packages/json-schemas/schemas/order_cancel_schema.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
export const orderCancellationRequestsSchema = {
|
||||||
|
id: '/OrderCancellationRequests',
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
properties: {
|
||||||
|
order: {$ref: '/Order'},
|
||||||
|
takerTokenCancelAmount: {$ref: '/Number'},
|
||||||
|
},
|
||||||
|
required: ['order', 'takerTokenCancelAmount'],
|
||||||
|
type: 'object',
|
||||||
|
},
|
||||||
|
};
|
@ -0,0 +1,12 @@
|
|||||||
|
export const orderFillOrKillRequestsSchema = {
|
||||||
|
id: '/OrderFillOrKillRequests',
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
properties: {
|
||||||
|
signedOrder: {$ref: '/SignedOrder'},
|
||||||
|
fillTakerAmount: {$ref: '/Number'},
|
||||||
|
},
|
||||||
|
required: ['signedOrder', 'fillTakerAmount'],
|
||||||
|
type: 'object',
|
||||||
|
},
|
||||||
|
};
|
12
packages/json-schemas/schemas/order_fill_requests_schema.ts
Normal file
12
packages/json-schemas/schemas/order_fill_requests_schema.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
export const orderFillRequestsSchema = {
|
||||||
|
id: '/OrderFillRequests',
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
properties: {
|
||||||
|
signedOrder: {$ref: '/SignedOrder'},
|
||||||
|
takerTokenFillAmount: {$ref: '/Number'},
|
||||||
|
},
|
||||||
|
required: ['signedOrder', 'takerTokenFillAmount'],
|
||||||
|
type: 'object',
|
||||||
|
},
|
||||||
|
};
|
5
packages/json-schemas/schemas/order_hash_schema.ts
Normal file
5
packages/json-schemas/schemas/order_hash_schema.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export const orderHashSchema = {
|
||||||
|
id: '/OrderHashSchema',
|
||||||
|
type: 'string',
|
||||||
|
pattern: '^0x[0-9a-fA-F]{64}$',
|
||||||
|
};
|
35
packages/json-schemas/schemas/order_schemas.ts
Normal file
35
packages/json-schemas/schemas/order_schemas.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
export const orderSchema = {
|
||||||
|
id: '/Order',
|
||||||
|
properties: {
|
||||||
|
maker: {$ref: '/Address'},
|
||||||
|
taker: {$ref: '/Address'},
|
||||||
|
makerFee: {$ref: '/Number'},
|
||||||
|
takerFee: {$ref: '/Number'},
|
||||||
|
makerTokenAmount: {$ref: '/Number'},
|
||||||
|
takerTokenAmount: {$ref: '/Number'},
|
||||||
|
makerTokenAddress: {$ref: '/Address'},
|
||||||
|
takerTokenAddress: {$ref: '/Address'},
|
||||||
|
salt: {$ref: '/Number'},
|
||||||
|
feeRecipient: {$ref: '/Address'},
|
||||||
|
expirationUnixTimestampSec: {$ref: '/Number'},
|
||||||
|
exchangeContractAddress: {$ref: '/Address'},
|
||||||
|
},
|
||||||
|
required: [
|
||||||
|
'maker', 'taker', 'makerFee', 'takerFee', 'makerTokenAmount', 'takerTokenAmount',
|
||||||
|
'salt', 'feeRecipient', 'expirationUnixTimestampSec', 'exchangeContractAddress',
|
||||||
|
],
|
||||||
|
type: 'object',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const signedOrderSchema = {
|
||||||
|
id: '/SignedOrder',
|
||||||
|
allOf: [
|
||||||
|
{ $ref: '/Order' },
|
||||||
|
{
|
||||||
|
properties: {
|
||||||
|
ecSignature: {$ref: '/ECSignature'},
|
||||||
|
},
|
||||||
|
required: ['ecSignature'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
@ -0,0 +1,21 @@
|
|||||||
|
export const relayerApiErrorResponseSchema = {
|
||||||
|
id: '/RelayerApiErrorResponse',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
code: {type: 'number'},
|
||||||
|
reason: {type: 'string'},
|
||||||
|
validationErrors: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
field: {type: 'string'},
|
||||||
|
code: {type: 'number'},
|
||||||
|
reason: {type: 'string'},
|
||||||
|
},
|
||||||
|
required: ['field', 'code', 'reason'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ['code', 'reason'],
|
||||||
|
};
|
@ -0,0 +1,19 @@
|
|||||||
|
export const relayerApiFeesPayloadSchema = {
|
||||||
|
id: '/RelayerApiFeesPayload',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
exchangeContractAddress: {$ref: '/Address'},
|
||||||
|
maker: {$ref: '/Address'},
|
||||||
|
taker: {$ref: '/Address'},
|
||||||
|
makerTokenAddress: {$ref: '/Address'},
|
||||||
|
takerTokenAddress: {$ref: '/Address'},
|
||||||
|
makerTokenAmount: {$ref: '/Number'},
|
||||||
|
takerTokenAmount: {$ref: '/Number'},
|
||||||
|
expirationUnixTimestampSec: {$ref: '/Number'},
|
||||||
|
salt: {$ref: '/Number'},
|
||||||
|
},
|
||||||
|
required: [
|
||||||
|
'exchangeContractAddress', 'maker', 'taker', 'makerTokenAddress', 'takerTokenAddress',
|
||||||
|
'expirationUnixTimestampSec', 'salt',
|
||||||
|
],
|
||||||
|
};
|
@ -0,0 +1,10 @@
|
|||||||
|
export const relayerApiFeesResponseSchema = {
|
||||||
|
id: '/RelayerApiFeesResponse',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
makerFee: {$ref: '/Number'},
|
||||||
|
takerFee: {$ref: '/Number'},
|
||||||
|
feeRecipient: {$ref: '/Address'},
|
||||||
|
},
|
||||||
|
required: ['makerFee', 'takerFee', 'feeRecipient'],
|
||||||
|
};
|
@ -0,0 +1,22 @@
|
|||||||
|
export const relayerApiOrderbookChannelSubscribeSchema = {
|
||||||
|
id: '/RelayerApiOrderbookChannelSubscribe',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
type: {enum: ['subscribe']},
|
||||||
|
channel: {enum: ['orderbook']},
|
||||||
|
payload: {$ref: '/RelayerApiOrderbookChannelSubscribePayload'},
|
||||||
|
},
|
||||||
|
required: ['type', 'channel', 'payload'],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const relayerApiOrderbookChannelSubscribePayload = {
|
||||||
|
id: '/RelayerApiOrderbookChannelSubscribePayload',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
baseTokenAddress: {$ref: '/Address'},
|
||||||
|
quoteTokenAddress: {$ref: '/Address'},
|
||||||
|
snapshot: {type: 'boolean'},
|
||||||
|
limit: {type: 'number'},
|
||||||
|
},
|
||||||
|
required: ['baseTokenAddress', 'quoteTokenAddress'],
|
||||||
|
};
|
@ -0,0 +1,21 @@
|
|||||||
|
export const relayerApiOrderbookChannelSnapshotSchema = {
|
||||||
|
id: '/RelayerApiOrderbookChannelSnapshot',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
type: {enum: ['snapshot']},
|
||||||
|
channel: {enum: ['orderbook']},
|
||||||
|
channelId: {type: 'number'},
|
||||||
|
payload: {$ref: '/RelayerApiOrderbookChannelSnapshotPayload'},
|
||||||
|
},
|
||||||
|
required: ['type', 'channel', 'channelId', 'payload'],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const relayerApiOrderbookChannelSnapshotPayload = {
|
||||||
|
id: '/RelayerApiOrderbookChannelSnapshotPayload',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
bids: {$ref: '/signedOrdersSchema'},
|
||||||
|
asks: {$ref: '/signedOrdersSchema'},
|
||||||
|
},
|
||||||
|
required: ['bids', 'asks'],
|
||||||
|
};
|
@ -0,0 +1,11 @@
|
|||||||
|
export const relayerApiOrderbookChannelUpdateSchema = {
|
||||||
|
id: '/RelayerApiOrderbookChannelUpdate',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
type: {enum: ['update']},
|
||||||
|
channel: {enum: ['orderbook']},
|
||||||
|
channelId: {type: 'number'},
|
||||||
|
payload: {$ref: '/SignedOrder'},
|
||||||
|
},
|
||||||
|
required: ['type', 'channel', 'channelId', 'payload'],
|
||||||
|
};
|
@ -0,0 +1,9 @@
|
|||||||
|
export const relayerApiOrderBookResponseSchema = {
|
||||||
|
id: '/RelayerApiOrderBookResponse',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
bids: {$ref: '/signedOrdersSchema'},
|
||||||
|
asks: {$ref: '/signedOrdersSchema'},
|
||||||
|
},
|
||||||
|
required: ['bids', 'asks'],
|
||||||
|
};
|
@ -0,0 +1,24 @@
|
|||||||
|
export const relayerApiTokenPairsResponseSchema = {
|
||||||
|
id: '/RelayerApiTokenPairsResponse',
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
properties: {
|
||||||
|
tokenA: {$ref: '/RelayerApiTokenTradeInfo'},
|
||||||
|
tokenB: {$ref: '/RelayerApiTokenTradeInfo'},
|
||||||
|
},
|
||||||
|
required: ['tokenA', 'tokenB'],
|
||||||
|
type: 'object',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const relayerApiTokenTradeInfoSchema = {
|
||||||
|
id: '/RelayerApiTokenTradeInfo',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
address: {$ref: '/Address'},
|
||||||
|
minAmount: {$ref: '/Number'},
|
||||||
|
maxAmount: {$ref: '/Number'},
|
||||||
|
precision: {type: 'number'},
|
||||||
|
},
|
||||||
|
required: ['address'],
|
||||||
|
};
|
5
packages/json-schemas/schemas/signed_orders_schema.ts
Normal file
5
packages/json-schemas/schemas/signed_orders_schema.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export const signedOrdersSchema = {
|
||||||
|
id: '/signedOrdersSchema',
|
||||||
|
type: 'array',
|
||||||
|
items: {$ref: '/SignedOrder'},
|
||||||
|
};
|
20
packages/json-schemas/schemas/subscription_opts_schema.ts
Normal file
20
packages/json-schemas/schemas/subscription_opts_schema.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
export const blockParamSchema = {
|
||||||
|
id: '/BlockParam',
|
||||||
|
oneOf: [
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
enum: ['latest', 'earliest', 'pending'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const subscriptionOptsSchema = {
|
||||||
|
id: '/SubscriptionOpts',
|
||||||
|
properties: {
|
||||||
|
fromBlock: {$ref: '/BlockParam'},
|
||||||
|
toBlock: {$ref: '/BlockParam'},
|
||||||
|
},
|
||||||
|
type: 'object',
|
||||||
|
};
|
11
packages/json-schemas/schemas/token_schema.ts
Normal file
11
packages/json-schemas/schemas/token_schema.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
export const tokenSchema = {
|
||||||
|
id: '/Token',
|
||||||
|
properties: {
|
||||||
|
name: {type: 'string'},
|
||||||
|
symbol: {type: 'string'},
|
||||||
|
decimals: {type: 'number'},
|
||||||
|
address: {$ref: '/Address'},
|
||||||
|
},
|
||||||
|
required: ['name', 'symbol', 'decimals', 'address'],
|
||||||
|
type: 'object',
|
||||||
|
};
|
42
packages/json-schemas/schemas/tx_data_schema.ts
Normal file
42
packages/json-schemas/schemas/tx_data_schema.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
export const jsNumber = {
|
||||||
|
id: '/JsNumber',
|
||||||
|
type: 'number',
|
||||||
|
minimum: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const txDataSchema = {
|
||||||
|
id: '/TxData',
|
||||||
|
properties: {
|
||||||
|
from: {$ref: '/Address'},
|
||||||
|
to: {$ref: '/Address'},
|
||||||
|
value: {
|
||||||
|
oneOf: [
|
||||||
|
{$ref: '/Number'},
|
||||||
|
{$ref: '/JsNumber'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
gas: {
|
||||||
|
oneOf: [
|
||||||
|
{$ref: '/Number'},
|
||||||
|
{$ref: '/JsNumber'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
gasPrice: {
|
||||||
|
oneOf: [
|
||||||
|
{$ref: '/Number'},
|
||||||
|
{$ref: '/JsNumber'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: 'string',
|
||||||
|
pattern: '^0x[0-9a-f]*$',
|
||||||
|
},
|
||||||
|
nonce: {
|
||||||
|
type: 'number',
|
||||||
|
minimum: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ['from'],
|
||||||
|
type: 'object',
|
||||||
|
additionalProperties: false,
|
||||||
|
};
|
14
packages/json-schemas/scripts/postpublish.js
Normal file
14
packages/json-schemas/scripts/postpublish.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
const postpublish_utils = require('../../../scripts/postpublish_utils');
|
||||||
|
const packageJSON = require('../package.json');
|
||||||
|
|
||||||
|
const subPackageName = packageJSON.name;
|
||||||
|
|
||||||
|
postpublish_utils.getLatestTagAndVersionAsync(subPackageName)
|
||||||
|
.then(function(result) {
|
||||||
|
const releaseName = postpublish_utils.getReleaseName(subPackageName, result.version);
|
||||||
|
const assets = [];
|
||||||
|
return postpublish_utils.publishReleaseNotes(result.tag, releaseName, assets);
|
||||||
|
})
|
||||||
|
.catch (function(err) {
|
||||||
|
throw err;
|
||||||
|
});
|
7
packages/json-schemas/src/globals.d.ts
vendored
Normal file
7
packages/json-schemas/src/globals.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
declare module 'dirty-chai';
|
||||||
|
|
||||||
|
// es6-promisify declarations
|
||||||
|
declare function promisify(original: any, settings?: any): ((...arg: any[]) => Promise<any>);
|
||||||
|
declare module 'es6-promisify' {
|
||||||
|
export = promisify;
|
||||||
|
}
|
4
packages/json-schemas/src/index.ts
Normal file
4
packages/json-schemas/src/index.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export {ValidatorResult, Schema} from 'jsonschema';
|
||||||
|
|
||||||
|
export {SchemaValidator} from './schema_validator';
|
||||||
|
export {schemas} from './schemas';
|
28
packages/json-schemas/src/schema_validator.ts
Normal file
28
packages/json-schemas/src/schema_validator.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import values = require('lodash.values');
|
||||||
|
import {Validator, ValidatorResult, Schema} from 'jsonschema';
|
||||||
|
import {schemas} from './schemas';
|
||||||
|
|
||||||
|
export class SchemaValidator {
|
||||||
|
private validator: Validator;
|
||||||
|
constructor() {
|
||||||
|
this.validator = new Validator();
|
||||||
|
for (const schema of values(schemas)) {
|
||||||
|
this.validator.addSchema(schema, schema.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public addSchema(schema: Schema) {
|
||||||
|
this.validator.addSchema(schema, schema.id);
|
||||||
|
}
|
||||||
|
// In order to validate a complex JS object using jsonschema, we must replace any complex
|
||||||
|
// sub-types (e.g BigNumber) with a simpler string representation. Since BigNumber and other
|
||||||
|
// complex types implement the `toString` method, we can stringify the object and
|
||||||
|
// then parse it. The resultant object can then be checked using jsonschema.
|
||||||
|
public validate(instance: any, schema: Schema): ValidatorResult {
|
||||||
|
const jsonSchemaCompatibleObject = JSON.parse(JSON.stringify(instance));
|
||||||
|
return this.validator.validate(jsonSchemaCompatibleObject, schema);
|
||||||
|
}
|
||||||
|
public isValid(instance: any, schema: Schema): boolean {
|
||||||
|
const isValid = this.validate(instance, schema).errors.length === 0;
|
||||||
|
return isValid;
|
||||||
|
}
|
||||||
|
}
|
99
packages/json-schemas/src/schemas.ts
Normal file
99
packages/json-schemas/src/schemas.ts
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import {
|
||||||
|
numberSchema,
|
||||||
|
addressSchema,
|
||||||
|
} from '../schemas/basic_type_schemas';
|
||||||
|
import {
|
||||||
|
ecSignatureSchema,
|
||||||
|
ecSignatureParameterSchema,
|
||||||
|
} from '../schemas/ec_signature_schema';
|
||||||
|
import {
|
||||||
|
indexFilterValuesSchema,
|
||||||
|
} from '../schemas/index_filter_values_schema';
|
||||||
|
import {
|
||||||
|
orderCancellationRequestsSchema,
|
||||||
|
} from '../schemas/order_cancel_schema';
|
||||||
|
import {
|
||||||
|
orderFillOrKillRequestsSchema,
|
||||||
|
} from '../schemas/order_fill_or_kill_requests_schema';
|
||||||
|
import {
|
||||||
|
orderFillRequestsSchema,
|
||||||
|
} from '../schemas/order_fill_requests_schema';
|
||||||
|
import {
|
||||||
|
orderHashSchema,
|
||||||
|
} from '../schemas/order_hash_schema';
|
||||||
|
import {
|
||||||
|
orderSchema,
|
||||||
|
signedOrderSchema,
|
||||||
|
} from '../schemas/order_schemas';
|
||||||
|
import {
|
||||||
|
blockParamSchema,
|
||||||
|
subscriptionOptsSchema,
|
||||||
|
} from '../schemas/subscription_opts_schema';
|
||||||
|
import {
|
||||||
|
tokenSchema,
|
||||||
|
} from '../schemas/token_schema';
|
||||||
|
import {
|
||||||
|
signedOrdersSchema,
|
||||||
|
} from '../schemas/signed_orders_schema';
|
||||||
|
import {
|
||||||
|
relayerApiErrorResponseSchema,
|
||||||
|
} from '../schemas/relayer_api_error_response_schema';
|
||||||
|
import {
|
||||||
|
relayerApiFeesResponseSchema,
|
||||||
|
} from '../schemas/relayer_api_fees_response_schema';
|
||||||
|
import {
|
||||||
|
relayerApiFeesPayloadSchema,
|
||||||
|
} from '../schemas/relayer_api_fees_payload_schema';
|
||||||
|
import {
|
||||||
|
relayerApiOrderBookResponseSchema,
|
||||||
|
} from '../schemas/relayer_api_orderbook_response_schema';
|
||||||
|
import {
|
||||||
|
relayerApiTokenPairsResponseSchema,
|
||||||
|
relayerApiTokenTradeInfoSchema,
|
||||||
|
} from '../schemas/relayer_api_token_pairs_response_schema';
|
||||||
|
import {
|
||||||
|
jsNumber,
|
||||||
|
txDataSchema,
|
||||||
|
} from '../schemas/tx_data_schema';
|
||||||
|
import {
|
||||||
|
relayerApiOrderbookChannelSubscribeSchema,
|
||||||
|
relayerApiOrderbookChannelSubscribePayload,
|
||||||
|
} from '../schemas/relayer_api_orberbook_channel_subscribe_schema';
|
||||||
|
import {
|
||||||
|
relayerApiOrderbookChannelUpdateSchema,
|
||||||
|
} from '../schemas/relayer_api_orderbook_channel_update_response_schema';
|
||||||
|
import {
|
||||||
|
relayerApiOrderbookChannelSnapshotSchema,
|
||||||
|
relayerApiOrderbookChannelSnapshotPayload,
|
||||||
|
} from '../schemas/relayer_api_orderbook_channel_snapshot_schema';
|
||||||
|
|
||||||
|
export const schemas = {
|
||||||
|
numberSchema,
|
||||||
|
addressSchema,
|
||||||
|
ecSignatureSchema,
|
||||||
|
ecSignatureParameterSchema,
|
||||||
|
indexFilterValuesSchema,
|
||||||
|
orderCancellationRequestsSchema,
|
||||||
|
orderFillOrKillRequestsSchema,
|
||||||
|
orderFillRequestsSchema,
|
||||||
|
orderHashSchema,
|
||||||
|
orderSchema,
|
||||||
|
signedOrderSchema,
|
||||||
|
signedOrdersSchema,
|
||||||
|
blockParamSchema,
|
||||||
|
subscriptionOptsSchema,
|
||||||
|
tokenSchema,
|
||||||
|
jsNumber,
|
||||||
|
txDataSchema,
|
||||||
|
relayerApiErrorResponseSchema,
|
||||||
|
relayerApiFeesPayloadSchema,
|
||||||
|
relayerApiFeesResponseSchema,
|
||||||
|
relayerApiOrderBookResponseSchema,
|
||||||
|
relayerApiTokenPairsResponseSchema,
|
||||||
|
relayerApiTokenTradeInfoSchema,
|
||||||
|
relayerApiOrderbookChannelSubscribeSchema,
|
||||||
|
relayerApiOrderbookChannelSubscribePayload,
|
||||||
|
relayerApiOrderbookChannelUpdateSchema,
|
||||||
|
relayerApiOrderbookChannelSnapshotSchema,
|
||||||
|
relayerApiOrderbookChannelSnapshotPayload,
|
||||||
|
};
|
972
packages/json-schemas/test/schema_test.ts
Normal file
972
packages/json-schemas/test/schema_test.ts
Normal file
@ -0,0 +1,972 @@
|
|||||||
|
import 'mocha';
|
||||||
|
import forEach = require('lodash.foreach');
|
||||||
|
import * as dirtyChai from 'dirty-chai';
|
||||||
|
import * as chai from 'chai';
|
||||||
|
import BigNumber from 'bignumber.js';
|
||||||
|
import promisify = require('es6-promisify');
|
||||||
|
import {SchemaValidator, schemas} from '../src/index';
|
||||||
|
|
||||||
|
chai.config.includeStack = true;
|
||||||
|
chai.use(dirtyChai);
|
||||||
|
const expect = chai.expect;
|
||||||
|
const NULL_ADDRESS = '0x0000000000000000000000000000000000000000';
|
||||||
|
const {
|
||||||
|
numberSchema,
|
||||||
|
addressSchema,
|
||||||
|
ecSignatureSchema,
|
||||||
|
ecSignatureParameterSchema,
|
||||||
|
indexFilterValuesSchema,
|
||||||
|
orderCancellationRequestsSchema,
|
||||||
|
orderFillOrKillRequestsSchema,
|
||||||
|
orderFillRequestsSchema,
|
||||||
|
orderHashSchema,
|
||||||
|
orderSchema,
|
||||||
|
signedOrderSchema,
|
||||||
|
signedOrdersSchema,
|
||||||
|
blockParamSchema,
|
||||||
|
subscriptionOptsSchema,
|
||||||
|
tokenSchema,
|
||||||
|
jsNumber,
|
||||||
|
txDataSchema,
|
||||||
|
relayerApiErrorResponseSchema,
|
||||||
|
relayerApiOrderBookResponseSchema,
|
||||||
|
relayerApiTokenPairsResponseSchema,
|
||||||
|
relayerApiFeesPayloadSchema,
|
||||||
|
relayerApiFeesResponseSchema,
|
||||||
|
relayerApiOrderbookChannelSubscribeSchema,
|
||||||
|
relayerApiOrderbookChannelUpdateSchema,
|
||||||
|
relayerApiOrderbookChannelSnapshotSchema,
|
||||||
|
} = schemas;
|
||||||
|
|
||||||
|
describe('Schema', () => {
|
||||||
|
const validator = new SchemaValidator();
|
||||||
|
const validateAgainstSchema = (testCases: any[], schema: any, shouldFail = false) => {
|
||||||
|
forEach(testCases, (testCase: any) => {
|
||||||
|
const validationResult = validator.validate(testCase, schema);
|
||||||
|
const hasErrors = validationResult.errors.length !== 0;
|
||||||
|
if (shouldFail) {
|
||||||
|
if (!hasErrors) {
|
||||||
|
throw new Error(
|
||||||
|
`Expected testCase: ${JSON.stringify(testCase, null, '\t')} to fail and it didn't.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (hasErrors) {
|
||||||
|
throw new Error(JSON.stringify(validationResult.errors, null, '\t'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
describe('#numberSchema', () => {
|
||||||
|
it('should validate valid numbers', () => {
|
||||||
|
const testCases = ['42', '0', '1.3', '0.2', '00.00'];
|
||||||
|
validateAgainstSchema(testCases, numberSchema);
|
||||||
|
});
|
||||||
|
it('should fail for invalid numbers', () => {
|
||||||
|
const testCases = ['.3', '1.', 'abacaba', 'и', '1..0'];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, numberSchema, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#addressSchema', () => {
|
||||||
|
it('should validate valid addresses', () => {
|
||||||
|
const testCases = ['0x8b0292b11a196601ed2ce54b665cafeca0347d42', NULL_ADDRESS];
|
||||||
|
validateAgainstSchema(testCases, addressSchema);
|
||||||
|
});
|
||||||
|
it('should fail for invalid addresses', () => {
|
||||||
|
const testCases = [
|
||||||
|
'0x',
|
||||||
|
'0',
|
||||||
|
'0x00',
|
||||||
|
'0xzzzzzzB11a196601eD2ce54B665CaFEca0347D42',
|
||||||
|
'0x8b0292B11a196601eD2ce54B665CaFEca0347D42',
|
||||||
|
];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, addressSchema, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#ecSignatureParameterSchema', () => {
|
||||||
|
it('should validate valid parameters', () => {
|
||||||
|
const testCases = [
|
||||||
|
'0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33',
|
||||||
|
'0X40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
|
||||||
|
];
|
||||||
|
validateAgainstSchema(testCases, ecSignatureParameterSchema);
|
||||||
|
});
|
||||||
|
it('should fail for invalid parameters', () => {
|
||||||
|
const testCases = [
|
||||||
|
'0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc3', // shorter
|
||||||
|
'0xzzzz9190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254', // invalid characters
|
||||||
|
'40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254', // no 0x
|
||||||
|
];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, ecSignatureParameterSchema, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#ecSignatureSchema', () => {
|
||||||
|
it('should validate valid signature', () => {
|
||||||
|
const signature = {
|
||||||
|
v: 27,
|
||||||
|
r: '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33',
|
||||||
|
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
|
||||||
|
};
|
||||||
|
const testCases = [
|
||||||
|
signature,
|
||||||
|
{
|
||||||
|
...signature,
|
||||||
|
v: 28,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
validateAgainstSchema(testCases, ecSignatureSchema);
|
||||||
|
});
|
||||||
|
it('should fail for invalid signature', () => {
|
||||||
|
const v = 27;
|
||||||
|
const r = '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33';
|
||||||
|
const s = '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254';
|
||||||
|
const testCases = [
|
||||||
|
{},
|
||||||
|
{v},
|
||||||
|
{r, s, v: 31},
|
||||||
|
];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, ecSignatureSchema, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#orderHashSchema', () => {
|
||||||
|
it('should validate valid order hash', () => {
|
||||||
|
const testCases = [
|
||||||
|
'0x61a3ed31B43c8780e905a260a35faefEc527be7516aa11c0256729b5b351bc33',
|
||||||
|
'0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
|
||||||
|
];
|
||||||
|
validateAgainstSchema(testCases, orderHashSchema);
|
||||||
|
});
|
||||||
|
it('should fail for invalid order hash', () => {
|
||||||
|
const testCases = [
|
||||||
|
{},
|
||||||
|
'0x',
|
||||||
|
'0x8b0292B11a196601eD2ce54B665CaFEca0347D42',
|
||||||
|
'61a3ed31B43c8780e905a260a35faefEc527be7516aa11c0256729b5b351bc33',
|
||||||
|
];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, orderHashSchema, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#blockParamSchema', () => {
|
||||||
|
it('should validate valid block param', () => {
|
||||||
|
const testCases = [
|
||||||
|
42,
|
||||||
|
'latest',
|
||||||
|
'pending',
|
||||||
|
'earliest',
|
||||||
|
];
|
||||||
|
validateAgainstSchema(testCases, blockParamSchema);
|
||||||
|
});
|
||||||
|
it('should fail for invalid block param', () => {
|
||||||
|
const testCases = [
|
||||||
|
{},
|
||||||
|
'42',
|
||||||
|
'pemding',
|
||||||
|
];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, blockParamSchema, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#subscriptionOptsSchema', () => {
|
||||||
|
it('should validate valid subscription opts', () => {
|
||||||
|
const testCases = [
|
||||||
|
{fromBlock: 42, toBlock: 'latest'},
|
||||||
|
{fromBlock: 42},
|
||||||
|
{},
|
||||||
|
];
|
||||||
|
validateAgainstSchema(testCases, subscriptionOptsSchema);
|
||||||
|
});
|
||||||
|
it('should fail for invalid subscription opts', () => {
|
||||||
|
const testCases = [
|
||||||
|
{fromBlock: '42'},
|
||||||
|
];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, subscriptionOptsSchema, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#tokenSchema', () => {
|
||||||
|
const token = {
|
||||||
|
name: 'Zero Ex',
|
||||||
|
symbol: 'ZRX',
|
||||||
|
decimals: 100500,
|
||||||
|
address: '0x8b0292b11a196601ed2ce54b665cafeca0347d42',
|
||||||
|
url: 'https://0xproject.com',
|
||||||
|
};
|
||||||
|
it('should validate valid token', () => {
|
||||||
|
const testCases = [
|
||||||
|
token,
|
||||||
|
];
|
||||||
|
validateAgainstSchema(testCases, tokenSchema);
|
||||||
|
});
|
||||||
|
it('should fail for invalid token', () => {
|
||||||
|
const testCases = [
|
||||||
|
{
|
||||||
|
...token,
|
||||||
|
address: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...token,
|
||||||
|
decimals: undefined,
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
4,
|
||||||
|
];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, tokenSchema, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('order including schemas', () => {
|
||||||
|
const order = {
|
||||||
|
maker: NULL_ADDRESS,
|
||||||
|
taker: NULL_ADDRESS,
|
||||||
|
makerFee: '1',
|
||||||
|
takerFee: '2',
|
||||||
|
makerTokenAmount: '1',
|
||||||
|
takerTokenAmount: '2',
|
||||||
|
makerTokenAddress: NULL_ADDRESS,
|
||||||
|
takerTokenAddress: NULL_ADDRESS,
|
||||||
|
salt: '67006738228878699843088602623665307406148487219438534730168799356281242528500',
|
||||||
|
feeRecipient: NULL_ADDRESS,
|
||||||
|
exchangeContractAddress: NULL_ADDRESS,
|
||||||
|
expirationUnixTimestampSec: '42',
|
||||||
|
};
|
||||||
|
describe('#orderSchema', () => {
|
||||||
|
it('should validate valid order', () => {
|
||||||
|
const testCases = [
|
||||||
|
order,
|
||||||
|
];
|
||||||
|
validateAgainstSchema(testCases, orderSchema);
|
||||||
|
});
|
||||||
|
it('should fail for invalid order', () => {
|
||||||
|
const testCases = [
|
||||||
|
{
|
||||||
|
...order,
|
||||||
|
salt: undefined,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...order,
|
||||||
|
salt: 'salt',
|
||||||
|
},
|
||||||
|
'order',
|
||||||
|
];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, orderSchema, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('signed order including schemas', () => {
|
||||||
|
const signedOrder = {
|
||||||
|
...order,
|
||||||
|
ecSignature: {
|
||||||
|
v: 27,
|
||||||
|
r: '0x61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33',
|
||||||
|
s: '0x40349190569279751135161d22529dc25add4f6069af05be04cacbda2ace2254',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
describe('#signedOrdersSchema', () => {
|
||||||
|
it('should validate valid signed orders', () => {
|
||||||
|
const testCases = [
|
||||||
|
[signedOrder],
|
||||||
|
[],
|
||||||
|
];
|
||||||
|
validateAgainstSchema(testCases, signedOrdersSchema);
|
||||||
|
});
|
||||||
|
it('should fail for invalid signed orders', () => {
|
||||||
|
const testCases = [
|
||||||
|
[
|
||||||
|
signedOrder,
|
||||||
|
1,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, signedOrdersSchema, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#signedOrderSchema', () => {
|
||||||
|
it('should validate valid signed order', () => {
|
||||||
|
const testCases = [
|
||||||
|
signedOrder,
|
||||||
|
];
|
||||||
|
validateAgainstSchema(testCases, signedOrderSchema);
|
||||||
|
});
|
||||||
|
it('should fail for invalid signed order', () => {
|
||||||
|
const testCases = [
|
||||||
|
{
|
||||||
|
...signedOrder,
|
||||||
|
ecSignature: undefined,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, signedOrderSchema, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#orderFillOrKillRequestsSchema', () => {
|
||||||
|
const orderFillOrKillRequests = [
|
||||||
|
{
|
||||||
|
signedOrder,
|
||||||
|
fillTakerAmount: '5',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
it('should validate valid order fill or kill requests', () => {
|
||||||
|
const testCases = [
|
||||||
|
orderFillOrKillRequests,
|
||||||
|
];
|
||||||
|
validateAgainstSchema(testCases, orderFillOrKillRequestsSchema);
|
||||||
|
});
|
||||||
|
it('should fail for invalid order fill or kill requests', () => {
|
||||||
|
const testCases = [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
...orderFillOrKillRequests[0],
|
||||||
|
fillTakerAmount: undefined,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, orderFillOrKillRequestsSchema, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#orderCancellationRequestsSchema', () => {
|
||||||
|
const orderCancellationRequests = [
|
||||||
|
{
|
||||||
|
order,
|
||||||
|
takerTokenCancelAmount: '5',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
it('should validate valid order cancellation requests', () => {
|
||||||
|
const testCases = [
|
||||||
|
orderCancellationRequests,
|
||||||
|
];
|
||||||
|
validateAgainstSchema(testCases, orderCancellationRequestsSchema);
|
||||||
|
});
|
||||||
|
it('should fail for invalid order cancellation requests', () => {
|
||||||
|
const testCases = [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
...orderCancellationRequests[0],
|
||||||
|
takerTokenCancelAmount: undefined,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, orderCancellationRequestsSchema, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#orderFillRequestsSchema', () => {
|
||||||
|
const orderFillRequests = [
|
||||||
|
{
|
||||||
|
signedOrder,
|
||||||
|
takerTokenFillAmount: '5',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
it('should validate valid order fill requests', () => {
|
||||||
|
const testCases = [
|
||||||
|
orderFillRequests,
|
||||||
|
];
|
||||||
|
validateAgainstSchema(testCases, orderFillRequestsSchema);
|
||||||
|
});
|
||||||
|
it('should fail for invalid order fill requests', () => {
|
||||||
|
const testCases = [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
...orderFillRequests[0],
|
||||||
|
takerTokenFillAmount: undefined,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, orderFillRequestsSchema, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#relayerApiOrderBookResponseSchema', () => {
|
||||||
|
it('should validate valid order book responses', () => {
|
||||||
|
const testCases = [
|
||||||
|
{
|
||||||
|
bids: [],
|
||||||
|
asks: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bids: [signedOrder, signedOrder],
|
||||||
|
asks: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bids: [],
|
||||||
|
asks: [signedOrder, signedOrder],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bids: [signedOrder],
|
||||||
|
asks: [signedOrder, signedOrder],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
validateAgainstSchema(testCases, relayerApiOrderBookResponseSchema);
|
||||||
|
});
|
||||||
|
it('should fail for invalid order fill requests', () => {
|
||||||
|
const testCases = [
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
bids: [signedOrder, signedOrder],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
asks: [signedOrder, signedOrder],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bids: signedOrder,
|
||||||
|
asks: [signedOrder, signedOrder],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bids: [signedOrder],
|
||||||
|
asks: signedOrder,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, relayerApiOrderBookResponseSchema, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#relayerApiOrderbookChannelSubscribeSchema', () => {
|
||||||
|
it('should validate valid orderbook channel websocket subscribe message', () => {
|
||||||
|
const testCases = [
|
||||||
|
{
|
||||||
|
type: 'subscribe',
|
||||||
|
channel: 'orderbook',
|
||||||
|
payload: {
|
||||||
|
baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
quoteTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
snapshot: true,
|
||||||
|
limit: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'subscribe',
|
||||||
|
channel: 'orderbook',
|
||||||
|
payload: {
|
||||||
|
baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
quoteTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
validateAgainstSchema(testCases, relayerApiOrderbookChannelSubscribeSchema);
|
||||||
|
});
|
||||||
|
it('should fail for invalid orderbook channel websocket subscribe message', () => {
|
||||||
|
const checksummedAddress = '0xA2b31daCf30a9C50ca473337c01d8A201ae33e32';
|
||||||
|
const testCases = [
|
||||||
|
{
|
||||||
|
type: 'foo',
|
||||||
|
channel: 'orderbook',
|
||||||
|
payload: {
|
||||||
|
baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
quoteTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'subscribe',
|
||||||
|
channel: 'bar',
|
||||||
|
payload: {
|
||||||
|
baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
quoteTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'subscribe',
|
||||||
|
channel: 'orderbook',
|
||||||
|
payload: {
|
||||||
|
baseTokenAddress: checksummedAddress,
|
||||||
|
quoteTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'subscribe',
|
||||||
|
channel: 'orderbook',
|
||||||
|
payload: {
|
||||||
|
baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
quoteTokenAddress: checksummedAddress,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'subscribe',
|
||||||
|
channel: 'orderbook',
|
||||||
|
payload: {
|
||||||
|
quoteTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'subscribe',
|
||||||
|
channel: 'orderbook',
|
||||||
|
payload: {
|
||||||
|
baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'subscribe',
|
||||||
|
channel: 'orderbook',
|
||||||
|
payload: {
|
||||||
|
baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
quoteTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
snapshot: 'true',
|
||||||
|
limit: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'subscribe',
|
||||||
|
channel: 'orderbook',
|
||||||
|
payload: {
|
||||||
|
baseTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
quoteTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
snapshot: true,
|
||||||
|
limit: '100',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, relayerApiOrderbookChannelSubscribeSchema, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#relayerApiOrderbookChannelSnapshotSchema', () => {
|
||||||
|
it('should validate valid orderbook channel websocket snapshot message', () => {
|
||||||
|
const testCases = [
|
||||||
|
{
|
||||||
|
type: 'snapshot',
|
||||||
|
channel: 'orderbook',
|
||||||
|
channelId: 2,
|
||||||
|
payload: {
|
||||||
|
bids: [],
|
||||||
|
asks: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'snapshot',
|
||||||
|
channel: 'orderbook',
|
||||||
|
channelId: 2,
|
||||||
|
payload: {
|
||||||
|
bids: [
|
||||||
|
signedOrder,
|
||||||
|
],
|
||||||
|
asks: [
|
||||||
|
signedOrder,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
validateAgainstSchema(testCases, relayerApiOrderbookChannelSnapshotSchema);
|
||||||
|
});
|
||||||
|
it('should fail for invalid orderbook channel websocket snapshot message', () => {
|
||||||
|
const testCases = [
|
||||||
|
{
|
||||||
|
type: 'foo',
|
||||||
|
channel: 'orderbook',
|
||||||
|
channelId: 2,
|
||||||
|
payload: {
|
||||||
|
bids: [
|
||||||
|
signedOrder,
|
||||||
|
],
|
||||||
|
asks: [
|
||||||
|
signedOrder,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'snapshot',
|
||||||
|
channel: 'bar',
|
||||||
|
channelId: 2,
|
||||||
|
payload: {
|
||||||
|
bids: [
|
||||||
|
signedOrder,
|
||||||
|
],
|
||||||
|
asks: [
|
||||||
|
signedOrder,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'snapshot',
|
||||||
|
channel: 'orderbook',
|
||||||
|
payload: {
|
||||||
|
bids: [
|
||||||
|
signedOrder,
|
||||||
|
],
|
||||||
|
asks: [
|
||||||
|
signedOrder,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'snapshot',
|
||||||
|
channel: 'orderbook',
|
||||||
|
channelId: '2',
|
||||||
|
payload: {
|
||||||
|
bids: [
|
||||||
|
signedOrder,
|
||||||
|
],
|
||||||
|
asks: [
|
||||||
|
signedOrder,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'snapshot',
|
||||||
|
channel: 'orderbook',
|
||||||
|
channelId: 2,
|
||||||
|
payload: {
|
||||||
|
bids: [
|
||||||
|
signedOrder,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'snapshot',
|
||||||
|
channel: 'orderbook',
|
||||||
|
channelId: 2,
|
||||||
|
payload: {
|
||||||
|
asks: [
|
||||||
|
signedOrder,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'snapshot',
|
||||||
|
channel: 'orderbook',
|
||||||
|
channelId: 2,
|
||||||
|
payload: {
|
||||||
|
bids: [
|
||||||
|
signedOrder,
|
||||||
|
],
|
||||||
|
asks: [
|
||||||
|
{},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'snapshot',
|
||||||
|
channel: 'orderbook',
|
||||||
|
channelId: 2,
|
||||||
|
payload: {
|
||||||
|
bids: [
|
||||||
|
{},
|
||||||
|
],
|
||||||
|
asks: [
|
||||||
|
signedOrder,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, relayerApiOrderbookChannelSnapshotSchema, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#relayerApiOrderbookChannelUpdateSchema', () => {
|
||||||
|
it('should validate valid orderbook channel websocket update message', () => {
|
||||||
|
const testCases = [
|
||||||
|
{
|
||||||
|
type: 'update',
|
||||||
|
channel: 'orderbook',
|
||||||
|
channelId: 2,
|
||||||
|
payload: signedOrder,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
validateAgainstSchema(testCases, relayerApiOrderbookChannelUpdateSchema);
|
||||||
|
});
|
||||||
|
it('should fail for invalid orderbook channel websocket update message', () => {
|
||||||
|
const testCases = [
|
||||||
|
{
|
||||||
|
type: 'foo',
|
||||||
|
channel: 'orderbook',
|
||||||
|
payload: signedOrder,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'update',
|
||||||
|
channel: 'bar',
|
||||||
|
payload: signedOrder,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'update',
|
||||||
|
channel: 'orderbook',
|
||||||
|
payload: {},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, relayerApiOrderbookChannelUpdateSchema, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('BigNumber serialization', () => {
|
||||||
|
it('should correctly serialize BigNumbers', () => {
|
||||||
|
const testCases = {
|
||||||
|
'42': '42',
|
||||||
|
'0': '0',
|
||||||
|
'1.3': '1.3',
|
||||||
|
'0.2': '0.2',
|
||||||
|
'00.00': '0',
|
||||||
|
'.3': '0.3',
|
||||||
|
};
|
||||||
|
forEach(testCases, (serialized: string, input: string) => {
|
||||||
|
expect(JSON.parse(JSON.stringify(new BigNumber(input)))).to.be.equal(serialized);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#relayerApiErrorResponseSchema', () => {
|
||||||
|
it('should validate valid errorResponse', () => {
|
||||||
|
const testCases = [
|
||||||
|
{
|
||||||
|
code: 102,
|
||||||
|
reason: 'Order submission disabled',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 101,
|
||||||
|
reason: 'Validation failed',
|
||||||
|
validationErrors: [
|
||||||
|
{
|
||||||
|
field: 'maker',
|
||||||
|
code: 1002,
|
||||||
|
reason: 'Invalid address',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
validateAgainstSchema(testCases, relayerApiErrorResponseSchema);
|
||||||
|
});
|
||||||
|
it('should fail for invalid error responses', () => {
|
||||||
|
const testCases = [
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
code: 102,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: '102',
|
||||||
|
reason: 'Order submission disabled',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reason: 'Order submission disabled',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 101,
|
||||||
|
reason: 'Validation failed',
|
||||||
|
validationErrors: [
|
||||||
|
{
|
||||||
|
field: 'maker',
|
||||||
|
reason: 'Invalid address',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 101,
|
||||||
|
reason: 'Validation failed',
|
||||||
|
validationErrors: [
|
||||||
|
{
|
||||||
|
field: 'maker',
|
||||||
|
code: '1002',
|
||||||
|
reason: 'Invalid address',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, relayerApiErrorResponseSchema, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#relayerApiFeesPayloadSchema', () => {
|
||||||
|
it('should validate valid fees payloads', () => {
|
||||||
|
const testCases = [
|
||||||
|
{
|
||||||
|
exchangeContractAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
maker: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
taker: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
makerTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
takerTokenAddress: '0xef7fff64389b814a946f3e92105513705ca6b990',
|
||||||
|
makerTokenAmount: '10000000000000000000',
|
||||||
|
takerTokenAmount: '30000000000000000000',
|
||||||
|
expirationUnixTimestampSec: '42',
|
||||||
|
salt: '67006738228878699843088602623665307406148487219438534730168799356281242528500',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
validateAgainstSchema(testCases, relayerApiFeesPayloadSchema);
|
||||||
|
});
|
||||||
|
it('should fail for invalid fees payloads', () => {
|
||||||
|
const checksummedAddress = '0xA2b31daCf30a9C50ca473337c01d8A201ae33e32';
|
||||||
|
const testCases = [
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
takerTokenAddress: '0xef7fff64389b814a946f3e92105513705ca6b990',
|
||||||
|
makerTokenAmount: '10000000000000000000',
|
||||||
|
takerTokenAmount: '30000000000000000000',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
taker: checksummedAddress,
|
||||||
|
makerTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
takerTokenAddress: '0xef7fff64389b814a946f3e92105513705ca6b990',
|
||||||
|
makerTokenAmount: '10000000000000000000',
|
||||||
|
takerTokenAmount: '30000000000000000000',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
makerTokenAddress: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
takerTokenAddress: '0xef7fff64389b814a946f3e92105513705ca6b990',
|
||||||
|
makerTokenAmount: 10000000000000000000,
|
||||||
|
takerTokenAmount: 30000000000000000000,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, relayerApiFeesPayloadSchema, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#relayerApiFeesResponseSchema', () => {
|
||||||
|
it('should validate valid fees responses', () => {
|
||||||
|
const testCases = [
|
||||||
|
{
|
||||||
|
makerFee: '10000000000000000',
|
||||||
|
takerFee: '30000000000000000',
|
||||||
|
feeRecipient: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
validateAgainstSchema(testCases, relayerApiFeesResponseSchema);
|
||||||
|
});
|
||||||
|
it('should fail for invalid fees responses', () => {
|
||||||
|
const checksummedAddress = '0xA2b31daCf30a9C50ca473337c01d8A201ae33e32';
|
||||||
|
const testCases = [
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
makerFee: 10000000000000000,
|
||||||
|
takerFee: 30000000000000000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
feeRecipient: checksummedAddress,
|
||||||
|
takerToSpecify: checksummedAddress,
|
||||||
|
makerFee: '10000000000000000',
|
||||||
|
takerFee: '30000000000000000',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, relayerApiFeesResponseSchema, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#relayerApiTokenPairsResponseSchema', () => {
|
||||||
|
it('should validate valid tokenPairs response', () => {
|
||||||
|
const testCases = [
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
tokenA: {
|
||||||
|
address: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
minAmount: '0',
|
||||||
|
maxAmount: '10000000000000000000',
|
||||||
|
precision: 5,
|
||||||
|
},
|
||||||
|
tokenB: {
|
||||||
|
address: '0xef7fff64389b814a946f3e92105513705ca6b990',
|
||||||
|
minAmount: '0',
|
||||||
|
maxAmount: '50000000000000000000',
|
||||||
|
precision: 5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
tokenA: {
|
||||||
|
address: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
},
|
||||||
|
tokenB: {
|
||||||
|
address: '0xef7fff64389b814a946f3e92105513705ca6b990',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
];
|
||||||
|
validateAgainstSchema(testCases, relayerApiTokenPairsResponseSchema);
|
||||||
|
});
|
||||||
|
it('should fail for invalid tokenPairs responses', () => {
|
||||||
|
const checksummedAddress = '0xA2b31daCf30a9C50ca473337c01d8A201ae33e32';
|
||||||
|
const testCases = [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
tokenA: {
|
||||||
|
address: checksummedAddress,
|
||||||
|
},
|
||||||
|
tokenB: {
|
||||||
|
address: checksummedAddress,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
tokenA: {
|
||||||
|
address: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
minAmount: 0,
|
||||||
|
maxAmount: 10000000000000000000,
|
||||||
|
},
|
||||||
|
tokenB: {
|
||||||
|
address: '0xef7fff64389b814a946f3e92105513705ca6b990',
|
||||||
|
minAmount: 0,
|
||||||
|
maxAmount: 50000000000000000000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
tokenA: {
|
||||||
|
address: '0x323b5d4c32345ced77393b3530b1eed0f346429d',
|
||||||
|
precision: '5',
|
||||||
|
},
|
||||||
|
tokenB: {
|
||||||
|
address: '0xef7fff64389b814a946f3e92105513705ca6b990',
|
||||||
|
precision: '5',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, relayerApiTokenPairsResponseSchema, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#jsNumberSchema', () => {
|
||||||
|
it('should validate valid js number', () => {
|
||||||
|
const testCases = [
|
||||||
|
1,
|
||||||
|
42,
|
||||||
|
];
|
||||||
|
validateAgainstSchema(testCases, jsNumber);
|
||||||
|
});
|
||||||
|
it('should fail for invalid js number', () => {
|
||||||
|
const testCases = [
|
||||||
|
NaN,
|
||||||
|
-1,
|
||||||
|
new BigNumber(1),
|
||||||
|
];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, jsNumber, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#txDataSchema', () => {
|
||||||
|
it('should validate valid txData', () => {
|
||||||
|
const testCases = [
|
||||||
|
{
|
||||||
|
from: NULL_ADDRESS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: NULL_ADDRESS,
|
||||||
|
gas: new BigNumber(42),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: NULL_ADDRESS,
|
||||||
|
gas: 42,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
validateAgainstSchema(testCases, txDataSchema);
|
||||||
|
});
|
||||||
|
it('should fail for invalid txData', () => {
|
||||||
|
const testCases = [
|
||||||
|
{
|
||||||
|
gas: new BigNumber(42),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: NULL_ADDRESS,
|
||||||
|
unknownProp: 'here',
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
[],
|
||||||
|
new BigNumber(1),
|
||||||
|
];
|
||||||
|
const shouldFail = true;
|
||||||
|
validateAgainstSchema(testCases, txDataSchema, shouldFail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
17
packages/json-schemas/tsconfig.json
Normal file
17
packages/json-schemas/tsconfig.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "es5",
|
||||||
|
"lib": [ "es2017", "dom"],
|
||||||
|
"outDir": "lib",
|
||||||
|
"sourceMap": true,
|
||||||
|
"declaration": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"strictNullChecks": true
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"./src/**/*",
|
||||||
|
"./test/**/*",
|
||||||
|
"../../node_modules/chai-typescript-typings/index.d.ts"
|
||||||
|
]
|
||||||
|
}
|
5
packages/json-schemas/tslint.json
Normal file
5
packages/json-schemas/tslint.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"extends": [
|
||||||
|
"@0xproject/tslint-config"
|
||||||
|
]
|
||||||
|
}
|
6
packages/tslint-config/CHANGELOG.md
Normal file
6
packages/tslint-config/CHANGELOG.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# CHANGELOG
|
||||||
|
|
||||||
|
v0.1.0 - _Nov. 14, 2017_
|
||||||
|
------------------------
|
||||||
|
* Re-published TsLintConfig previously published under NPM package `tslint-config-0xproject`
|
||||||
|
* Updated to TSLint v5.8.0, requiring several rule additions to keep our conventions aligned.
|
10
packages/tslint-config/README.md
Normal file
10
packages/tslint-config/README.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
tslint-config
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Lint rules related to 0xProject for TSLint.
|
||||||
|
|
||||||
|
## Install:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install @0xproject/tslint-config --save-dev
|
||||||
|
```
|
38
packages/tslint-config/package.json
Normal file
38
packages/tslint-config/package.json
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"name": "@0xproject/tslint-config",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "Lint rules related to 0xProject for TSLint",
|
||||||
|
"main": "tslint.json",
|
||||||
|
"files": [
|
||||||
|
"tslint.js",
|
||||||
|
"README.md",
|
||||||
|
"LICENSE"
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git://github.com/0xProject/0x.js.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"tslint",
|
||||||
|
"config",
|
||||||
|
"0xProject",
|
||||||
|
"typescript",
|
||||||
|
"ts"
|
||||||
|
],
|
||||||
|
"author": {
|
||||||
|
"name": "Fabio Berger",
|
||||||
|
"email": "fabio@0xproject.com"
|
||||||
|
},
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/0xProject/0x.js/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/0xProject/0x.js/packages/tslint-config/README.md",
|
||||||
|
"devDependencies": {
|
||||||
|
"tslint": "5.8.0",
|
||||||
|
"typescript": "2.6.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"tslint-react": "^3.2.0"
|
||||||
|
}
|
||||||
|
}
|
14
packages/tslint-config/scripts/postpublish.js
Normal file
14
packages/tslint-config/scripts/postpublish.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
const postpublish_utils = require('../../../scripts/postpublish_utils');
|
||||||
|
const packageJSON = require('../package.json');
|
||||||
|
|
||||||
|
const subPackageName = packageJSON.name;
|
||||||
|
|
||||||
|
postpublish_utils.getLatestTagAndVersionAsync(subPackageName)
|
||||||
|
.then(function(result) {
|
||||||
|
const releaseName = postpublish_utils.getReleaseName(subPackageName, result.version);
|
||||||
|
const assets = [];
|
||||||
|
return postpublish_utils.publishReleaseNotes(result.tag, releaseName, assets);
|
||||||
|
})
|
||||||
|
.catch (function(err) {
|
||||||
|
throw err;
|
||||||
|
});
|
53
packages/tslint-config/tslint.json
Normal file
53
packages/tslint-config/tslint.json
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"extends": [
|
||||||
|
"tslint:latest",
|
||||||
|
"tslint-react"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"arrow-parens": [true, "ban-single-arg-parens"],
|
||||||
|
"ordered-imports": false,
|
||||||
|
"quotemark": [true, "single", "avoid-escape", "jsx-double"],
|
||||||
|
"callable-types": true,
|
||||||
|
"interface-name": false,
|
||||||
|
"interface-over-type-literal": true,
|
||||||
|
"object-literal-sort-keys": false,
|
||||||
|
"max-classes-per-file": false,
|
||||||
|
"max-line-length": [true, 120],
|
||||||
|
"member-ordering": [true,
|
||||||
|
"public-before-private",
|
||||||
|
"static-before-instance",
|
||||||
|
"variables-before-functions"
|
||||||
|
],
|
||||||
|
"no-angle-bracket-type-assertion": true,
|
||||||
|
"no-default-export": true,
|
||||||
|
"no-empty-interface": false,
|
||||||
|
"no-string-throw": true,
|
||||||
|
"no-submodule-imports": false,
|
||||||
|
"no-implicit-dependencies": [true, "dev"],
|
||||||
|
"prefer-const": true,
|
||||||
|
"variable-name": [true,
|
||||||
|
"ban-keywords",
|
||||||
|
"allow-pascal-case"
|
||||||
|
],
|
||||||
|
"whitespace": [
|
||||||
|
true,
|
||||||
|
"check-branch",
|
||||||
|
"check-decl",
|
||||||
|
"check-operator",
|
||||||
|
"check-separator",
|
||||||
|
"check-rest-spread",
|
||||||
|
"check-type",
|
||||||
|
"check-typecast",
|
||||||
|
"check-preblock"
|
||||||
|
],
|
||||||
|
"jsx-alignment": true,
|
||||||
|
"jsx-boolean-value": true,
|
||||||
|
"jsx-curly-spacing": [true, "never"],
|
||||||
|
"jsx-no-lambda": true,
|
||||||
|
"jsx-no-multiline-js": false,
|
||||||
|
"jsx-no-string-ref": true,
|
||||||
|
"jsx-self-close": true,
|
||||||
|
"jsx-wrap-multiline": false,
|
||||||
|
"jsx-no-bind": false
|
||||||
|
}
|
||||||
|
}
|
51
scripts/postpublish_utils.js
Normal file
51
scripts/postpublish_utils.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
const execAsync = require('async-child-process').execAsync;
|
||||||
|
const semverSort = require('semver-sort');
|
||||||
|
const promisify = require('es6-promisify');
|
||||||
|
const publishRelease = require('publish-release');
|
||||||
|
|
||||||
|
const publishReleaseAsync = promisify(publishRelease);
|
||||||
|
const githubPersonalAccessToken = process.env.GITHUB_PERSONAL_ACCESS_TOKEN_0X_JS;
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getLatestTagAndVersionAsync: function(subPackageName) {
|
||||||
|
const subPackagePrefix = subPackageName + '@';
|
||||||
|
const gitTagsCommand = 'git tags -l "' + subPackagePrefix + '*"';
|
||||||
|
return execAsync(gitTagsCommand)
|
||||||
|
.then(function(result) {
|
||||||
|
if (result.stderr !== '') {
|
||||||
|
throw new Error(result.stderr);
|
||||||
|
}
|
||||||
|
const tags = result.stdout.trim().split('\n');
|
||||||
|
const versions = tags.map(function(tag) {
|
||||||
|
return tag.slice(subPackagePrefix.length);
|
||||||
|
});
|
||||||
|
const sortedVersions = semverSort.desc(versions);
|
||||||
|
const latestVersion = sortedVersions[0];
|
||||||
|
const latestTag = subPackagePrefix + latestVersion;
|
||||||
|
return {
|
||||||
|
tag: latestTag,
|
||||||
|
version: latestVersion
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
publishReleaseNotes: function(tag, releaseName, assets) {
|
||||||
|
console.log('POSTPUBLISH: Releasing ', releaseName, '...');
|
||||||
|
return publishReleaseAsync({
|
||||||
|
token: githubPersonalAccessToken,
|
||||||
|
owner: '0xProject',
|
||||||
|
repo: '0x.js',
|
||||||
|
tag: tag,
|
||||||
|
name: releaseName,
|
||||||
|
notes: 'TODO',
|
||||||
|
draft: false,
|
||||||
|
prerelease: false,
|
||||||
|
reuseRelease: true,
|
||||||
|
reuseDraftOnly: false,
|
||||||
|
assets: assets,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getReleaseName(subPackageName, version) {
|
||||||
|
const releaseName = subPackageName + ' v' + version;
|
||||||
|
return releaseName;
|
||||||
|
},
|
||||||
|
};
|
152
yarn.lock
152
yarn.lock
@ -2,20 +2,17 @@
|
|||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
"0x-json-schemas@^0.6.1", "0x-json-schemas@^0.6.5":
|
"@types/fetch-mock@^5.12.1":
|
||||||
version "0.6.6"
|
version "5.12.2"
|
||||||
resolved "https://registry.yarnpkg.com/0x-json-schemas/-/0x-json-schemas-0.6.6.tgz#3852e639245474a14daa2f8c454ba83ca5df8a9c"
|
resolved "https://registry.yarnpkg.com/@types/fetch-mock/-/fetch-mock-5.12.2.tgz#8c96517ff74303031c65c5da2d99858e34c844d2"
|
||||||
dependencies:
|
|
||||||
jsonschema "^1.2.0"
|
|
||||||
lodash.values "^4.3.0"
|
|
||||||
|
|
||||||
"@types/bintrees@^1.0.2":
|
"@types/bintrees@^1.0.2":
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@types/bintrees/-/bintrees-1.0.2.tgz#0dfdce4eeebdf90427bd35b0e79dc248b3d157a6"
|
resolved "https://registry.yarnpkg.com/@types/bintrees/-/bintrees-1.0.2.tgz#0dfdce4eeebdf90427bd35b0e79dc248b3d157a6"
|
||||||
|
|
||||||
"@types/fs-extra@^4.0.0":
|
"@types/fs-extra@^4.0.0":
|
||||||
version "4.0.4"
|
version "4.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-4.0.4.tgz#72947e108f2cbeda5ab288a927399fdf6d02bd42"
|
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-4.0.5.tgz#8aa6033c0e87c653b09a6711686916864b48ec9e"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
@ -40,7 +37,19 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
jsonschema "*"
|
jsonschema "*"
|
||||||
|
|
||||||
"@types/lodash@^4.14.37", "@types/lodash@^4.14.64", "@types/lodash@^4.14.78":
|
"@types/lodash.foreach@^4.5.3":
|
||||||
|
version "4.5.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/lodash.foreach/-/lodash.foreach-4.5.3.tgz#87c01a0c5d9d17eec936ca3c28897af79440cdfc"
|
||||||
|
dependencies:
|
||||||
|
"@types/lodash" "*"
|
||||||
|
|
||||||
|
"@types/lodash.values@^4.3.3":
|
||||||
|
version "4.3.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/lodash.values/-/lodash.values-4.3.3.tgz#910edc65b391782d65dc4b4d8804a0dabc5370e6"
|
||||||
|
dependencies:
|
||||||
|
"@types/lodash" "*"
|
||||||
|
|
||||||
|
"@types/lodash@*", "@types/lodash@^4.14.37", "@types/lodash@^4.14.64", "@types/lodash@^4.14.77", "@types/lodash@^4.14.78":
|
||||||
version "4.14.85"
|
version "4.14.85"
|
||||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.85.tgz#a16fbf942422f6eca5622b6910492c496c35069b"
|
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.85.tgz#a16fbf942422f6eca5622b6910492c496c35069b"
|
||||||
|
|
||||||
@ -48,7 +57,11 @@
|
|||||||
version "0.0.28"
|
version "0.0.28"
|
||||||
resolved "https://registry.yarnpkg.com/@types/marked/-/marked-0.0.28.tgz#44ba754e9fa51432583e8eb30a7c4dd249b52faa"
|
resolved "https://registry.yarnpkg.com/@types/marked/-/marked-0.0.28.tgz#44ba754e9fa51432583e8eb30a7c4dd249b52faa"
|
||||||
|
|
||||||
"@types/minimatch@*", "@types/minimatch@^2.0.29":
|
"@types/minimatch@*":
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.1.tgz#b683eb60be358304ef146f5775db4c0e3696a550"
|
||||||
|
|
||||||
|
"@types/minimatch@^2.0.29":
|
||||||
version "2.0.29"
|
version "2.0.29"
|
||||||
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-2.0.29.tgz#5002e14f75e2d71e564281df0431c8c1b4a2a36a"
|
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-2.0.29.tgz#5002e14f75e2d71e564281df0431c8c1b4a2a36a"
|
||||||
|
|
||||||
@ -60,9 +73,13 @@
|
|||||||
version "8.0.51"
|
version "8.0.51"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.51.tgz#b31d716fb8d58eeb95c068a039b9b6292817d5fb"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.51.tgz#b31d716fb8d58eeb95c068a039b9b6292817d5fb"
|
||||||
|
|
||||||
|
"@types/query-string@^5.0.1":
|
||||||
|
version "5.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/query-string/-/query-string-5.0.1.tgz#6cb41c724cb1644d56c2d1dae7c7b204e706b39e"
|
||||||
|
|
||||||
"@types/shelljs@^0.7.0":
|
"@types/shelljs@^0.7.0":
|
||||||
version "0.7.5"
|
version "0.7.6"
|
||||||
resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.7.5.tgz#5834fb7385d1137bd2be5842f2c278ac36a117f4"
|
resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.7.6.tgz#4ac7ca01c191ba65b8e2bf50543c5560084d8d27"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/glob" "*"
|
"@types/glob" "*"
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
@ -81,6 +98,12 @@
|
|||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@types/valid-url/-/valid-url-1.0.2.tgz#60fa435ce24bfd5ba107b8d2a80796aeaf3a8f45"
|
resolved "https://registry.yarnpkg.com/@types/valid-url/-/valid-url-1.0.2.tgz#60fa435ce24bfd5ba107b8d2a80796aeaf3a8f45"
|
||||||
|
|
||||||
|
"@types/websocket@^0.0.34":
|
||||||
|
version "0.0.34"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/websocket/-/websocket-0.0.34.tgz#25596764cec885eda070fdb6d19cd76fe582747c"
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
|
||||||
JSONStream@^1.0.4:
|
JSONStream@^1.0.4:
|
||||||
version "1.3.1"
|
version "1.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.1.tgz#707f761e01dae9e16f1bcf93703b78c70966579a"
|
resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.1.tgz#707f761e01dae9e16f1bcf93703b78c70966579a"
|
||||||
@ -308,6 +331,12 @@ assertion-error@^1.0.1:
|
|||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c"
|
resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c"
|
||||||
|
|
||||||
|
async-child-process@^1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/async-child-process/-/async-child-process-1.1.1.tgz#27d0a598b5738707f9898c048bd231340583747b"
|
||||||
|
dependencies:
|
||||||
|
babel-runtime "^6.11.6"
|
||||||
|
|
||||||
async-each@^1.0.0:
|
async-each@^1.0.0:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
|
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
|
||||||
@ -725,7 +754,7 @@ babel-register@^6.26.0:
|
|||||||
mkdirp "^0.5.1"
|
mkdirp "^0.5.1"
|
||||||
source-map-support "^0.4.15"
|
source-map-support "^0.4.15"
|
||||||
|
|
||||||
babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0:
|
babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0:
|
||||||
version "6.26.0"
|
version "6.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
|
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -876,7 +905,7 @@ bn.js@4.11.7:
|
|||||||
version "4.11.7"
|
version "4.11.7"
|
||||||
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.7.tgz#ddb048e50d9482790094c13eb3fcfc833ce7ab46"
|
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.7.tgz#ddb048e50d9482790094c13eb3fcfc833ce7ab46"
|
||||||
|
|
||||||
bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.10.0, bn.js@^4.11.3, bn.js@^4.11.7, bn.js@^4.4.0, bn.js@^4.8.0:
|
bn.js@4.11.8, bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.10.0, bn.js@^4.11.3, bn.js@^4.11.7, bn.js@^4.4.0, bn.js@^4.8.0:
|
||||||
version "4.11.8"
|
version "4.11.8"
|
||||||
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
|
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
|
||||||
|
|
||||||
@ -1031,7 +1060,7 @@ buffer@^5.0.6:
|
|||||||
base64-js "^1.0.2"
|
base64-js "^1.0.2"
|
||||||
ieee754 "^1.1.4"
|
ieee754 "^1.1.4"
|
||||||
|
|
||||||
builtin-modules@^1.0.0:
|
builtin-modules@^1.0.0, builtin-modules@^1.1.1:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
|
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
|
||||||
|
|
||||||
@ -1127,7 +1156,7 @@ chai-typescript-typings@^0.0.1:
|
|||||||
version "0.0.1"
|
version "0.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/chai-typescript-typings/-/chai-typescript-typings-0.0.1.tgz#433dee303b0b2978ad0dd03129df0a5afb791274"
|
resolved "https://registry.yarnpkg.com/chai-typescript-typings/-/chai-typescript-typings-0.0.1.tgz#433dee303b0b2978ad0dd03129df0a5afb791274"
|
||||||
|
|
||||||
chai@^4.0.1:
|
chai@^4.0.1, chai@^4.1.1:
|
||||||
version "4.1.2"
|
version "4.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/chai/-/chai-4.1.2.tgz#0f64584ba642f0f2ace2806279f4f06ca23ad73c"
|
resolved "https://registry.yarnpkg.com/chai/-/chai-4.1.2.tgz#0f64584ba642f0f2ace2806279f4f06ca23ad73c"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -2284,6 +2313,14 @@ fast-json-stable-stringify@^2.0.0:
|
|||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
|
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
|
||||||
|
|
||||||
|
fetch-mock@^5.13.1:
|
||||||
|
version "5.13.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/fetch-mock/-/fetch-mock-5.13.1.tgz#955794a77f3d972f1644b9ace65a0fdfd60f1df7"
|
||||||
|
dependencies:
|
||||||
|
glob-to-regexp "^0.3.0"
|
||||||
|
node-fetch "^1.3.3"
|
||||||
|
path-to-regexp "^1.7.0"
|
||||||
|
|
||||||
fetch-ponyfill@^4.0.0:
|
fetch-ponyfill@^4.0.0:
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz#ae3ce5f732c645eab87e4ae8793414709b239893"
|
resolved "https://registry.yarnpkg.com/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz#ae3ce5f732c645eab87e4ae8793414709b239893"
|
||||||
@ -2602,6 +2639,10 @@ glob-parent@^3.1.0:
|
|||||||
is-glob "^3.1.0"
|
is-glob "^3.1.0"
|
||||||
path-dirname "^1.0.0"
|
path-dirname "^1.0.0"
|
||||||
|
|
||||||
|
glob-to-regexp@^0.3.0:
|
||||||
|
version "0.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
|
||||||
|
|
||||||
glob@7.1.2, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2, glob@~7.1.2:
|
glob@7.1.2, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2, glob@~7.1.2:
|
||||||
version "7.1.2"
|
version "7.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
|
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
|
||||||
@ -3143,7 +3184,7 @@ is-text-path@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
text-extensions "^1.0.0"
|
text-extensions "^1.0.0"
|
||||||
|
|
||||||
is-typedarray@~1.0.0:
|
is-typedarray@^1.0.0, is-typedarray@~1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
|
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
|
||||||
|
|
||||||
@ -3177,7 +3218,7 @@ isobject@^3.0.0, isobject@^3.0.1:
|
|||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
|
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
|
||||||
|
|
||||||
isomorphic-fetch@^2.2.0:
|
isomorphic-fetch@^2.2.0, isomorphic-fetch@^2.2.1:
|
||||||
version "2.2.1"
|
version "2.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
|
resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -3555,6 +3596,10 @@ lodash.assign@^4.0.3, lodash.assign@^4.0.6:
|
|||||||
version "4.2.0"
|
version "4.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7"
|
resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7"
|
||||||
|
|
||||||
|
lodash.foreach@^4.5.0:
|
||||||
|
version "4.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53"
|
||||||
|
|
||||||
lodash.get@^4.4.2:
|
lodash.get@^4.4.2:
|
||||||
version "4.4.2"
|
version "4.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
|
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
|
||||||
@ -3880,7 +3925,7 @@ mute-stream@0.0.7, mute-stream@~0.0.4:
|
|||||||
version "0.0.7"
|
version "0.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
|
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
|
||||||
|
|
||||||
nan@^2.0.5, nan@^2.0.8, nan@^2.2.1, nan@^2.3.0:
|
nan@^2.0.5, nan@^2.0.8, nan@^2.2.1, nan@^2.3.0, nan@^2.3.3:
|
||||||
version "2.7.0"
|
version "2.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.7.0.tgz#d95bf721ec877e08db276ed3fc6eb78f9083ad46"
|
resolved "https://registry.yarnpkg.com/nan/-/nan-2.7.0.tgz#d95bf721ec877e08db276ed3fc6eb78f9083ad46"
|
||||||
|
|
||||||
@ -3916,7 +3961,7 @@ node-abi@^2.1.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
semver "^5.4.1"
|
semver "^5.4.1"
|
||||||
|
|
||||||
node-fetch@^1.0.1, node-fetch@~1.7.1:
|
node-fetch@^1.0.1, node-fetch@^1.3.3, node-fetch@~1.7.1:
|
||||||
version "1.7.3"
|
version "1.7.3"
|
||||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef"
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -4473,9 +4518,9 @@ public-encrypt@^4.0.0:
|
|||||||
parse-asn1 "^5.0.0"
|
parse-asn1 "^5.0.0"
|
||||||
randombytes "^2.0.1"
|
randombytes "^2.0.1"
|
||||||
|
|
||||||
publish-release@^1.3.3:
|
publish-release@0xproject/publish-release:
|
||||||
version "1.3.3"
|
version "1.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/publish-release/-/publish-release-1.3.3.tgz#6cd11df835e14c13b0e08a35d3fb992b918bec3c"
|
resolved "https://codeload.github.com/0xproject/publish-release/tar.gz/c67c546726deecabd0cb35f9873afc912f862bd3"
|
||||||
dependencies:
|
dependencies:
|
||||||
async "^0.9.0"
|
async "^0.9.0"
|
||||||
ghauth "^2.0.0"
|
ghauth "^2.0.0"
|
||||||
@ -4518,6 +4563,14 @@ qs@~6.5.1:
|
|||||||
version "6.5.1"
|
version "6.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
|
||||||
|
|
||||||
|
query-string@^5.0.1:
|
||||||
|
version "5.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.0.1.tgz#6e2b86fe0e08aef682ecbe86e85834765402bd88"
|
||||||
|
dependencies:
|
||||||
|
decode-uri-component "^0.2.0"
|
||||||
|
object-assign "^4.1.0"
|
||||||
|
strict-uri-encode "^1.0.0"
|
||||||
|
|
||||||
querystring-es3@^0.2.0:
|
querystring-es3@^0.2.0:
|
||||||
version "0.2.1"
|
version "0.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
|
resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
|
||||||
@ -4944,7 +4997,14 @@ semver-regex@^1.0.0:
|
|||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-1.0.0.tgz#92a4969065f9c70c694753d55248fc68f8f652c9"
|
resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-1.0.0.tgz#92a4969065f9c70c694753d55248fc68f8f652c9"
|
||||||
|
|
||||||
"semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@~5.4.1:
|
semver-sort@^0.0.4:
|
||||||
|
version "0.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/semver-sort/-/semver-sort-0.0.4.tgz#34fdbddc6a6b2b4161398c3c4dba56243bfeaa8b"
|
||||||
|
dependencies:
|
||||||
|
semver "^5.0.3"
|
||||||
|
semver-regex "^1.0.0"
|
||||||
|
|
||||||
|
"semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@~5.4.1:
|
||||||
version "5.4.1"
|
version "5.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e"
|
||||||
|
|
||||||
@ -5278,6 +5338,10 @@ stream-http@^2.3.1:
|
|||||||
to-arraybuffer "^1.0.0"
|
to-arraybuffer "^1.0.0"
|
||||||
xtend "^4.0.0"
|
xtend "^4.0.0"
|
||||||
|
|
||||||
|
strict-uri-encode@^1.0.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
|
||||||
|
|
||||||
string-editor@^0.1.0:
|
string-editor@^0.1.0:
|
||||||
version "0.1.2"
|
version "0.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/string-editor/-/string-editor-0.1.2.tgz#f5ff1b5ac4aed7ac6c2fb8de236d1551b20f61d0"
|
resolved "https://registry.yarnpkg.com/string-editor/-/string-editor-0.1.2.tgz#f5ff1b5ac4aed7ac6c2fb8de236d1551b20f61d0"
|
||||||
@ -5620,24 +5684,19 @@ tslib@^1.7.1:
|
|||||||
version "1.8.0"
|
version "1.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.8.0.tgz#dc604ebad64bcbf696d613da6c954aa0e7ea1eb6"
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.8.0.tgz#dc604ebad64bcbf696d613da6c954aa0e7ea1eb6"
|
||||||
|
|
||||||
tslint-config-0xproject@^0.0.2:
|
tslint-react@^3.2.0:
|
||||||
version "0.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/tslint-config-0xproject/-/tslint-config-0xproject-0.0.2.tgz#39901e0c0b3e9388f00092a28b90c015395d5bba"
|
|
||||||
dependencies:
|
|
||||||
tslint-react "^3.0.0"
|
|
||||||
|
|
||||||
tslint-react@^3.0.0:
|
|
||||||
version "3.2.0"
|
version "3.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/tslint-react/-/tslint-react-3.2.0.tgz#851fb505201c63d0343c51726e6364f7e9ad2e99"
|
resolved "https://registry.yarnpkg.com/tslint-react/-/tslint-react-3.2.0.tgz#851fb505201c63d0343c51726e6364f7e9ad2e99"
|
||||||
dependencies:
|
dependencies:
|
||||||
tsutils "^2.8.0"
|
tsutils "^2.8.0"
|
||||||
|
|
||||||
tslint@~5.5.0:
|
tslint@5.8.0:
|
||||||
version "5.5.0"
|
version "5.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.5.0.tgz#10e8dab3e3061fa61e9442e8cee3982acf20a6aa"
|
resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.8.0.tgz#1f49ad5b2e77c76c3af4ddcae552ae4e3612eb13"
|
||||||
dependencies:
|
dependencies:
|
||||||
babel-code-frame "^6.22.0"
|
babel-code-frame "^6.22.0"
|
||||||
colors "^1.1.2"
|
builtin-modules "^1.1.1"
|
||||||
|
chalk "^2.1.0"
|
||||||
commander "^2.9.0"
|
commander "^2.9.0"
|
||||||
diff "^3.2.0"
|
diff "^3.2.0"
|
||||||
glob "^7.1.1"
|
glob "^7.1.1"
|
||||||
@ -5645,9 +5704,9 @@ tslint@~5.5.0:
|
|||||||
resolve "^1.3.2"
|
resolve "^1.3.2"
|
||||||
semver "^5.3.0"
|
semver "^5.3.0"
|
||||||
tslib "^1.7.1"
|
tslib "^1.7.1"
|
||||||
tsutils "^2.5.1"
|
tsutils "^2.12.1"
|
||||||
|
|
||||||
tsutils@^2.5.1, tsutils@^2.8.0:
|
tsutils@^2.12.1, tsutils@^2.8.0:
|
||||||
version "2.12.2"
|
version "2.12.2"
|
||||||
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.12.2.tgz#ad58a4865d17ec3ddb6631b6ca53be14a5656ff3"
|
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.12.2.tgz#ad58a4865d17ec3ddb6631b6ca53be14a5656ff3"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -5671,6 +5730,12 @@ type-detect@^4.0.0:
|
|||||||
version "4.0.5"
|
version "4.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.5.tgz#d70e5bc81db6de2a381bcaca0c6e0cbdc7635de2"
|
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.5.tgz#d70e5bc81db6de2a381bcaca0c6e0cbdc7635de2"
|
||||||
|
|
||||||
|
typedarray-to-buffer@^3.1.2:
|
||||||
|
version "3.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.2.tgz#1017b32d984ff556eba100f501589aba1ace2e04"
|
||||||
|
dependencies:
|
||||||
|
is-typedarray "^1.0.0"
|
||||||
|
|
||||||
typedarray@^0.0.6:
|
typedarray@^0.0.6:
|
||||||
version "0.0.6"
|
version "0.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||||
@ -5719,7 +5784,7 @@ typescript@2.4.1:
|
|||||||
version "2.4.1"
|
version "2.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.4.1.tgz#c3ccb16ddaa0b2314de031e7e6fee89e5ba346bc"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.4.1.tgz#c3ccb16ddaa0b2314de031e7e6fee89e5ba346bc"
|
||||||
|
|
||||||
typescript@^2.4.2, typescript@~2.6.1:
|
typescript@2.6.1, typescript@^2.4.2, typescript@~2.6.1:
|
||||||
version "2.6.1"
|
version "2.6.1"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.1.tgz#ef39cdea27abac0b500242d6726ab90e0c846631"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.1.tgz#ef39cdea27abac0b500242d6726ab90e0c846631"
|
||||||
|
|
||||||
@ -5982,6 +6047,15 @@ webpack@^3.0.0, webpack@^3.1.0:
|
|||||||
webpack-sources "^1.0.1"
|
webpack-sources "^1.0.1"
|
||||||
yargs "^8.0.2"
|
yargs "^8.0.2"
|
||||||
|
|
||||||
|
websocket@^1.0.25:
|
||||||
|
version "1.0.25"
|
||||||
|
resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.25.tgz#998ec790f0a3eacb8b08b50a4350026692a11958"
|
||||||
|
dependencies:
|
||||||
|
debug "^2.2.0"
|
||||||
|
nan "^2.3.3"
|
||||||
|
typedarray-to-buffer "^3.1.2"
|
||||||
|
yaeti "^0.0.6"
|
||||||
|
|
||||||
whatwg-fetch@>=0.10.0:
|
whatwg-fetch@>=0.10.0:
|
||||||
version "2.0.3"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
|
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
|
||||||
@ -6098,6 +6172,10 @@ y18n@^3.2.1:
|
|||||||
version "3.2.1"
|
version "3.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
|
resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
|
||||||
|
|
||||||
|
yaeti@^0.0.6:
|
||||||
|
version "0.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577"
|
||||||
|
|
||||||
yallist@^2.1.2:
|
yallist@^2.1.2:
|
||||||
version "2.1.2"
|
version "2.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
|
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user