Look for relevant events in the decodedLogs and emit orderState events for orders impacted by the blockchain state changes
This commit is contained in:
		
				
					committed by
					
						
						Leonid Logvinov
					
				
			
			
				
	
			
			
			
						parent
						
							6f00c422c7
						
					
				
				
					commit
					e952c98ca8
				
			@@ -3,6 +3,7 @@ import {schemas} from '0x-json-schemas';
 | 
				
			|||||||
import {ZeroEx} from '../';
 | 
					import {ZeroEx} from '../';
 | 
				
			||||||
import {EventWatcher} from './event_watcher';
 | 
					import {EventWatcher} from './event_watcher';
 | 
				
			||||||
import {assert} from '../utils/assert';
 | 
					import {assert} from '../utils/assert';
 | 
				
			||||||
 | 
					import {utils} from '../utils/utils';
 | 
				
			||||||
import {artifacts} from '../artifacts';
 | 
					import {artifacts} from '../artifacts';
 | 
				
			||||||
import {AbiDecoder} from '../utils/abi_decoder';
 | 
					import {AbiDecoder} from '../utils/abi_decoder';
 | 
				
			||||||
import {OrderStateUtils} from '../utils/order_state_utils';
 | 
					import {OrderStateUtils} from '../utils/order_state_utils';
 | 
				
			||||||
@@ -14,11 +15,24 @@ import {
 | 
				
			|||||||
    BlockParamLiteral,
 | 
					    BlockParamLiteral,
 | 
				
			||||||
    LogWithDecodedArgs,
 | 
					    LogWithDecodedArgs,
 | 
				
			||||||
    OnOrderStateChangeCallback,
 | 
					    OnOrderStateChangeCallback,
 | 
				
			||||||
 | 
					    ExchangeEvents,
 | 
				
			||||||
 | 
					    TokenEvents,
 | 
				
			||||||
} from '../types';
 | 
					} from '../types';
 | 
				
			||||||
