aboutsummaryrefslogtreecommitdiffstats
path: root/packages/0x.js
diff options
context:
space:
mode:
authorLeonid <logvinov.leon@gmail.com>2017-11-21 04:46:53 +0800
committerGitHub <noreply@github.com>2017-11-21 04:46:53 +0800
commitd39c0bee39a7bc9cbab6810e8b1b42dfe2e6cf09 (patch)
treea02081e61b11bfb6bb643fcb4e8981541bb8d2bd /packages/0x.js
parent5788b90c522b63b53f5e8480f2b357ee24bb08a3 (diff)
parent037f466e1f80f635b48f3235258402e2ce75fb7b (diff)
downloaddexon-sol-tools-d39c0bee39a7bc9cbab6810e8b1b42dfe2e6cf09.tar
dexon-sol-tools-d39c0bee39a7bc9cbab6810e8b1b42dfe2e6cf09.tar.gz
dexon-sol-tools-d39c0bee39a7bc9cbab6810e8b1b42dfe2e6cf09.tar.bz2
dexon-sol-tools-d39c0bee39a7bc9cbab6810e8b1b42dfe2e6cf09.tar.lz
dexon-sol-tools-d39c0bee39a7bc9cbab6810e8b1b42dfe2e6cf09.tar.xz
dexon-sol-tools-d39c0bee39a7bc9cbab6810e8b1b42dfe2e6cf09.tar.zst
dexon-sol-tools-d39c0bee39a7bc9cbab6810e8b1b42dfe2e6cf09.zip
Merge branch 'development' into feature/orderExpired
Diffstat (limited to 'packages/0x.js')
-rw-r--r--packages/0x.js/CHANGELOG.md11
-rw-r--r--packages/0x.js/README.md3
-rw-r--r--packages/0x.js/package.json23
-rw-r--r--packages/0x.js/scripts/postpublish.js43
-rwxr-xr-xpackages/0x.js/scripts/test_umd.sh1
-rw-r--r--packages/0x.js/src/0x.ts2
-rw-r--r--packages/0x.js/src/contract.ts2
-rw-r--r--packages/0x.js/src/contract_wrappers/exchange_wrapper.ts2
-rw-r--r--packages/0x.js/src/contract_wrappers/token_wrapper.ts2
-rw-r--r--packages/0x.js/src/index.ts2
-rw-r--r--packages/0x.js/src/order_watcher/event_watcher.ts2
-rw-r--r--packages/0x.js/src/order_watcher/order_state_watcher.ts41
-rw-r--r--packages/0x.js/src/types.ts14
-rw-r--r--packages/0x.js/src/utils/abi_decoder.ts2
-rw-r--r--packages/0x.js/src/utils/assert.ts7
-rw-r--r--packages/0x.js/src/utils/order_state_utils.ts13
-rw-r--r--packages/0x.js/test/order_state_watcher_test.ts222
-rw-r--r--packages/0x.js/test/token_registry_wrapper_test.ts2
-rw-r--r--packages/0x.js/tslint.json2
19 files changed, 256 insertions, 140 deletions
diff --git a/packages/0x.js/CHANGELOG.md b/packages/0x.js/CHANGELOG.md
index a9362151c..6245308c3 100644
--- a/packages/0x.js/CHANGELOG.md
+++ b/packages/0x.js/CHANGELOG.md
@@ -1,13 +1,20 @@
# 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
+ * 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_
------------------------
* Fixed unhandled promise rejection error in subscribe methods (#209)
- * Subscribe callbacks now receive an error object as their first argument
+ * Subscribe callbacks now receive an error object as their first argument
v0.22.6 - _November 10, 2017_
------------------------
diff --git a/packages/0x.js/README.md b/packages/0x.js/README.md
index 4b6cc8df4..6cdcbde70 100644
--- a/packages/0x.js/README.md
+++ b/packages/0x.js/README.md
@@ -1,3 +1,6 @@
+0x.js
+-----
+
## Installation
0x.js ships as both a [UMD](https://github.com/umdjs/umd) module and a [CommonJS](https://en.wikipedia.org/wiki/CommonJS) package.
diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json
index 539a78f37..4fe11a8dc 100644
--- a/packages/0x.js/package.json
+++ b/packages/0x.js/package.json
@@ -1,6 +1,6 @@
{
"name": "0x.js",
- "version": "0.23.0",
+ "version": "0.25.1",
"description": "A javascript library for interacting with the 0x protocol",
"keywords": [
"0x.js",
@@ -13,11 +13,9 @@
"types": "lib/src/index.d.ts",
"scripts": {
"prebuild": "npm run clean",
- "build": "run-p build:umd:prod build:commonjs",
- "prepublishOnly": "run-p build",
- "postpublish": "run-s release docs:json upload_docs_json",
- "release": "publish-release --assets _bundles/index.js,_bundles/index.min.js --tag $(git describe --tags) --owner 0xProject --repo 0x.js",
- "upload_docs_json": "aws s3 cp docs/index.json s3://0xjs-docs-jsons/$(git describe --tags).json --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type aplication/json",
+ "build": "run-p build:umd:prod build:commonjs; exit 0;",
+ "docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_DIR",
+ "upload_docs_json": "aws s3 cp docs/index.json $S3_URL --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type aplication/json",
"lint": "tslint src/**/*.ts test/**/*.ts",
"test:circleci": "run-s test:coverage report_test_coverage; if [ $CIRCLE_BRANCH = \"development\" ]; then yarn test:umd; fi",
"test": "run-s clean test:commonjs",
@@ -25,9 +23,6 @@
"test:coverage": "nyc npm run test --all",
"report_test_coverage": "nyc report --reporter=text-lcov | coveralls",
"update_contracts": "for i in ${npm_package_config_artifacts}; do copyfiles -u 4 ../contracts/build/contracts/$i.json ../0x.js/src/artifacts; done;",
- "docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json docs/index.json .",
- "docs:generate": "typedoc --out docs .",
- "docs:open": "opn docs/index.html",
"clean": "shx rm -rf _bundles lib test_temp",
"build:umd:dev": "webpack",
"build:umd:prod": "NODE_ENV=production webpack",
@@ -49,6 +44,7 @@
"node": ">=6.0.0"
},
"devDependencies": {
+ "@0xproject/tslint-config": "^0.1.0",
"@types/bintrees": "^1.0.2",
"@types/jsonschema": "^1.1.1",
"@types/lodash": "^4.14.64",
@@ -77,8 +73,7 @@
"sinon": "^4.0.0",
"source-map-support": "^0.5.0",
"truffle-hdwallet-provider": "^0.0.3",
- "tslint": "~5.5.0",
- "tslint-config-0xproject": "^0.0.2",
+ "tslint": "5.8.0",
"typedoc": "~0.8.0",
"types-bn": "^0.0.1",
"types-ethereumjs-util": "0xProject/types-ethereumjs-util",
@@ -88,10 +83,11 @@
"webpack": "^3.1.0"
},
"dependencies": {
- "0x-json-schemas": "^0.6.1",
- "@0xproject/assert": "0.0.3",
+ "@0xproject/assert": "^0.0.4",
+ "@0xproject/json-schemas": "^0.6.7",
"bignumber.js": "~4.1.0",
"bintrees": "^1.0.2",
+ "bn.js": "4.11.8",
"compare-versions": "^3.0.1",
"es6-promisify": "^5.0.0",
"ethereumjs-abi": "^0.6.4",
@@ -100,7 +96,6 @@
"find-versions": "^2.0.0",
"js-sha3": "^0.6.1",
"lodash": "^4.17.4",
- "publish-release": "^1.3.3",
"uuid": "^3.1.0",
"web3": "^0.20.0"
}
diff --git a/packages/0x.js/scripts/postpublish.js b/packages/0x.js/scripts/postpublish.js
new file mode 100644
index 000000000..ffc68afb4
--- /dev/null
+++ b/packages/0x.js/scripts/postpublish.js
@@ -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;
+ });
diff --git a/packages/0x.js/scripts/test_umd.sh b/packages/0x.js/scripts/test_umd.sh
index d200c76d0..e3eba088a 100755
--- a/packages/0x.js/scripts/test_umd.sh
+++ b/packages/0x.js/scripts/test_umd.sh
@@ -3,5 +3,4 @@
# UMD tests should only be run after building the commonjs because they reuse some of the commonjs build artifacts
run-s substitute_umd_bundle run_mocha
return_code=$?
-npm run clean
exit $return_code
diff --git a/packages/0x.js/src/0x.ts b/packages/0x.js/src/0x.ts
index fe765bbbe..85c2b7724 100644
--- a/packages/0x.js/src/0x.ts
+++ b/packages/0x.js/src/0x.ts
@@ -1,6 +1,6 @@
import * as _ from 'lodash';
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 * as ethUtil from 'ethereumjs-util';
import {Web3Wrapper} from './web3_wrapper';
diff --git a/packages/0x.js/src/contract.ts b/packages/0x.js/src/contract.ts
index 1aacc65dc..7ccd336d6 100644
--- a/packages/0x.js/src/contract.ts
+++ b/packages/0x.js/src/contract.ts
@@ -1,7 +1,7 @@
import * as Web3 from 'web3';
import * as _ from 'lodash';
import promisify = require('es6-promisify');
-import {SchemaValidator, schemas} from '0x-json-schemas';
+import {SchemaValidator, schemas} from '@0xproject/json-schemas';
import {AbiType} from './types';
export class Contract implements Web3.ContractInstance {
diff --git a/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts b/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts
index 5acfd3cc9..3e631b73e 100644
--- a/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts
+++ b/packages/0x.js/src/contract_wrappers/exchange_wrapper.ts
@@ -1,7 +1,7 @@
import * as _ from 'lodash';
import * as Web3 from 'web3';
import BigNumber from 'bignumber.js';
-import {schemas} from '0x-json-schemas';
+import {schemas} from '@0xproject/json-schemas';
import {Web3Wrapper} from '../web3_wrapper';
import {
ECSignature,
diff --git a/packages/0x.js/src/contract_wrappers/token_wrapper.ts b/packages/0x.js/src/contract_wrappers/token_wrapper.ts
index 614ac19d4..4b89d3cfc 100644
--- a/packages/0x.js/src/contract_wrappers/token_wrapper.ts
+++ b/packages/0x.js/src/contract_wrappers/token_wrapper.ts
@@ -1,6 +1,6 @@
import * as _ from 'lodash';
import BigNumber from 'bignumber.js';
-import {schemas} from '0x-json-schemas';
+import {schemas} from '@0xproject/json-schemas';
import {Web3Wrapper} from '../web3_wrapper';
import {assert} from '../utils/assert';
import {constants} from '../utils/constants';
diff --git a/packages/0x.js/src/index.ts b/packages/0x.js/src/index.ts
index 1b3e893ba..e529e2858 100644
--- a/packages/0x.js/src/index.ts
+++ b/packages/0x.js/src/index.ts
@@ -6,8 +6,6 @@ export {
ECSignature,
ZeroExError,
EventCallback,
- EventCallbackAsync,
- EventCallbackSync,
ExchangeContractErrs,
ContractEvent,
Token,
diff --git a/packages/0x.js/src/order_watcher/event_watcher.ts b/packages/0x.js/src/order_watcher/event_watcher.ts
index da824bd09..ecbab0cd5 100644
--- a/packages/0x.js/src/order_watcher/event_watcher.ts
+++ b/packages/0x.js/src/order_watcher/event_watcher.ts
@@ -81,7 +81,7 @@ export class EventWatcher {
...log,
};
if (!_.isUndefined(this._intervalIdIfExists)) {
- await callback(logEvent);
+ callback(logEvent);
}
}
}
diff --git a/packages/0x.js/src/order_watcher/order_state_watcher.ts b/packages/0x.js/src/order_watcher/order_state_watcher.ts
index 975679f57..579fa388a 100644
--- a/packages/0x.js/src/order_watcher/order_state_watcher.ts
+++ b/packages/0x.js/src/order_watcher/order_state_watcher.ts
@@ -1,5 +1,5 @@
import * as _ from 'lodash';
-import {schemas} from '0x-json-schemas';
+import {schemas} from '@0xproject/json-schemas';
import {ZeroEx} from '../0x';
import {EventWatcher} from './event_watcher';
import {assert} from '../utils/assert';
@@ -53,7 +53,7 @@ interface OrderByOrderHash {
export class OrderStateWatcher {
private _orderByOrderHash: OrderByOrderHash = {};
private _dependentOrderHashes: DependentOrderHashes = {};
- private _callbackIfExistsAsync?: OnOrderStateChangeCallback;
+ private _callbackIfExists?: OnOrderStateChangeCallback;
private _eventWatcher: EventWatcher;
private _web3Wrapper: Web3Wrapper;
private _abiDecoder: AbiDecoder;
@@ -89,12 +89,12 @@ export class OrderStateWatcher {
* signature is verified.
* @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);
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
assert.isValidSignature(orderHash, signedOrder.ecSignature, signedOrder.maker);
this._orderByOrderHash[orderHash] = signedOrder;
- this.addToDependentOrderHashes(signedOrder, orderHash);
+ await this.addToDependentOrderHashesAsync(signedOrder, orderHash);
const expirationUnixTimestampMs = signedOrder.expirationUnixTimestampSec.times(1000);
this._expirationWatcher.addOrder(orderHash, expirationUnixTimestampMs);
}
@@ -102,13 +102,16 @@ export class OrderStateWatcher {
* Removes an order from the orderStateWatcher
* @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);
const signedOrder = this._orderByOrderHash[orderHash];
if (_.isUndefined(signedOrder)) {
return; // noop
}
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._expirationWatcher.removeOrder(orderHash);
}
@@ -120,10 +123,10 @@ export class OrderStateWatcher {
*/
public subscribe(callback: OnOrderStateChangeCallback): void {
assert.isFunction('callback', callback);
- if (!_.isUndefined(this._callbackIfExistsAsync)) {
+ if (!_.isUndefined(this._callbackIfExists)) {
throw new Error(ZeroExError.SubscriptionAlreadyPresent);
}
- this._callbackIfExistsAsync = callback;
+ this._callbackIfExists = callback;
this._eventWatcher.subscribe(this._onEventWatcherCallbackAsync.bind(this));
this._expirationWatcher.subscribe(this._onOrderExpired.bind(this));
}
@@ -131,12 +134,12 @@ export class OrderStateWatcher {
* Ends an orderStateWatcher subscription.
*/
public unsubscribe(): void {
- if (_.isUndefined(this._callbackIfExistsAsync)) {
+ if (_.isUndefined(this._callbackIfExists)) {
throw new Error(ZeroExError.SubscriptionNotFound);
}
this._balanceAndProxyAllowanceLazyStore.deleteAll();
this._orderFilledCancelledLazyStore.deleteAll();
- delete this._callbackIfExistsAsync;
+ delete this._callbackIfExists;
this._eventWatcher.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
// and only updated when cache is invalidated
const orderState = await this._orderStateUtils.getOrderStateAsync(signedOrder);
- if (_.isUndefined(this._callbackIfExistsAsync)) {
+ if (_.isUndefined(this._callbackIfExists)) {
break; // Unsubscribe was called
}
- await this._callbackIfExistsAsync(orderState);
+ this._callbackIfExists(orderState);
}
}
- private addToDependentOrderHashes(signedOrder: SignedOrder, orderHash: string) {
+ private async addToDependentOrderHashesAsync(signedOrder: SignedOrder, orderHash: string): Promise<void> {
if (_.isUndefined(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].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();
+ }
+ this._dependentOrderHashes[signedOrder.maker][zrxTokenAddress].add(orderHash);
}
- private removeFromDependentOrderHashes(makerAddress: string, makerTokenAddress: string, orderHash: string) {
- this._dependentOrderHashes[makerAddress][makerTokenAddress].delete(orderHash);
- if (this._dependentOrderHashes[makerAddress][makerTokenAddress].size === 0) {
- delete this._dependentOrderHashes[makerAddress][makerTokenAddress];
+ private removeFromDependentOrderHashes(makerAddress: string, tokenAddress: string, orderHash: string) {
+ this._dependentOrderHashes[makerAddress][tokenAddress].delete(orderHash);
+ if (this._dependentOrderHashes[makerAddress][tokenAddress].size === 0) {
+ delete this._dependentOrderHashes[makerAddress][tokenAddress];
}
if (_.isEmpty(this._dependentOrderHashes[makerAddress])) {
delete this._dependentOrderHashes[makerAddress];
diff --git a/packages/0x.js/src/types.ts b/packages/0x.js/src/types.ts
index 13a46659d..39c60695e 100644
--- a/packages/0x.js/src/types.ts
+++ b/packages/0x.js/src/types.ts
@@ -42,13 +42,8 @@ export type OrderValues = [BigNumber, BigNumber, BigNumber,
export type LogEvent = Web3.LogEntryEvent;
export type DecodedLogEvent<ArgsType> = Web3.DecodedLogEntryEvent<ArgsType>;
-export type EventCallbackAsync<ArgsType> = (err: null|Error, log?: DecodedLogEvent<ArgsType>) => Promise<void>;
-export type EventCallbackSync<ArgsType> = (err: null|Error, log?: DecodedLogEvent<ArgsType>) => void;
-export type EventCallback<ArgsType> = EventCallbackSync<ArgsType>|EventCallbackAsync<ArgsType>;
-
-export type EventWatcherCallbackSync = (log: LogEvent) => void;
-export type EventWatcherCallbackAsync = (log: LogEvent) => Promise<void>;
-export type EventWatcherCallback = EventWatcherCallbackSync|EventWatcherCallbackAsync;
+export type EventCallback<ArgsType> = (err: null|Error, log?: DecodedLogEvent<ArgsType>) => void;
+export type EventWatcherCallback = (log: LogEvent) => void;
export interface ExchangeContract extends Web3.ContractInstance {
isValidSignature: {
@@ -496,6 +491,7 @@ export interface OrderRelevantState {
filledTakerTokenAmount: BigNumber;
cancelledTakerTokenAmount: BigNumber;
remainingFillableMakerTokenAmount: BigNumber;
+ remainingFillableTakerTokenAmount: BigNumber;
}
export interface OrderStateValid {
@@ -512,9 +508,7 @@ export interface OrderStateInvalid {
export type OrderState = OrderStateValid|OrderStateInvalid;
-export type OnOrderStateChangeCallbackSync = (orderState: OrderState) => void;
-export type OnOrderStateChangeCallbackAsync = (orderState: OrderState) => Promise<void>;
-export type OnOrderStateChangeCallback = OnOrderStateChangeCallbackAsync|OnOrderStateChangeCallbackSync;
+export type OnOrderStateChangeCallback = (orderState: OrderState) => void;
export interface TransactionReceipt {
blockHash: string;
diff --git a/packages/0x.js/src/utils/abi_decoder.ts b/packages/0x.js/src/utils/abi_decoder.ts
index 840ad9be0..df0fb2d6f 100644
--- a/packages/0x.js/src/utils/abi_decoder.ts
+++ b/packages/0x.js/src/utils/abi_decoder.ts
@@ -34,7 +34,7 @@ export class AbiDecoder {
value = this.padZeros(new BigNumber(value).toString(16));
} else if (param.type === SolidityTypes.Uint256 ||
param.type === SolidityTypes.Uint8 ||
- param.type === SolidityTypes.Uint ) {
+ param.type === SolidityTypes.Uint) {
value = new BigNumber(value);
}
decodedParams[param.name] = value;
diff --git a/packages/0x.js/src/utils/assert.ts b/packages/0x.js/src/utils/assert.ts
index 4aa83ef17..55912525c 100644
--- a/packages/0x.js/src/utils/assert.ts
+++ b/packages/0x.js/src/utils/assert.ts
@@ -1,7 +1,7 @@
import * as _ from 'lodash';
import * as Web3 from 'web3';
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 {Web3Wrapper} from '../web3_wrapper';
import {signatureUtils} from '../utils/signature_utils';
@@ -9,7 +9,8 @@ import {ECSignature} from '../types';
const HEX_REGEX = /^0x[0-9A-F]*$/i;
-export const assert = _.extend({}, sharedAssert, {
+export const assert = {
+ ...sharedAssert,
isValidSignature(orderHash: string, ecSignature: ECSignature, signerAddress: string) {
const isValidSignature = signatureUtils.isValidSignature(orderHash, ecSignature, signerAddress);
this.assert(isValidSignature, `Expected order with hash '${orderHash}' to have a valid signature`);
@@ -26,4 +27,4 @@ export const assert = _.extend({}, sharedAssert, {
const availableAddresses = await web3Wrapper.getAvailableAddressesAsync();
this.assert(!_.isEmpty(availableAddresses), 'No addresses were available on the provided web3 provider');
},
-});
+};
diff --git a/packages/0x.js/src/utils/order_state_utils.ts b/packages/0x.js/src/utils/order_state_utils.ts
index a1ee7577d..123584f90 100644
--- a/packages/0x.js/src/utils/order_state_utils.ts
+++ b/packages/0x.js/src/utils/order_state_utils.ts
@@ -18,6 +18,8 @@ import {constants} from '../utils/constants';
import {OrderFilledCancelledLazyStore} from '../stores/order_filled_cancelled_lazy_store';
import {BalanceAndProxyAllowanceLazyStore} from '../stores/balance_proxy_allowance_lazy_store';
+const ACCEPTABLE_RELATIVE_ROUNDING_ERROR = 0.0001;
+
export class OrderStateUtils {
private balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore;
private orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore;
@@ -78,6 +80,9 @@ export class OrderStateUtils {
.dividedToIntegerBy(totalTakerTokenAmount);
const fillableMakerTokenAmount = BigNumber.min([makerProxyAllowance, makerBalance]);
const remainingFillableMakerTokenAmount = BigNumber.min(fillableMakerTokenAmount, remainingMakerTokenAmount);
+ const remainingFillableTakerTokenAmount = remainingFillableMakerTokenAmount
+ .times(totalTakerTokenAmount)
+ .dividedToIntegerBy(totalMakerTokenAmount);
// TODO: Handle edge case where maker token is ZRX with fee
const orderRelevantState = {
makerBalance,
@@ -87,6 +92,7 @@ export class OrderStateUtils {
filledTakerTokenAmount,
cancelledTakerTokenAmount,
remainingFillableMakerTokenAmount,
+ remainingFillableTakerTokenAmount,
};
return orderRelevantState;
}
@@ -113,6 +119,13 @@ export class OrderStateUtils {
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
// Return the max amount that's fillable
}
diff --git a/packages/0x.js/test/order_state_watcher_test.ts b/packages/0x.js/test/order_state_watcher_test.ts
index 32f493ee6..00b290252 100644
--- a/packages/0x.js/test/order_state_watcher_test.ts
+++ b/packages/0x.js/test/order_state_watcher_test.ts
@@ -47,7 +47,7 @@ describe('OrderStateWatcher', () => {
let taker: string;
let web3Wrapper: Web3Wrapper;
let signedOrder: SignedOrder;
- const fillableAmount = new BigNumber(5);
+ const fillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(5), 18);
before(async () => {
web3 = web3Factory.create();
zeroEx = new ZeroEx(web3.currentProvider);
@@ -61,19 +61,25 @@ describe('OrderStateWatcher', () => {
[makerToken, takerToken] = tokenUtils.getNonProtocolTokens();
web3Wrapper = (zeroEx as any)._web3Wrapper;
});
+ beforeEach(async () => {
+ await blockchainLifecycle.startAsync();
+ });
+ afterEach(async () => {
+ await blockchainLifecycle.revertAsync();
+ });
describe('#removeOrder', async () => {
it('should successfully remove existing order', async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
makerToken.address, takerToken.address, maker, taker, fillableAmount,
);
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- zeroEx.orderStateWatcher.addOrder(signedOrder);
+ await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
expect((zeroEx.orderStateWatcher as any)._orderByOrderHash).to.include({
[orderHash]: signedOrder,
});
let dependentOrderHashes = (zeroEx.orderStateWatcher as any)._dependentOrderHashes;
expect(dependentOrderHashes[signedOrder.maker][signedOrder.makerTokenAddress]).to.have.keys(orderHash);
- zeroEx.orderStateWatcher.removeOrder(orderHash);
+ await zeroEx.orderStateWatcher.removeOrderAsync(orderHash);
expect((zeroEx.orderStateWatcher as any)._orderByOrderHash).to.not.include({
[orderHash]: signedOrder,
});
@@ -86,7 +92,7 @@ describe('OrderStateWatcher', () => {
);
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
const nonExistentOrderHash = `0x${orderHash.substr(2).split('').reverse().join('')}`;
- zeroEx.orderStateWatcher.removeOrder(nonExistentOrderHash);
+ await zeroEx.orderStateWatcher.removeOrderAsync(nonExistentOrderHash);
});
});
describe('#subscribe', async () => {
@@ -103,7 +109,7 @@ describe('OrderStateWatcher', () => {
afterEach(async () => {
zeroEx.orderStateWatcher.unsubscribe();
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) => {
(async () => {
@@ -111,7 +117,7 @@ describe('OrderStateWatcher', () => {
makerToken.address, takerToken.address, maker, taker, fillableAmount,
);
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- zeroEx.orderStateWatcher.addOrder(signedOrder);
+ await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
expect(orderState.isValid).to.be.false();
const invalidOrderState = orderState as OrderStateInvalid;
@@ -129,7 +135,7 @@ describe('OrderStateWatcher', () => {
makerToken.address, takerToken.address, maker, taker, fillableAmount,
);
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- zeroEx.orderStateWatcher.addOrder(signedOrder);
+ await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
throw new Error('OrderState callback fired for irrelevant order');
});
@@ -150,7 +156,7 @@ describe('OrderStateWatcher', () => {
makerToken.address, takerToken.address, maker, taker, fillableAmount,
);
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- zeroEx.orderStateWatcher.addOrder(signedOrder);
+ await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
expect(orderState.isValid).to.be.false();
const invalidOrderState = orderState as OrderStateInvalid;
@@ -170,7 +176,7 @@ describe('OrderStateWatcher', () => {
makerToken.address, takerToken.address, maker, taker, fillableAmount,
);
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- zeroEx.orderStateWatcher.addOrder(signedOrder);
+ await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
let eventCount = 0;
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
@@ -202,7 +208,7 @@ describe('OrderStateWatcher', () => {
const fillAmountInBaseUnits = new BigNumber(2);
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- zeroEx.orderStateWatcher.addOrder(signedOrder);
+ await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
let eventCount = 0;
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
@@ -215,6 +221,8 @@ describe('OrderStateWatcher', () => {
const remainingFillable = fillableAmount.minus(fillAmountInBaseUnits);
expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
remainingFillable);
+ expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
+ remainingFillable);
expect(orderRelevantState.makerBalance).to.be.bignumber.equal(remainingMakerBalance);
if (eventCount === 2) {
done();
@@ -227,84 +235,108 @@ describe('OrderStateWatcher', () => {
);
})().catch(done);
});
- describe('remainingFillableMakerTokenAmount', () => {
- it('should calculate correct remaining fillable', (done: DoneCallback) => {
- (async () => {
- const takerFillableAmount = new BigNumber(10);
- const makerFillableAmount = new BigNumber(20);
- signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
- makerToken.address, takerToken.address, maker, taker, makerFillableAmount, takerFillableAmount);
- const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
- const takerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, taker);
- const fillAmountInBaseUnits = new BigNumber(2);
- const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- zeroEx.orderStateWatcher.addOrder(signedOrder);
- let eventCount = 0;
- const callback = reportCallbackErrors(done)((orderState: OrderState) => {
- eventCount++;
- expect(orderState.isValid).to.be.true();
- const validOrderState = orderState as OrderStateValid;
- expect(validOrderState.orderHash).to.be.equal(orderHash);
- const orderRelevantState = validOrderState.orderRelevantState;
- expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
- new BigNumber(16));
- if (eventCount === 2) {
- done();
- }
- });
- zeroEx.orderStateWatcher.subscribe(callback);
- const shouldThrowOnInsufficientBalanceOrAllowance = true;
- await zeroEx.exchange.fillOrderAsync(
- signedOrder, fillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance, taker,
- );
- })().catch(done);
- });
- it('should equal approved amount when approved amount is lowest', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerToken.address, takerToken.address, maker, taker, fillableAmount,
- );
+ it('should trigger the callback when orders backing ZRX allowance changes', (done: DoneCallback) => {
+ (async () => {
+ const makerFee = ZeroEx.toBaseUnitAmount(new BigNumber(2), 18);
+ const takerFee = ZeroEx.toBaseUnitAmount(new BigNumber(0), 18);
+ signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
+ makerToken.address, takerToken.address, makerFee, takerFee, maker, taker, fillableAmount,
+ taker);
+ const orderHash = ZeroEx.getOrderHashHex(signedOrder);
+ 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) => {
+ (async () => {
+ const takerFillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(10), 18);
+ const makerFillableAmount = ZeroEx.toBaseUnitAmount(new BigNumber(20), 18);
+ signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
+ makerToken.address, takerToken.address, maker, taker, makerFillableAmount,
+ takerFillableAmount,
+ );
+ const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
+ const takerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, taker);
+ const fillAmountInBaseUnits = ZeroEx.toBaseUnitAmount(new BigNumber(2), 18);
+ const orderHash = ZeroEx.getOrderHashHex(signedOrder);
+ await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
+ let eventCount = 0;
+ const callback = reportCallbackErrors(done)((orderState: OrderState) => {
+ eventCount++;
+ expect(orderState.isValid).to.be.true();
+ const validOrderState = orderState as OrderStateValid;
+ expect(validOrderState.orderHash).to.be.equal(orderHash);
+ const orderRelevantState = validOrderState.orderRelevantState;
+ expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
+ ZeroEx.toBaseUnitAmount(new BigNumber(16), 18));
+ expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
+ ZeroEx.toBaseUnitAmount(new BigNumber(8), 18));
+ if (eventCount === 2) {
+ done();
+ }
+ });
+ zeroEx.orderStateWatcher.subscribe(callback);
+ const shouldThrowOnInsufficientBalanceOrAllowance = true;
+ await zeroEx.exchange.fillOrderAsync(
+ signedOrder, fillAmountInBaseUnits, shouldThrowOnInsufficientBalanceOrAllowance, taker,
+ );
+ })().catch(done);
+ });
+ it('should equal approved amount when approved amount is lowest', (done: DoneCallback) => {
+ (async () => {
+ signedOrder = await fillScenarios.createFillableSignedOrderAsync(
+ makerToken.address, takerToken.address, maker, taker, fillableAmount,
+ );
- const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
+ const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
- const changedMakerApprovalAmount = new BigNumber(3);
- zeroEx.orderStateWatcher.addOrder(signedOrder);
+ const changedMakerApprovalAmount = ZeroEx.toBaseUnitAmount(new BigNumber(3), 18);
+ await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
- const callback = reportCallbackErrors(done)((orderState: OrderState) => {
- const validOrderState = orderState as OrderStateValid;
- const orderRelevantState = validOrderState.orderRelevantState;
- expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
- changedMakerApprovalAmount);
- done();
- });
- zeroEx.orderStateWatcher.subscribe(callback);
- await zeroEx.token.setProxyAllowanceAsync(makerToken.address, maker, changedMakerApprovalAmount);
- })().catch(done);
- });
- it('should equal balance amount when balance amount is lowest', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerToken.address, takerToken.address, maker, taker, fillableAmount,
- );
+ const callback = reportCallbackErrors(done)((orderState: OrderState) => {
+ const validOrderState = orderState as OrderStateValid;
+ const orderRelevantState = validOrderState.orderRelevantState;
+ expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
+ changedMakerApprovalAmount);
+ expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
+ changedMakerApprovalAmount);
+ done();
+ });
+ zeroEx.orderStateWatcher.subscribe(callback);
+ await zeroEx.token.setProxyAllowanceAsync(makerToken.address, maker, changedMakerApprovalAmount);
+ })().catch(done);
+ });
+ it('should equal balance amount when balance amount is lowest', (done: DoneCallback) => {
+ (async () => {
+ signedOrder = await fillScenarios.createFillableSignedOrderAsync(
+ makerToken.address, takerToken.address, maker, taker, fillableAmount,
+ );
- const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
+ const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
- const remainingAmount = new BigNumber(1);
- const transferAmount = makerBalance.sub(remainingAmount);
- zeroEx.orderStateWatcher.addOrder(signedOrder);
+ const remainingAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), 18);
+ const transferAmount = makerBalance.sub(remainingAmount);
+ await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
- const callback = reportCallbackErrors(done)((orderState: OrderState) => {
- const validOrderState = orderState as OrderStateValid;
- const orderRelevantState = validOrderState.orderRelevantState;
- expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
- remainingAmount);
- done();
- });
- zeroEx.orderStateWatcher.subscribe(callback);
- await zeroEx.token.transferAsync(
- makerToken.address, maker, ZeroEx.NULL_ADDRESS, transferAmount);
- })().catch(done);
- });
+ const callback = reportCallbackErrors(done)((orderState: OrderState) => {
+ const validOrderState = orderState as OrderStateValid;
+ const orderRelevantState = validOrderState.orderRelevantState;
+ expect(orderRelevantState.remainingFillableMakerTokenAmount).to.be.bignumber.equal(
+ remainingAmount);
+ expect(orderRelevantState.remainingFillableTakerTokenAmount).to.be.bignumber.equal(
+ remainingAmount);
+ done();
+ });
+ zeroEx.orderStateWatcher.subscribe(callback);
+ await zeroEx.token.transferAsync(
+ makerToken.address, maker, ZeroEx.NULL_ADDRESS, transferAmount);
+ })().catch(done);
+ });
});
it('should emit orderStateInvalid when watched order cancelled', (done: DoneCallback) => {
(async () => {
@@ -312,7 +344,7 @@ describe('OrderStateWatcher', () => {
makerToken.address, takerToken.address, maker, taker, fillableAmount,
);
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- zeroEx.orderStateWatcher.addOrder(signedOrder);
+ await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
expect(orderState.isValid).to.be.false();
@@ -327,6 +359,28 @@ describe('OrderStateWatcher', () => {
await zeroEx.exchange.cancelOrderAsync(signedOrder, fillableAmount);
})().catch(done);
});
+ it('should emit orderStateInvalid when within rounding error range', (done: DoneCallback) => {
+ (async () => {
+ const remainingFillableAmountInBaseUnits = new BigNumber(100);
+ signedOrder = await fillScenarios.createFillableSignedOrderAsync(
+ makerToken.address, takerToken.address, maker, taker, fillableAmount,
+ );
+ const orderHash = ZeroEx.getOrderHashHex(signedOrder);
+ 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) => {
(async () => {
signedOrder = await fillScenarios.createFillableSignedOrderAsync(
@@ -338,7 +392,7 @@ describe('OrderStateWatcher', () => {
const cancelAmountInBaseUnits = new BigNumber(2);
const orderHash = ZeroEx.getOrderHashHex(signedOrder);
- zeroEx.orderStateWatcher.addOrder(signedOrder);
+ await zeroEx.orderStateWatcher.addOrderAsync(signedOrder);
const callback = reportCallbackErrors(done)((orderState: OrderState) => {
expect(orderState.isValid).to.be.true();
diff --git a/packages/0x.js/test/token_registry_wrapper_test.ts b/packages/0x.js/test/token_registry_wrapper_test.ts
index 6b5dd517e..d3497451b 100644
--- a/packages/0x.js/test/token_registry_wrapper_test.ts
+++ b/packages/0x.js/test/token_registry_wrapper_test.ts
@@ -1,7 +1,7 @@
import * as _ from 'lodash';
import 'mocha';
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 {web3Factory} from './utils/web3_factory';
import {ZeroEx, Token} from '../src';
diff --git a/packages/0x.js/tslint.json b/packages/0x.js/tslint.json
index 5842a872a..a07795151 100644
--- a/packages/0x.js/tslint.json
+++ b/packages/0x.js/tslint.json
@@ -1,5 +1,5 @@
{
"extends": [
- "tslint-config-0xproject"
+ "@0xproject/tslint-config"
]
}