aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabio Berger <me@fabioberger.com>2017-06-02 18:31:16 +0800
committerFabio Berger <me@fabioberger.com>2017-06-02 18:31:16 +0800
commitfc3be810a25ce98402c686bd41606e08e7b5c2ac (patch)
treeda0d7ee884c9df78ee7fc0659517075461b35096
parent104b7f2549e0164f629594c590b3d2d936ba66d0 (diff)
downloaddexon-sol-tools-fc3be810a25ce98402c686bd41606e08e7b5c2ac.tar
dexon-sol-tools-fc3be810a25ce98402c686bd41606e08e7b5c2ac.tar.gz
dexon-sol-tools-fc3be810a25ce98402c686bd41606e08e7b5c2ac.tar.bz2
dexon-sol-tools-fc3be810a25ce98402c686bd41606e08e7b5c2ac.tar.lz
dexon-sol-tools-fc3be810a25ce98402c686bd41606e08e7b5c2ac.tar.xz
dexon-sol-tools-fc3be810a25ce98402c686bd41606e08e7b5c2ac.tar.zst
dexon-sol-tools-fc3be810a25ce98402c686bd41606e08e7b5c2ac.zip
Implement zeroEx.exchange.subscribeAsync made sure to clean up subscriptions if user updates the provider
-rw-r--r--src/0x.js.ts4
-rw-r--r--src/contract_wrappers/exchange_wrapper.ts46
-rw-r--r--src/types.ts41
-rw-r--r--src/utils/utils.ts3
-rw-r--r--test/0x.js_test.ts6
5 files changed, 94 insertions, 6 deletions
diff --git a/src/0x.js.ts b/src/0x.js.ts
index 967c81ed8..0cda7732d 100644
--- a/src/0x.js.ts
+++ b/src/0x.js.ts
@@ -115,9 +115,9 @@ export class ZeroEx {
/**
* Sets a new provider for the web3 instance used by 0x.js
*/
- public setProvider(provider: Web3.Provider) {
+ public async setProviderAsync(provider: Web3.Provider) {
this.web3Wrapper.setProvider(provider);
- this.exchange.invalidateContractInstance();
+ await this.exchange.invalidateContractInstanceAsync();
this.tokenRegistry.invalidateContractInstance();
this.token.invalidateContractInstances();
}
diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts
index f32cb88a6..b394edb06 100644
--- a/src/contract_wrappers/exchange_wrapper.ts
+++ b/src/contract_wrappers/exchange_wrapper.ts
@@ -1,5 +1,6 @@
import * as _ from 'lodash';
import * as BigNumber from 'bignumber.js';
+import promisify = require('es6-promisify');
import {Web3Wrapper} from '../web3_wrapper';
import {
ECSignature,
@@ -11,8 +12,16 @@ import {
OrderAddresses,
SignedOrder,
ContractEvent,
+ ZeroExError,
+ ExchangeEvents,
+ SubscriptionOpts,
+ IndexFilterValues,
+ CreateContractEvent,
+ ContractEventObj,
+ EventCallback,
} from '../types';
import {assert} from '../utils/assert';
+import {utils} from '../utils/utils';
import {ContractWrapper} from './contract_wrapper';
import * as ExchangeArtifacts from '../artifacts/Exchange.json';
import {ecSignatureSchema} from '../schemas/ec_signature_schema';
@@ -32,12 +41,15 @@ export class ExchangeWrapper extends ContractWrapper {
[ExchangeContractErrCodes.ERROR_FILL_BALANCE_ALLOWANCE]: ExchangeContractErrs.ORDER_BALANCE_ALLOWANCE_ERROR,
};
private exchangeContractIfExists?: ExchangeContract;
+ private exchangeLogEventObjs: ContractEventObj[];
private tokenWrapper: TokenWrapper;
constructor(web3Wrapper: Web3Wrapper, tokenWrapper: TokenWrapper) {
super(web3Wrapper);
this.tokenWrapper = tokenWrapper;
+ this.exchangeLogEventObjs = [];
}
- public invalidateContractInstance(): void {
+ public async invalidateContractInstanceAsync(): Promise<void> {
+ await this.stopWatchingExchangeLogEventsAsync();
delete this.exchangeContractIfExists;
}
public async isValidSignatureAsync(dataHex: string, ecSignature: ECSignature,
@@ -159,6 +171,38 @@ export class ExchangeWrapper extends ContractWrapper {
);
this.throwErrorLogsAsErrors(response.logs);
}
+ /**
+ * Subscribe to an event type emitted by the Exchange smart contract
+ */
+ public async subscribeAsync(eventName: ExchangeEvents, subscriptionOpts: SubscriptionOpts,
+ indexFilterValues: IndexFilterValues, callback: EventCallback) {
+ 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:
+ utils.spawnSwitchErr('ExchangeEvents', eventName);
+ return;
+ }
+
+ const logEventObj: ContractEventObj = createLogEvent(indexFilterValues, subscriptionOpts);
+ logEventObj.watch(callback);
+ this.exchangeLogEventObjs.push(logEventObj);
+ }
+ private async stopWatchingExchangeLogEventsAsync() {
+ for (const logEventObj of this.exchangeLogEventObjs) {
+ await promisify(logEventObj.stopWatching, logEventObj)();
+ }
+ this.exchangeLogEventObjs = [];
+ }
private async validateFillOrderAsync(signedOrder: SignedOrder, fillAmount: BigNumber.BigNumber,
senderAddress: string) {
if (fillAmount.eq(0)) {
diff --git a/src/types.ts b/src/types.ts
index 29f7e0ee4..c6ad68d3f 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -51,6 +51,22 @@ export interface ExchangeContract {
};
}
+export type EventCallbackAsync = (err: Error, event: ContractEvent) => Promise<void>;
+export type EventCallbackSync = (err: Error, event: ContractEvent) => void;
+export type EventCallback = EventCallbackSync|EventCallbackAsync;
+export interface ContractEventObj {
+ watch: (eventWatch: EventCallback) => void;
+ stopWatching: () => void;
+}
+export type CreateContractEvent = (indexFilterValues: IndexFilterValues,
+ subscriptionOpts: SubscriptionOpts) => ContractEventObj;
+export interface ExchangeContract {
+ isValidSignature: any;
+ LogFill: CreateContractEvent;
+ LogCancel: CreateContractEvent;
+ LogError: CreateContractEvent;
+}
+
export interface TokenContract {
balanceOf: {
call: (address: string) => Promise<BigNumber.BigNumber>;
@@ -110,6 +126,13 @@ export interface ContractResponse {
}
export interface ContractEvent {
+ logIndex: number;
+ transactionIndex: number;
+ transactionHash: string;
+ blockHash: string;
+ blockNumber: number;
+ address: string;
+ type: string;
event: string;
args: any;
}
@@ -151,3 +174,21 @@ export interface TxOpts {
export interface TokenAddressBySymbol {
[symbol: string]: string;
}
+
+export const ExchangeEvents = strEnum([
+ 'LogFill',
+ 'LogCancel',
+ 'LogError',
+]);
+export type ExchangeEvents = keyof typeof ExchangeEvents;
+
+export interface IndexFilterValues {
+ [index: string]: any;
+}
+
+export interface SubscriptionOpts {
+ fromBlock: string|number;
+ toBlock: string|number;
+}
+
+export type DoneCallback = (err?: Error) => void;
diff --git a/src/utils/utils.ts b/src/utils/utils.ts
index e6840a624..114b46f6c 100644
--- a/src/utils/utils.ts
+++ b/src/utils/utils.ts
@@ -22,4 +22,7 @@ export const utils = {
const isValid = /^0x[0-9A-F]{64}$/i.test(orderHashHex);
return isValid;
},
+ spawnSwitchErr(name: string, value: any) {
+ return new Error(`Unexpected switch value: ${value} encountered for ${name}`);
+ },
};
diff --git a/test/0x.js_test.ts b/test/0x.js_test.ts
index efc703ea1..52580171b 100644
--- a/test/0x.js_test.ts
+++ b/test/0x.js_test.ts
@@ -8,7 +8,7 @@ import * as Sinon from 'sinon';
import {ZeroEx} from '../src/0x.js';
import {constants} from './utils/constants';
import {web3Factory} from './utils/web3_factory';
-import {Order} from '../src/types';
+import {Order, DoneCallback} from '../src/types';
chai.use(ChaiBigNumber());
chai.use(dirtyChai);
@@ -16,7 +16,7 @@ const expect = chai.expect;
describe('ZeroEx library', () => {
describe('#setProvider', () => {
- it('overrides the provider in the nested web3 instance and invalidates contractInstances', async () => {
+ it('overrides provider in nested web3s and invalidates contractInstances', async () => {
const web3 = web3Factory.create();
const zeroEx = new ZeroEx(web3);
// Instantiate the contract instances with the current provider
@@ -28,7 +28,7 @@ describe('ZeroEx library', () => {
const newProvider = web3Factory.getRpcProvider();
// Add property to newProvider so that we can differentiate it from old provider
(newProvider as any).zeroExTestId = 1;
- zeroEx.setProvider(newProvider);
+ await zeroEx.setProviderAsync(newProvider);
// Check that contractInstances with old provider are removed after provider update
expect((zeroEx.exchange as any).exchangeContractIfExists).to.be.undefined();