From 7dd63523939822203d938511472c84b8ff418aaf Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Thu, 5 Oct 2017 14:34:30 +0300 Subject: Implement subscriptions based on ethereumjs-blockstream --- src/contract_wrappers/exchange_wrapper.ts | 82 +++++++++++++------------------ 1 file changed, 34 insertions(+), 48 deletions(-) (limited to 'src/contract_wrappers/exchange_wrapper.ts') diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index 32eaa590c..e5f190864 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -16,11 +16,8 @@ import { SignedOrder, ContractEvent, ExchangeEvents, - ContractEventEmitter, SubscriptionOpts, IndexedFilterValues, - CreateContractEvent, - ContractEventObj, OrderCancellationRequest, OrderFillRequest, LogErrorContractEventArgs, @@ -31,10 +28,10 @@ import { ValidateOrderFillableOpts, OrderTransactionOpts, RawLog, + EventCallback, } from '../types'; import {assert} from '../utils/assert'; import {utils} from '../utils/utils'; -import {eventUtils} from '../utils/event_utils'; import {OrderValidationUtils} from '../utils/order_validation_utils'; import {ContractWrapper} from './contract_wrapper'; import {constants} from '../utils/constants'; @@ -51,7 +48,7 @@ const SHOULD_VALIDATE_BY_DEFAULT = true; */ export class ExchangeWrapper extends ContractWrapper { private _exchangeContractIfExists?: ExchangeContract; - private _exchangeLogEventEmitters: ContractEventEmitter[]; + private _activeSubscriptions: string[]; private _orderValidationUtils: OrderValidationUtils; private _tokenWrapper: TokenWrapper; private _exchangeContractErrCodesToMsg = { @@ -86,7 +83,7 @@ export class ExchangeWrapper extends ContractWrapper { super(web3Wrapper, abiDecoder); this._tokenWrapper = tokenWrapper; this._orderValidationUtils = new OrderValidationUtils(tokenWrapper, this); - this._exchangeLogEventEmitters = []; + this._activeSubscriptions = []; this._contractAddressIfExists = contractAddressIfExists; } /** @@ -622,41 +619,32 @@ export class ExchangeWrapper extends ContractWrapper { return txHash; } /** - * Subscribe to an event type emitted by the Exchange smart contract - * @param eventName The exchange contract event you would like to subscribe to. - * @param subscriptionOpts Subscriptions options that let you configure the subscription. - * @param indexFilterValues An object where the keys are indexed args returned by the event and - * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` - * @param exchangeContractAddress The hex encoded address of the Exchange contract to call. - * @return ContractEventEmitter object + * Subscribe to an event type emitted by the Exchange contract. + * @param tokenAddress The hex encoded address where the ERC20 token is deployed. + * @param eventName The exchange contract event you would like to subscribe to. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` + * @param callback Callback that gets called when a log is added/removed + * @return ContractEventEmitter object */ - public async subscribeAsync(eventName: ExchangeEvents, subscriptionOpts: SubscriptionOpts, - indexFilterValues: IndexedFilterValues, exchangeContractAddress: string): - Promise { - assert.isETHAddressHex('exchangeContractAddress', exchangeContractAddress); + public async subscribeAsync(eventName: ExchangeEvents, indexFilterValues: IndexedFilterValues, + callback: EventCallback): Promise { assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents); - assert.doesConformToSchema('subscriptionOpts', subscriptionOpts, schemas.subscriptionOptsSchema); assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); - const exchangeContract = await this._getExchangeContractAsync(); - let createLogEvent: CreateContractEvent; - switch (eventName) { - case ExchangeEvents.LogFill: - createLogEvent = exchangeContract.LogFill; - break; - case ExchangeEvents.LogError: - createLogEvent = exchangeContract.LogError; - break; - case ExchangeEvents.LogCancel: - createLogEvent = exchangeContract.LogCancel; - break; - default: - throw utils.spawnSwitchErr('ExchangeEvents', eventName); - } - - const logEventObj: ContractEventObj = createLogEvent(indexFilterValues, subscriptionOpts); - const eventEmitter = eventUtils.wrapEventEmitter(logEventObj); - this._exchangeLogEventEmitters.push(eventEmitter); - return eventEmitter; + const exchangeContractAddress = await this.getContractAddressAsync(); + const subscriptionToken = this._subscribe( + exchangeContractAddress, eventName, indexFilterValues, artifacts.ExchangeArtifact.abi, callback, + ); + this._activeSubscriptions.push(subscriptionToken); + return subscriptionToken; + } + /** + * Cancel a subscription + * @param subscriptionToken Subscription token returned by `subscribe()` + */ + public unsubscribe(subscriptionToken: string): void { + _.pull(this._activeSubscriptions, subscriptionToken); + this._unsubscribe(subscriptionToken); } /** * Gets historical logs without creating a subscription @@ -677,15 +665,6 @@ export class ExchangeWrapper extends ContractWrapper { ); return logs; } - /** - * Stops watching for all exchange events - */ - public async stopWatchingAllEventsAsync(): Promise { - const stopWatchingPromises = _.map(this._exchangeLogEventEmitters, - logEventObj => logEventObj.stopWatchingAsync()); - await Promise.all(stopWatchingPromises); - this._exchangeLogEventEmitters = []; - } /** * Retrieves the Ethereum address of the Exchange contract deployed on the network * that the user-passed web3 provider is connected to. @@ -809,8 +788,15 @@ export class ExchangeWrapper extends ContractWrapper { const ZRXtokenAddress = await exchangeInstance.ZRX_TOKEN_CONTRACT.callAsync(); return ZRXtokenAddress; } + /** + * Cancels all existing subscriptions + */ + public unsubscribeAll(): void { + _.forEach(this._activeSubscriptions, this._unsubscribe.bind(this)); + this._activeSubscriptions = []; + } private async _invalidateContractInstancesAsync(): Promise { - await this.stopWatchingAllEventsAsync(); + this.unsubscribeAll(); delete this._exchangeContractIfExists; } private async _isValidSignatureUsingContractCallAsync(dataHex: string, ecSignature: ECSignature, -- cgit From f2100fa36dae740735f9a2e2811cc7977f4c286c Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Thu, 5 Oct 2017 14:48:45 +0300 Subject: Remove missing comment --- src/contract_wrappers/exchange_wrapper.ts | 1 - 1 file changed, 1 deletion(-) (limited to 'src/contract_wrappers/exchange_wrapper.ts') diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index e5f190864..ab5bc15ee 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -620,7 +620,6 @@ export class ExchangeWrapper extends ContractWrapper { } /** * Subscribe to an event type emitted by the Exchange contract. - * @param tokenAddress The hex encoded address where the ERC20 token is deployed. * @param eventName The exchange contract event you would like to subscribe to. * @param indexFilterValues An object where the keys are indexed args returned by the event and * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` -- cgit From 553cbb25f4d8b8ae43156eb21d3358d5b1350c68 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Thu, 5 Oct 2017 15:26:38 +0300 Subject: Fix comments --- src/contract_wrappers/exchange_wrapper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/contract_wrappers/exchange_wrapper.ts') diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index ab5bc15ee..0eb600ff6 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -624,7 +624,7 @@ export class ExchangeWrapper extends ContractWrapper { * @param indexFilterValues An object where the keys are indexed args returned by the event and * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` * @param callback Callback that gets called when a log is added/removed - * @return ContractEventEmitter object + * @return Subscription token used later to unsubscribe */ public async subscribeAsync(eventName: ExchangeEvents, indexFilterValues: IndexedFilterValues, callback: EventCallback): Promise { -- cgit From 1414b8ee8bdb1be901371c4cf7b8a5150d8fb771 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Thu, 5 Oct 2017 16:32:01 +0300 Subject: Add type assertions for callback parameters --- src/contract_wrappers/exchange_wrapper.ts | 1 + 1 file changed, 1 insertion(+) (limited to 'src/contract_wrappers/exchange_wrapper.ts') diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index 0eb600ff6..b2e48b36e 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -630,6 +630,7 @@ export class ExchangeWrapper extends ContractWrapper { callback: EventCallback): Promise { assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents); assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + assert.isFunction('callback', callback); const exchangeContractAddress = await this.getContractAddressAsync(); const subscriptionToken = this._subscribe( exchangeContractAddress, eventName, indexFilterValues, artifacts.ExchangeArtifact.abi, callback, -- cgit From a406b4d134e729bceba81a98f5756a8759f18655 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Thu, 5 Oct 2017 17:34:30 +0300 Subject: Remove unused imports --- src/contract_wrappers/exchange_wrapper.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/contract_wrappers/exchange_wrapper.ts') diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index b2e48b36e..5f02903ce 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -1,7 +1,6 @@ import * as _ from 'lodash'; import * as BigNumber from 'bignumber.js'; -import {SchemaValidator, schemas} from '0x-json-schemas'; -import promisify = require('es6-promisify'); +import {schemas} from '0x-json-schemas'; import {Web3Wrapper} from '../web3_wrapper'; import { ECSignature, @@ -34,7 +33,6 @@ import {assert} from '../utils/assert'; import {utils} from '../utils/utils'; import {OrderValidationUtils} from '../utils/order_validation_utils'; import {ContractWrapper} from './contract_wrapper'; -import {constants} from '../utils/constants'; import {TokenWrapper} from './token_wrapper'; import {decorators} from '../utils/decorators'; import {AbiDecoder} from '../utils/abi_decoder'; -- cgit