import {Web3Wrapper} from '../web3_wrapper';
 | 
					import {Web3Wrapper} from '../web3_wrapper';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface DependentOrderHashes {
 | 
				
			||||||
 | 
					    [makerAddress: string]: {
 | 
				
			||||||
 | 
					        [makerToken: string]: Set<string>,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface OrderByOrderHash {
 | 
				
			||||||
 | 
					    [orderHash: string]: SignedOrder;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class OrderStateWatcher {
 | 
					export class OrderStateWatcher {
 | 
				
			||||||
    private _orders = new Map<string, SignedOrder>();
 | 
					    private _orders: OrderByOrderHash;
 | 
				
			||||||
 | 
					    private _dependentOrderHashes: DependentOrderHashes;
 | 
				
			||||||
    private _web3Wrapper: Web3Wrapper;
 | 
					    private _web3Wrapper: Web3Wrapper;
 | 
				
			||||||
    private _callbackAsync?: OnOrderStateChangeCallback;
 | 
					    private _callbackAsync?: OnOrderStateChangeCallback;
 | 
				
			||||||
    private _eventWatcher: EventWatcher;
 | 
					    private _eventWatcher: EventWatcher;
 | 
				
			||||||
@@ -28,6 +42,8 @@ export class OrderStateWatcher {
 | 
				
			|||||||
        web3Wrapper: Web3Wrapper, abiDecoder: AbiDecoder, orderStateUtils: OrderStateUtils,
 | 
					        web3Wrapper: Web3Wrapper, abiDecoder: AbiDecoder, orderStateUtils: OrderStateUtils,
 | 
				
			||||||
        mempoolPollingIntervalMs?: number) {
 | 
					        mempoolPollingIntervalMs?: number) {
 | 
				
			||||||
        this._web3Wrapper = web3Wrapper;
 | 
					        this._web3Wrapper = web3Wrapper;
 | 
				
			||||||
 | 
					        this._orders = {};
 | 
				
			||||||
 | 
					        this._dependentOrderHashes = {};
 | 
				
			||||||
        this._eventWatcher = new EventWatcher(
 | 
					        this._eventWatcher = new EventWatcher(
 | 
				
			||||||
            this._web3Wrapper, mempoolPollingIntervalMs,
 | 
					            this._web3Wrapper, mempoolPollingIntervalMs,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
@@ -37,12 +53,18 @@ export class OrderStateWatcher {
 | 
				
			|||||||
    public addOrder(signedOrder: SignedOrder): void {
 | 
					    public addOrder(signedOrder: SignedOrder): void {
 | 
				
			||||||
        assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
 | 
					        assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
 | 
				
			||||||
        const orderHash = ZeroEx.getOrderHashHex(signedOrder);
 | 
					        const orderHash = ZeroEx.getOrderHashHex(signedOrder);
 | 
				
			||||||
        this._orders.set(orderHash, signedOrder);
 | 
					        this._orders[orderHash] = signedOrder;
 | 
				
			||||||
 | 
					        this.addToDependentOrderHashes(signedOrder, orderHash);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    public removeOrder(signedOrder: SignedOrder): void {
 | 
					    public removeOrder(signedOrder: SignedOrder): void {
 | 
				
			||||||
        assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
 | 
					        assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
 | 
				
			||||||
 | 
					        if (_.isUndefined(this._dependentOrderHashes[signedOrder.maker][signedOrder.makerTokenAddress])) {
 | 
				
			||||||
 | 
					            return; // noop if user tries to remove order that wasn't added
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        const orderHash = ZeroEx.getOrderHashHex(signedOrder);
 | 
					        const orderHash = ZeroEx.getOrderHashHex(signedOrder);
 | 
				
			||||||
        this._orders.delete(orderHash);
 | 
					        delete this._orders[orderHash];
 | 
				
			||||||
 | 
					        this._dependentOrderHashes[signedOrder.maker][signedOrder.makerTokenAddress].delete(orderHash);
 | 
				
			||||||
 | 
					        // We currently do not remove the maker/makerToken keys from the mapping when all orderHashes removed
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    public subscribe(callback: OnOrderStateChangeCallback): void {
 | 
					    public subscribe(callback: OnOrderStateChangeCallback): void {
 | 
				
			||||||
        assert.isFunction('callback', callback);
 | 
					        assert.isFunction('callback', callback);
 | 
				
			||||||
@@ -55,17 +77,59 @@ export class OrderStateWatcher {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    private async _onMempoolEventCallbackAsync(log: LogEvent): Promise<void> {
 | 
					    private async _onMempoolEventCallbackAsync(log: LogEvent): Promise<void> {
 | 
				
			||||||
        const maybeDecodedLog = this._abiDecoder.tryToDecodeLogOrNoop(log);
 | 
					        const maybeDecodedLog = this._abiDecoder.tryToDecodeLogOrNoop(log);
 | 
				
			||||||
        if (!_.isUndefined((maybeDecodedLog as LogWithDecodedArgs<any>).event)) {
 | 
					        const isDecodedLog = !_.isUndefined((maybeDecodedLog as LogWithDecodedArgs<any>).event);
 | 
				
			||||||
            await this._revalidateOrdersAsync();
 | 
					        if (!isDecodedLog) {
 | 
				
			||||||
 | 
					            return; // noop
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const decodedLog = maybeDecodedLog as LogWithDecodedArgs<any>;
 | 
				
			||||||
 | 
					        let makerToken: string;
 | 
				
			||||||
 | 
					        let makerAddress: string;
 | 
				
			||||||
 | 
					        let orderHashesSet: Set<string>;
 | 
				
			||||||
 | 
					        switch (decodedLog.event) {
 | 
				
			||||||
 | 
					            case TokenEvents.Approval:
 | 
				
			||||||
 | 
					                makerToken = decodedLog.address;
 | 
				
			||||||
 | 
					                makerAddress = decodedLog.args._owner;
 | 
				
			||||||
 | 
					                orderHashesSet = _.get(this._dependentOrderHashes, [makerAddress, makerToken]);
 | 
				
			||||||
 | 
					                if (!_.isUndefined(orderHashesSet)) {
 | 
				
			||||||
 | 
					                    const orderHashes = Array.from(orderHashesSet);
 | 
				
			||||||
 | 
					                    await this._emitRevalidateOrdersAsync(orderHashes);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case TokenEvents.Transfer:
 | 
				
			||||||
 | 
					                makerToken = decodedLog.address;
 | 
				
			||||||
 | 
					                makerAddress = decodedLog.args._from;
 | 
				
			||||||
 | 
					                orderHashesSet = _.get(this._dependentOrderHashes, [makerAddress, makerToken]);
 | 
				
			||||||
 | 
					                if (!_.isUndefined(orderHashesSet)) {
 | 
				
			||||||
 | 
					                    const orderHashes = Array.from(orderHashesSet);
 | 
				
			||||||
 | 
					                    await this._emitRevalidateOrdersAsync(orderHashes);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case ExchangeEvents.LogFill:
 | 
				
			||||||
 | 
					            case ExchangeEvents.LogCancel:
 | 
				
			||||||
 | 
					                const orderHash = decodedLog.args.orderHash;
 | 
				
			||||||
 | 
					                const isOrderWatched = !_.isUndefined(this._orders[orderHash]);
 | 
				
			||||||
 | 
					                if (isOrderWatched) {
 | 
				
			||||||
 | 
					                    await this._emitRevalidateOrdersAsync([orderHash]);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case ExchangeEvents.LogError:
 | 
				
			||||||
 | 
					                return; // noop
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                throw utils.spawnSwitchErr('decodedLog.event', decodedLog.event);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    private async _revalidateOrdersAsync(): Promise<void> {
 | 
					    private async _emitRevalidateOrdersAsync(orderHashes: string[]): Promise<void> {
 | 
				
			||||||
 | 
					        // TODO: Make defaultBlock a passed in option
 | 
				
			||||||
        const methodOpts = {
 | 
					        const methodOpts = {
 | 
				
			||||||
            defaultBlock: BlockParamLiteral.Pending,
 | 
					            defaultBlock: BlockParamLiteral.Pending,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        const orderHashes = Array.from(this._orders.keys());
 | 
					
 | 
				
			||||||
        for (const orderHash of orderHashes) {
 | 
					        for (const orderHash of orderHashes) {
 | 
				
			||||||
            const signedOrder = this._orders.get(orderHash) as SignedOrder;
 | 
					            const signedOrder = this._orders[orderHash] as SignedOrder;
 | 
				
			||||||
            const orderState = await this._orderStateUtils.getOrderStateAsync(signedOrder, methodOpts);
 | 
					            const orderState = await this._orderStateUtils.getOrderStateAsync(signedOrder, methodOpts);
 | 
				
			||||||
            if (!_.isUndefined(this._callbackAsync)) {
 | 
					            if (!_.isUndefined(this._callbackAsync)) {
 | 
				
			||||||
                await this._callbackAsync(orderState);
 | 
					                await this._callbackAsync(orderState);
 | 
				
			||||||
@@ -74,4 +138,13 @@ export class OrderStateWatcher {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    private addToDependentOrderHashes(signedOrder: SignedOrder, orderHash: string) {
 | 
				
			||||||
 | 
					        if (_.isUndefined(this._dependentOrderHashes[signedOrder.maker])) {
 | 
				
			||||||
 | 
					            this._dependentOrderHashes[signedOrder.maker] = {};
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (_.isUndefined(this._dependentOrderHashes[signedOrder.maker][signedOrder.makerTokenAddress])) {
 | 
				
			||||||
 | 
					            this._dependentOrderHashes[signedOrder.maker][signedOrder.makerTokenAddress] = new Set();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this._dependentOrderHashes[signedOrder.maker][signedOrder.makerTokenAddress].add(orderHash);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,6 @@
 | 
				
			|||||||
import 'mocha';
 | 
					import 'mocha';
 | 
				
			||||||
import * as chai from 'chai';
 | 
					import * as chai from 'chai';
 | 
				
			||||||
import * as _ from 'lodash';
 | 
					import * as _ from 'lodash';
 | 
				
			||||||
import * as Sinon from 'sinon';
 | 
					 | 
				
			||||||
import * as Web3 from 'web3';
 | 
					import * as Web3 from 'web3';
 | 
				
			||||||
import BigNumber from 'bignumber.js';
 | 
					import BigNumber from 'bignumber.js';
 | 
				
			||||||
import { chaiSetup } from './utils/chai_setup';
 | 
					import { chaiSetup } from './utils/chai_setup';
 | 
				
			||||||
@@ -14,7 +13,10 @@ import {
 | 
				
			|||||||
    LogEvent,
 | 
					    LogEvent,
 | 
				
			||||||
    DecodedLogEvent,
 | 
					    DecodedLogEvent,
 | 
				
			||||||
    OrderState,
 | 
					    OrderState,
 | 
				
			||||||
 | 
					    SignedOrder,
 | 
				
			||||||
    OrderStateValid,
 | 
					    OrderStateValid,
 | 
				
			||||||
 | 
					    OrderStateInvalid,
 | 
				
			||||||
 | 
					    ExchangeContractErrs,
 | 
				
			||||||
} from '../src';
 | 
					} from '../src';
 | 
				
			||||||
import { TokenUtils } from './utils/token_utils';
 | 
					import { TokenUtils } from './utils/token_utils';
 | 
				
			||||||
import { FillScenarios } from './utils/fill_scenarios';
 | 
					import { FillScenarios } from './utils/fill_scenarios';
 | 
				
			||||||
@@ -23,9 +25,8 @@ import {DoneCallback} from '../src/types';
 | 
				
			|||||||
chaiSetup.configure();
 | 
					chaiSetup.configure();
 | 
				
			||||||
const expect = chai.expect;
 | 
					const expect = chai.expect;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('EventWatcher', () => {
 | 
					describe.only('EventWatcher', () => {
 | 
				
			||||||
    let web3: Web3;
 | 
					    let web3: Web3;
 | 
				
			||||||
    let stubs: Sinon.SinonStub[] = [];
 | 
					 | 
				
			||||||
    let zeroEx: ZeroEx;
 | 
					    let zeroEx: ZeroEx;
 | 
				
			||||||
    let tokens: Token[];
 | 
					    let tokens: Token[];
 | 
				
			||||||
    let tokenUtils: TokenUtils;
 | 
					    let tokenUtils: TokenUtils;
 | 
				
			||||||
@@ -38,22 +39,8 @@ describe('EventWatcher', () => {
 | 
				
			|||||||
    let maker: string;
 | 
					    let maker: string;
 | 
				
			||||||
    let taker: string;
 | 
					    let taker: string;
 | 
				
			||||||
    let web3Wrapper: Web3Wrapper;
 | 
					    let web3Wrapper: Web3Wrapper;
 | 
				
			||||||
 | 
					    let signedOrder: SignedOrder;
 | 
				
			||||||
    const fillableAmount = new BigNumber(5);
 | 
					    const fillableAmount = new BigNumber(5);
 | 
				
			||||||
    const fakeLog = {
 | 
					 | 
				
			||||||
        address: '0xcdb594a32b1cc3479d8746279712c39d18a07fc0',
 | 
					 | 
				
			||||||
        blockHash: '0x2d5cec6e3239d40993b74008f684af82b69f238697832e4c4d58e0ba5a2fa99e',
 | 
					 | 
				
			||||||
        blockNumber: '0x34',
 | 
					 | 
				
			||||||
        data: '0x0000000000000000000000000000000000000000000000000000000000000028',
 | 
					 | 
				
			||||||
        logIndex: '0x00',
 | 
					 | 
				
			||||||
        topics: [
 | 
					 | 
				
			||||||
            '0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925',
 | 
					 | 
				
			||||||
            '0x0000000000000000000000006ecbe1db9ef729cbe972c83fb886247691fb6beb',
 | 
					 | 
				
			||||||
            '0x000000000000000000000000871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c',
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
        transactionHash: '0xa550fbe937985c383ed7ed077cf6011960a3c2d38ea39dea209426546f0e95cb',
 | 
					 | 
				
			||||||
        transactionIndex: '0x00',
 | 
					 | 
				
			||||||
        type: 'mined',
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    before(async () => {
 | 
					    before(async () => {
 | 
				
			||||||
        web3 = web3Factory.create();
 | 
					        web3 = web3Factory.create();
 | 
				
			||||||
        zeroEx = new ZeroEx(web3.currentProvider);
 | 
					        zeroEx = new ZeroEx(web3.currentProvider);
 | 
				
			||||||
@@ -67,36 +54,68 @@ describe('EventWatcher', () => {
 | 
				
			|||||||
        [makerToken, takerToken] = tokenUtils.getNonProtocolTokens();
 | 
					        [makerToken, takerToken] = tokenUtils.getNonProtocolTokens();
 | 
				
			||||||
        web3Wrapper = (zeroEx as any)._web3Wrapper;
 | 
					        web3Wrapper = (zeroEx as any)._web3Wrapper;
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    beforeEach(() => {
 | 
					    afterEach(async () => {
 | 
				
			||||||
        const getLogsStub = Sinon.stub(web3Wrapper, 'getLogsAsync');
 | 
					 | 
				
			||||||
        getLogsStub.onCall(0).returns([fakeLog]);
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    afterEach(() => {
 | 
					 | 
				
			||||||
        // clean up any stubs after the test has completed
 | 
					 | 
				
			||||||
        _.each(stubs, s => s.restore());
 | 
					 | 
				
			||||||
        stubs = [];
 | 
					 | 
				
			||||||
        zeroEx.orderStateWatcher.unsubscribe();
 | 
					        zeroEx.orderStateWatcher.unsubscribe();
 | 
				
			||||||
 | 
					        zeroEx.orderStateWatcher.removeOrder(signedOrder);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    it('should receive OrderState when order state is changed', (done: DoneCallback) => {
 | 
					    it('should emit orderStateInvalid when maker allowance set to 0 for watched order', (done: DoneCallback) => {
 | 
				
			||||||
        (async () => {
 | 
					        (async () => {
 | 
				
			||||||
            const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
 | 
					            signedOrder = await fillScenarios.createFillableSignedOrderAsync(
 | 
				
			||||||
                makerToken.address, takerToken.address, maker, taker, fillableAmount,
 | 
					                makerToken.address, takerToken.address, maker, taker, fillableAmount,
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            const orderHash = ZeroEx.getOrderHashHex(signedOrder);
 | 
					            const orderHash = ZeroEx.getOrderHashHex(signedOrder);
 | 
				
			||||||
            zeroEx.orderStateWatcher.addOrder(signedOrder);
 | 
					            zeroEx.orderStateWatcher.addOrder(signedOrder);
 | 
				
			||||||
            const callback = (orderState: OrderState) => {
 | 
					            const callback = (orderState: OrderState) => {
 | 
				
			||||||
                expect(orderState.isValid).to.be.true();
 | 
					                expect(orderState.isValid).to.be.false();
 | 
				
			||||||
                expect(orderState.orderHash).to.be.equal(orderHash);
 | 
					                const invalidOrderState = orderState as OrderStateInvalid;
 | 
				
			||||||
                const orderRelevantState = (orderState as OrderStateValid).orderRelevantState;
 | 
					                expect(invalidOrderState.orderHash).to.be.equal(orderHash);
 | 
				
			||||||
                expect(orderRelevantState.makerBalance).to.be.bignumber.equal(fillableAmount);
 | 
					                expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance);
 | 
				
			||||||
                expect(orderRelevantState.makerProxyAllowance).to.be.bignumber.equal(fillableAmount);
 | 
					 | 
				
			||||||
                expect(orderRelevantState.makerFeeBalance).to.be.bignumber.equal(0);
 | 
					 | 
				
			||||||
                expect(orderRelevantState.makerFeeProxyAllowance).to.be.bignumber.equal(0);
 | 
					 | 
				
			||||||
                expect(orderRelevantState.filledTakerTokenAmount).to.be.bignumber.equal(0);
 | 
					 | 
				
			||||||
                expect(orderRelevantState.canceledTakerTokenAmount).to.be.bignumber.equal(0);
 | 
					 | 
				
			||||||
                done();
 | 
					                done();
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            zeroEx.orderStateWatcher.subscribe(callback);
 | 
					            zeroEx.orderStateWatcher.subscribe(callback);
 | 
				
			||||||
 | 
					            await zeroEx.token.setProxyAllowanceAsync(makerToken.address, maker, new BigNumber(0));
 | 
				
			||||||
 | 
					        })().catch(done);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('should emit orderStateInvalid when maker moves balance backing watched order', (done: DoneCallback) => {
 | 
				
			||||||
 | 
					        (async () => {
 | 
				
			||||||
 | 
					            signedOrder = await fillScenarios.createFillableSignedOrderAsync(
 | 
				
			||||||
 | 
					                makerToken.address, takerToken.address, maker, taker, fillableAmount,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            const orderHash = ZeroEx.getOrderHashHex(signedOrder);
 | 
				
			||||||
 | 
					            zeroEx.orderStateWatcher.addOrder(signedOrder);
 | 
				
			||||||
 | 
					            const callback = (orderState: OrderState) => {
 | 
				
			||||||
 | 
					                expect(orderState.isValid).to.be.false();
 | 
				
			||||||
 | 
					                const invalidOrderState = orderState as OrderStateInvalid;
 | 
				
			||||||
 | 
					                expect(invalidOrderState.orderHash).to.be.equal(orderHash);
 | 
				
			||||||
 | 
					                expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerBalance);
 | 
				
			||||||
 | 
					                done();
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            zeroEx.orderStateWatcher.subscribe(callback);
 | 
				
			||||||
 | 
					            const anyRecipient = taker;
 | 
				
			||||||
 | 
					            const makerBalance = await zeroEx.token.getBalanceAsync(makerToken.address, maker);
 | 
				
			||||||
 | 
					            await zeroEx.token.transferAsync(makerToken.address, maker, anyRecipient, makerBalance);
 | 
				
			||||||
 | 
					        })().catch(done);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    it('should emit orderStateInvalid when watched order fully filled', (done: DoneCallback) => {
 | 
				
			||||||
 | 
					        (async () => {
 | 
				
			||||||
 | 
					            signedOrder = await fillScenarios.createFillableSignedOrderAsync(
 | 
				
			||||||
 | 
					                makerToken.address, takerToken.address, maker, taker, fillableAmount,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            const orderHash = ZeroEx.getOrderHashHex(signedOrder);
 | 
				
			||||||
 | 
					            zeroEx.orderStateWatcher.addOrder(signedOrder);
 | 
				
			||||||
 | 
					            const callback = (orderState: OrderState) => {
 | 
				
			||||||
 | 
					                expect(orderState.isValid).to.be.false();
 | 
				
			||||||
 | 
					                const invalidOrderState = orderState as OrderStateInvalid;
 | 
				
			||||||
 | 
					                expect(invalidOrderState.orderHash).to.be.equal(orderHash);
 | 
				
			||||||
 | 
					                expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderRemainingFillAmountZero);
 | 
				
			||||||
 | 
					                done();
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            zeroEx.orderStateWatcher.subscribe(callback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const shouldThrowOnInsufficientBalanceOrAllowance = true;
 | 
				
			||||||
 | 
					            await zeroEx.exchange.fillOrderAsync(
 | 
				
			||||||
 | 
					                signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, taker,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
        })().catch(done);
 | 
					        })().catch(done);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user