aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLeonid <logvinov.leon@gmail.com>2017-10-13 22:16:11 +0800
committerGitHub <noreply@github.com>2017-10-13 22:16:11 +0800
commit5591378245184178dd1a1997076bb1cbb17ddcb1 (patch)
tree0ce4bebb4c038748e04f791cda501543018113df /src
parentba654c04a086b8c4ce4330b3d6064716a4090599 (diff)
parentdde2268f9fad24ad8baee88eca7aef068d05c178 (diff)
downloaddexon-sol-tools-5591378245184178dd1a1997076bb1cbb17ddcb1.tar
dexon-sol-tools-5591378245184178dd1a1997076bb1cbb17ddcb1.tar.gz
dexon-sol-tools-5591378245184178dd1a1997076bb1cbb17ddcb1.tar.bz2
dexon-sol-tools-5591378245184178dd1a1997076bb1cbb17ddcb1.tar.lz
dexon-sol-tools-5591378245184178dd1a1997076bb1cbb17ddcb1.tar.xz
dexon-sol-tools-5591378245184178dd1a1997076bb1cbb17ddcb1.tar.zst
dexon-sol-tools-5591378245184178dd1a1997076bb1cbb17ddcb1.zip
Merge pull request #194 from 0xProject/feature/type-safe-subscriptions
Make logs fetching and subscriptions more type-safe
Diffstat (limited to 'src')
-rw-r--r--src/contract_wrappers/contract_wrapper.ts29
-rw-r--r--src/contract_wrappers/exchange_wrapper.ts27
-rw-r--r--src/contract_wrappers/token_wrapper.ts15
-rw-r--r--src/index.ts1
-rw-r--r--src/types.ts16
-rw-r--r--src/utils/abi_decoder.ts5
6 files changed, 52 insertions, 41 deletions
diff --git a/src/contract_wrappers/contract_wrapper.ts b/src/contract_wrappers/contract_wrapper.ts
index f6ccfdee4..19dccc6f2 100644
--- a/src/contract_wrappers/contract_wrapper.ts
+++ b/src/contract_wrappers/contract_wrapper.ts
@@ -14,6 +14,7 @@ import {
IndexedFilterValues,
EventCallback,
BlockParamLiteral,
+ ContractEventArgs,
} from '../types';
import {constants} from '../utils/constants';
import {intervalUtils} from '../utils/interval_utils';
@@ -25,7 +26,7 @@ export class ContractWrapper {
private _blockAndLogStreamer: BlockAndLogStreamer|undefined;
private _blockAndLogStreamInterval: NodeJS.Timer;
private _filters: {[filterToken: string]: Web3.FilterObject};
- private _filterCallbacks: {[filterToken: string]: EventCallback};
+ private _filterCallbacks: {[filterToken: string]: EventCallback<ContractEventArgs>};
private _onLogAddedSubscriptionToken: string|undefined;
private _onLogRemovedSubscriptionToken: string|undefined;
constructor(web3Wrapper: Web3Wrapper, abiDecoder?: AbiDecoder) {
@@ -37,9 +38,9 @@ export class ContractWrapper {
this._onLogAddedSubscriptionToken = undefined;
this._onLogRemovedSubscriptionToken = undefined;
}
- protected _subscribe(address: string, eventName: ContractEvents,
- indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi,
- callback: EventCallback): string {
+ protected _subscribe<ArgsType extends ContractEventArgs>(
+ address: string, eventName: ContractEvents, indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi,
+ callback: EventCallback<ArgsType>): string {
const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi);
if (_.isUndefined(this._blockAndLogStreamer)) {
this._startBlockAndLogStream();
@@ -59,32 +60,32 @@ export class ContractWrapper {
this._stopBlockAndLogStream();
}
}
- protected async _getLogsAsync(address: string, eventName: ContractEvents, subscriptionOpts: SubscriptionOpts,
- indexFilterValues: IndexedFilterValues,
- abi: Web3.ContractAbi): Promise<LogWithDecodedArgs[]> {
+ protected async _getLogsAsync<ArgsType extends ContractEventArgs>(
+ address: string, eventName: ContractEvents, subscriptionOpts: SubscriptionOpts,
+ indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi, subscriptionOpts);
const logs = await this._web3Wrapper.getLogsAsync(filter);
const logsWithDecodedArguments = _.map(logs, this._tryToDecodeLogOrNoop.bind(this));
return logsWithDecodedArguments;
}
- protected _tryToDecodeLogOrNoop(log: Web3.LogEntry): LogWithDecodedArgs|RawLog {
+ protected _tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>(
+ log: Web3.LogEntry): LogWithDecodedArgs<ArgsType>|RawLog {
if (_.isUndefined(this._abiDecoder)) {
throw new Error(InternalZeroExError.NoAbiDecoder);
}
const logWithDecodedArgs = this._abiDecoder.tryToDecodeLogOrNoop(log);
return logWithDecodedArgs;
}
- protected async _instantiateContractIfExistsAsync<A extends Web3.ContractInstance>(artifact: Artifact,
- addressIfExists?: string,
- ): Promise<A> {
+ protected async _instantiateContractIfExistsAsync<ContractType extends Web3.ContractInstance>(
+ artifact: Artifact, addressIfExists?: string): Promise<ContractType> {
const contractInstance =
- await this._web3Wrapper.getContractInstanceFromArtifactAsync<A>(artifact, addressIfExists);
+ await this._web3Wrapper.getContractInstanceFromArtifactAsync<ContractType>(artifact, addressIfExists);
return contractInstance;
}
- private _onLogStateChanged(removed: boolean, log: Web3.LogEntry): void {
+ private _onLogStateChanged<ArgsType extends ContractEventArgs>(removed: boolean, log: Web3.LogEntry): void {
_.forEach(this._filters, (filter: Web3.FilterObject, filterToken: string) => {
if (filterUtils.matchesFilter(log, filter)) {
- const decodedLog = this._tryToDecodeLogOrNoop(log) as LogWithDecodedArgs;
+ const decodedLog = this._tryToDecodeLogOrNoop(log) as LogWithDecodedArgs<ArgsType>;
const logEvent = {
...decodedLog,
removed,
diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts
index 9e4936de6..739fe74c6 100644
--- a/src/contract_wrappers/exchange_wrapper.ts
+++ b/src/contract_wrappers/exchange_wrapper.ts
@@ -1,4 +1,5 @@
import * as _ from 'lodash';
+import * as Web3 from 'web3';
import * as BigNumber from 'bignumber.js';
import {schemas} from '0x-json-schemas';
import {Web3Wrapper} from '../web3_wrapper';
@@ -28,6 +29,8 @@ import {
OrderTransactionOpts,
RawLog,
EventCallback,
+ ExchangeContractEventArgs,
+ DecodedLogArgs,
} from '../types';
import {assert} from '../utils/assert';
import {utils} from '../utils/utils';
@@ -654,13 +657,14 @@ export class ExchangeWrapper extends ContractWrapper {
* @param callback Callback that gets called when a log is added/removed
* @return Subscription token used later to unsubscribe
*/
- public async subscribeAsync(eventName: ExchangeEvents, indexFilterValues: IndexedFilterValues,
- callback: EventCallback): Promise<string> {
+ public async subscribeAsync<ArgsType extends ExchangeContractEventArgs>(
+ eventName: ExchangeEvents, indexFilterValues: IndexedFilterValues,
+ callback: EventCallback<ArgsType>): Promise<string> {
assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
assert.isFunction('callback', callback);
const exchangeContractAddress = await this.getContractAddressAsync();
- const subscriptionToken = this._subscribe(
+ const subscriptionToken = this._subscribe<ArgsType>(
exchangeContractAddress, eventName, indexFilterValues, artifacts.ExchangeArtifact.abi, callback,
);
this._activeSubscriptions.push(subscriptionToken);
@@ -682,13 +686,14 @@ export class ExchangeWrapper extends ContractWrapper {
* the value is the value you are interested in. E.g `{_from: aUserAddressHex}`
* @return Array of logs that match the parameters
*/
- public async getLogsAsync(eventName: ExchangeEvents, subscriptionOpts: SubscriptionOpts,
- indexFilterValues: IndexedFilterValues): Promise<LogWithDecodedArgs[]> {
+ public async getLogsAsync<ArgsType extends ExchangeContractEventArgs>(
+ eventName: ExchangeEvents, subscriptionOpts: SubscriptionOpts, indexFilterValues: IndexedFilterValues,
+ ): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents);
assert.doesConformToSchema('subscriptionOpts', subscriptionOpts, schemas.subscriptionOptsSchema);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
const exchangeContractAddress = await this.getContractAddressAsync();
- const logs = await this._getLogsAsync(
+ const logs = await this._getLogsAsync<ArgsType>(
exchangeContractAddress, eventName, subscriptionOpts, indexFilterValues, artifacts.ExchangeArtifact.abi,
);
return logs;
@@ -799,12 +804,14 @@ export class ExchangeWrapper extends ContractWrapper {
}
/**
* Checks if logs contain LogError, which is emmited by Exchange contract on transaction failure.
- * @param logsWithDecodedArgs Transaction logs as returned by `zeroEx.awaitTransactionMinedAsync`
+ * @param logs Transaction logs as returned by `zeroEx.awaitTransactionMinedAsync`
*/
- public throwLogErrorsAsErrors(logsWithDecodedArgs: LogWithDecodedArgs[]): void {
- const errLog = _.find(logsWithDecodedArgs, {event: ExchangeEvents.LogError});
+ public throwLogErrorsAsErrors(logs: Array<LogWithDecodedArgs<DecodedLogArgs>|Web3.LogEntry>): void {
+ const errLog = _.find(logs, {
+ event: ExchangeEvents.LogError,
+ }) as LogWithDecodedArgs<LogErrorContractEventArgs>|undefined;
if (!_.isUndefined(errLog)) {
- const logArgs: LogErrorContractEventArgs = errLog.args as any;
+ const logArgs = errLog.args;
const errCode = logArgs.errorId.toNumber();
const errMessage = this._exchangeContractErrCodesToMsg[errCode];
throw new Error(errMessage);
diff --git a/src/contract_wrappers/token_wrapper.ts b/src/contract_wrappers/token_wrapper.ts
index abd090f7e..8dc4e61c5 100644
--- a/src/contract_wrappers/token_wrapper.ts
+++ b/src/contract_wrappers/token_wrapper.ts
@@ -16,6 +16,7 @@ import {
MethodOpts,
LogWithDecodedArgs,
EventCallback,
+ TokenContractEventArgs,
} from '../types';
const ALLOWANCE_TO_ZERO_GAS_AMOUNT = 47155;
@@ -251,13 +252,14 @@ export class TokenWrapper extends ContractWrapper {
* @param callback Callback that gets called when a log is added/removed
* @return Subscription token used later to unsubscribe
*/
- public subscribe(tokenAddress: string, eventName: TokenEvents, indexFilterValues: IndexedFilterValues,
- callback: EventCallback): string {
+ public subscribe<ArgsType extends TokenContractEventArgs>(
+ tokenAddress: string, eventName: TokenEvents, indexFilterValues: IndexedFilterValues,
+ callback: EventCallback<ArgsType>): string {
assert.isETHAddressHex('tokenAddress', tokenAddress);
assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
assert.isFunction('callback', callback);
- const subscriptionToken = this._subscribe(
+ const subscriptionToken = this._subscribe<ArgsType>(
tokenAddress, eventName, indexFilterValues, artifacts.TokenArtifact.abi, callback,
);
this._activeSubscriptions.push(subscriptionToken);
@@ -280,13 +282,14 @@ export class TokenWrapper extends ContractWrapper {
* the value is the value you are interested in. E.g `{_from: aUserAddressHex}`
* @return Array of logs that match the parameters
*/
- public async getLogsAsync(tokenAddress: string, eventName: TokenEvents, subscriptionOpts: SubscriptionOpts,
- indexFilterValues: IndexedFilterValues): Promise<LogWithDecodedArgs[]> {
+ public async getLogsAsync<ArgsType extends TokenContractEventArgs>(
+ tokenAddress: string, eventName: TokenEvents, subscriptionOpts: SubscriptionOpts,
+ indexFilterValues: IndexedFilterValues): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
assert.isETHAddressHex('tokenAddress', tokenAddress);
assert.doesBelongToStringEnum('eventName', eventName, TokenEvents);
assert.doesConformToSchema('subscriptionOpts', subscriptionOpts, schemas.subscriptionOptsSchema);
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
- const logs = await this._getLogsAsync(
+ const logs = await this._getLogsAsync<ArgsType>(
tokenAddress, eventName, subscriptionOpts, indexFilterValues, artifacts.TokenArtifact.abi,
);
return logs;
diff --git a/src/index.ts b/src/index.ts
index 048050c7a..f287a8c57 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -32,7 +32,6 @@ export {
ZeroExConfig,
TransactionReceiptWithDecodedLogs,
LogWithDecodedArgs,
- DecodedLogArgs,
MethodOpts,
OrderTransactionOpts,
FilterObject,
diff --git a/src/types.ts b/src/types.ts
index 8c0bc1cf9..d933404b7 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -36,12 +36,12 @@ export type OrderAddresses = [string, string, string, string, string];
export type OrderValues = [BigNumber.BigNumber, BigNumber.BigNumber, BigNumber.BigNumber,
BigNumber.BigNumber, BigNumber.BigNumber, BigNumber.BigNumber];
-export interface LogEvent extends LogWithDecodedArgs {
+export interface LogEvent<ArgsType> extends LogWithDecodedArgs<ArgsType> {
removed: boolean;
}
-export type EventCallbackAsync = (log: LogEvent) => Promise<void>;
-export type EventCallbackSync = (log: LogEvent) => void;
-export type EventCallback = EventCallbackSync|EventCallbackAsync;
+export type EventCallbackAsync<ArgsType> = (log: LogEvent<ArgsType>) => Promise<void>;
+export type EventCallbackSync<ArgsType> = (log: LogEvent<ArgsType>) => void;
+export type EventCallback<ArgsType> = EventCallbackSync<ArgsType>|EventCallbackAsync<ArgsType>;
export interface ExchangeContract extends Web3.ContractInstance {
isValidSignature: {
callAsync: (signerAddressHex: string, dataHex: string, v: number, r: string, s: string,
@@ -419,15 +419,15 @@ export interface DecodedLogArgs {
[argName: string]: ContractEventArg;
}
-export interface DecodedArgs {
- args: DecodedLogArgs;
+export interface DecodedArgs<ArgsType> {
+ args: ArgsType;
event: string;
}
-export interface LogWithDecodedArgs extends Web3.LogEntry, DecodedArgs {}
+export interface LogWithDecodedArgs<ArgsType> extends Web3.LogEntry, DecodedArgs<ArgsType> {}
export interface TransactionReceiptWithDecodedLogs extends Web3.TransactionReceipt {
- logs: Array<LogWithDecodedArgs|Web3.LogEntry>;
+ logs: Array<LogWithDecodedArgs<DecodedLogArgs>|Web3.LogEntry>;
}
export interface Artifact {
diff --git a/src/utils/abi_decoder.ts b/src/utils/abi_decoder.ts
index 52b114c12..a6c45bee7 100644
--- a/src/utils/abi_decoder.ts
+++ b/src/utils/abi_decoder.ts
@@ -1,7 +1,7 @@
import * as Web3 from 'web3';
import * as _ from 'lodash';
import * as BigNumber from 'bignumber.js';
-import {AbiType, DecodedLogArgs, LogWithDecodedArgs, RawLog, SolidityTypes} from '../types';
+import {AbiType, DecodedLogArgs, LogWithDecodedArgs, RawLog, SolidityTypes, ContractEventArgs} from '../types';
import * as SolidityCoder from 'web3/lib/solidity/coder';
export class AbiDecoder {
@@ -11,7 +11,8 @@ export class AbiDecoder {
_.map(abiArrays, this.addABI.bind(this));
}
// This method can only decode logs from the 0x smart contracts
- public tryToDecodeLogOrNoop(log: Web3.LogEntry): LogWithDecodedArgs|RawLog {
+ public tryToDecodeLogOrNoop<ArgsType extends ContractEventArgs>(
+ log: Web3.LogEntry): LogWithDecodedArgs<ArgsType>|RawLog {
const methodId = log.topics[0];
const event = this.methodIds[methodId];
if (_.isUndefined(event)) {