Merge branch 'development' into feature/orderExpired
This commit is contained in:
@@ -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_
|
||||
------------------------
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
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
|
||||
run-s substitute_umd_bundle run_mocha
|
||||
return_code=$?
|
||||
npm run clean
|
||||
exit $return_code
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -6,8 +6,6 @@ export {
|
||||
ECSignature,
|
||||
ZeroExError,
|
||||
EventCallback,
|
||||
EventCallbackAsync,
|
||||
EventCallbackSync,
|
||||
ExchangeContractErrs,
|
||||
ContractEvent,
|
||||
Token,
|
||||
|
||||
@@ -81,7 +81,7 @@ export class EventWatcher {
|
||||
...log,
|
||||
};
|
||||
if (!_.isUndefined(this._intervalIdIfExists)) {
|
||||
await callback(logEvent);
|
||||
callback(logEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": [
|
||||
"tslint-config-0xproject"
|
||||
"@0xproject/tslint-config"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user