diff options
author | Leonid Logvinov <logvinov.leon@gmail.com> | 2017-10-13 17:52:59 +0800 |
---|---|---|
committer | Leonid Logvinov <logvinov.leon@gmail.com> | 2017-10-13 17:52:59 +0800 |
commit | 0eaca6c691d92a10b08c0e69306291aa8de06bfb (patch) | |
tree | ffa00109b4115025b8be35822abbbbd4ddb05155 /src | |
parent | ba654c04a086b8c4ce4330b3d6064716a4090599 (diff) | |
download | dexon-sol-tools-0eaca6c691d92a10b08c0e69306291aa8de06bfb.tar dexon-sol-tools-0eaca6c691d92a10b08c0e69306291aa8de06bfb.tar.gz dexon-sol-tools-0eaca6c691d92a10b08c0e69306291aa8de06bfb.tar.bz2 dexon-sol-tools-0eaca6c691d92a10b08c0e69306291aa8de06bfb.tar.lz dexon-sol-tools-0eaca6c691d92a10b08c0e69306291aa8de06bfb.tar.xz dexon-sol-tools-0eaca6c691d92a10b08c0e69306291aa8de06bfb.tar.zst dexon-sol-tools-0eaca6c691d92a10b08c0e69306291aa8de06bfb.zip |
Make logs fetching and sunscriptions more type-safe
Diffstat (limited to 'src')
-rw-r--r-- | src/contract_wrappers/contract_wrapper.ts | 29 | ||||
-rw-r--r-- | src/contract_wrappers/exchange_wrapper.ts | 27 | ||||
-rw-r--r-- | src/contract_wrappers/token_wrapper.ts | 15 | ||||
-rw-r--r-- | src/index.ts | 1 | ||||
-rw-r--r-- | src/types.ts | 16 | ||||
-rw-r--r-- | src/utils/abi_decoder.ts | 5 |
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)) { |