diff options
author | Leonid <logvinov.leon@gmail.com> | 2017-10-04 19:30:36 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-10-04 19:30:36 +0800 |
commit | 836d9be7fee9986c8ffa380633d873ba557511f4 (patch) | |
tree | bdbe710ada39c7619efa5087cdd4eee6256cbf33 /src/contract_wrappers | |
parent | 5d554ab88246563a8efcbde1b92e45ab926214d5 (diff) | |
parent | e5bdf60460330a24597e018f3611e7bc939c1362 (diff) | |
download | dexon-sol-tools-836d9be7fee9986c8ffa380633d873ba557511f4.tar dexon-sol-tools-836d9be7fee9986c8ffa380633d873ba557511f4.tar.gz dexon-sol-tools-836d9be7fee9986c8ffa380633d873ba557511f4.tar.bz2 dexon-sol-tools-836d9be7fee9986c8ffa380633d873ba557511f4.tar.lz dexon-sol-tools-836d9be7fee9986c8ffa380633d873ba557511f4.tar.xz dexon-sol-tools-836d9be7fee9986c8ffa380633d873ba557511f4.tar.zst dexon-sol-tools-836d9be7fee9986c8ffa380633d873ba557511f4.zip |
Merge pull request #178 from 0xProject/feature/getLogs
Add zeroEx.getLogsAsync
Diffstat (limited to 'src/contract_wrappers')
-rw-r--r-- | src/contract_wrappers/contract_wrapper.ts | 66 | ||||
-rw-r--r-- | src/contract_wrappers/exchange_wrapper.ts | 23 | ||||
-rw-r--r-- | src/contract_wrappers/token_wrapper.ts | 24 |
3 files changed, 107 insertions, 6 deletions
diff --git a/src/contract_wrappers/contract_wrapper.ts b/src/contract_wrappers/contract_wrapper.ts index 2a55b53d9..743dfc9b2 100644 --- a/src/contract_wrappers/contract_wrapper.ts +++ b/src/contract_wrappers/contract_wrapper.ts @@ -1,13 +1,52 @@ import * as _ from 'lodash'; import * as Web3 from 'web3'; +import * as ethUtil from 'ethereumjs-util'; import {Web3Wrapper} from '../web3_wrapper'; -import {ZeroExError, Artifact} from '../types'; +import {AbiDecoder} from '../utils/abi_decoder'; +import { + InternalZeroExError, + Artifact, + LogWithDecodedArgs, + RawLog, + ContractEvents, + SubscriptionOpts, + IndexedFilterValues, +} from '../types'; import {utils} from '../utils/utils'; +const TOPIC_LENGTH = 32; + export class ContractWrapper { protected _web3Wrapper: Web3Wrapper; - constructor(web3Wrapper: Web3Wrapper) { + private _abiDecoder?: AbiDecoder; + constructor(web3Wrapper: Web3Wrapper, abiDecoder?: AbiDecoder) { this._web3Wrapper = web3Wrapper; + this._abiDecoder = abiDecoder; + } + protected async _getLogsAsync(address: string, eventName: ContractEvents, subscriptionOpts: SubscriptionOpts, + indexFilterValues: IndexedFilterValues, + abi: Web3.ContractAbi): Promise<LogWithDecodedArgs[]> { + const eventAbi = _.find(abi, {name: eventName}) as Web3.EventAbi; + const eventSignature = this._getEventSignatureFromAbiByName(eventAbi, eventName); + const topicForEventSignature = this._web3Wrapper.keccak256(eventSignature); + const topicsForIndexedArgs = this._getTopicsForIndexedArgs(eventAbi, indexFilterValues); + const topics = [topicForEventSignature, ...topicsForIndexedArgs]; + const filter = { + fromBlock: subscriptionOpts.fromBlock, + toBlock: subscriptionOpts.toBlock, + address, + topics, + }; + const logs = await this._web3Wrapper.getLogsAsync(filter); + const logsWithDecodedArguments = _.map(logs, this._tryToDecodeLogOrNoop.bind(this)); + return logsWithDecodedArguments; + } + protected _tryToDecodeLogOrNoop(log: Web3.LogEntry): LogWithDecodedArgs|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, @@ -16,4 +55,27 @@ export class ContractWrapper { await this._web3Wrapper.getContractInstanceFromArtifactAsync<A>(artifact, addressIfExists); return contractInstance; } + protected _getEventSignatureFromAbiByName(eventAbi: Web3.EventAbi, eventName: ContractEvents): string { + const types = _.map(eventAbi.inputs, 'type'); + const signature = `${eventAbi.name}(${types.join(',')})`; + return signature; + } + private _getTopicsForIndexedArgs(abi: Web3.EventAbi, indexFilterValues: IndexedFilterValues): Array<string|null> { + const topics: Array<string|null> = []; + for (const eventInput of abi.inputs) { + if (!eventInput.indexed) { + continue; + } + if (_.isUndefined(indexFilterValues[eventInput.name])) { + topics.push(null); + } else { + const value = indexFilterValues[eventInput.name] as string; + const buffer = ethUtil.toBuffer(value); + const paddedBuffer = ethUtil.setLengthLeft(buffer, TOPIC_LENGTH); + const topic = ethUtil.bufferToHex(paddedBuffer); + topics.push(topic); + } + } + return topics; + } } diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index d02a6e642..b3a35d5bf 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -30,6 +30,7 @@ import { MethodOpts, ValidateOrderFillableOpts, OrderTransactionOpts, + RawLog, } from '../types'; import {assert} from '../utils/assert'; import {utils} from '../utils/utils'; @@ -39,6 +40,7 @@ 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'; import {artifacts} from '../artifacts'; const SHOULD_VALIDATE_BY_DEFAULT = true; @@ -79,8 +81,9 @@ export class ExchangeWrapper extends ContractWrapper { ]; return [orderAddresses, orderValues]; } - constructor(web3Wrapper: Web3Wrapper, tokenWrapper: TokenWrapper, contractAddressIfExists?: string) { - super(web3Wrapper); + constructor(web3Wrapper: Web3Wrapper, abiDecoder: AbiDecoder, + tokenWrapper: TokenWrapper, contractAddressIfExists?: string) { + super(web3Wrapper, abiDecoder); this._tokenWrapper = tokenWrapper; this._orderValidationUtils = new OrderValidationUtils(tokenWrapper, this); this._exchangeLogEventEmitters = []; @@ -656,6 +659,22 @@ export class ExchangeWrapper extends ContractWrapper { return eventEmitter; } /** + * Gets historical logs without creating a subscription + * @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 `{_from: aUserAddressHex}` + * @return Array of logs that match the parameters + */ + public async getLogsAsync(eventName: ExchangeEvents, subscriptionOpts: SubscriptionOpts, + indexFilterValues: IndexedFilterValues): Promise<LogWithDecodedArgs[]> { + const exchangeContractAddress = await this.getContractAddressAsync(); + const logs = await this._getLogsAsync( + exchangeContractAddress, eventName, subscriptionOpts, indexFilterValues, artifacts.ExchangeArtifact.abi, + ); + return logs; + } + /** * Stops watching for all exchange events */ public async stopWatchingAllEventsAsync(): Promise<void> { diff --git a/src/contract_wrappers/token_wrapper.ts b/src/contract_wrappers/token_wrapper.ts index f7f0a0ce3..91af223e4 100644 --- a/src/contract_wrappers/token_wrapper.ts +++ b/src/contract_wrappers/token_wrapper.ts @@ -7,6 +7,7 @@ import {utils} from '../utils/utils'; import {eventUtils} from '../utils/event_utils'; import {constants} from '../utils/constants'; import {ContractWrapper} from './contract_wrapper'; +import {AbiDecoder} from '../utils/abi_decoder'; import {artifacts} from '../artifacts'; import { TokenContract, @@ -18,6 +19,8 @@ import { ContractEventEmitter, ContractEventObj, MethodOpts, + LogWithDecodedArgs, + RawLog, } from '../types'; const ALLOWANCE_TO_ZERO_GAS_AMOUNT = 47155; @@ -32,8 +35,9 @@ export class TokenWrapper extends ContractWrapper { private _tokenContractsByAddress: {[address: string]: TokenContract}; private _tokenLogEventEmitters: ContractEventEmitter[]; private _tokenTransferProxyContractAddressFetcher: () => Promise<string>; - constructor(web3Wrapper: Web3Wrapper, tokenTransferProxyContractAddressFetcher: () => Promise<string>) { - super(web3Wrapper); + constructor(web3Wrapper: Web3Wrapper, abiDecoder: AbiDecoder, + tokenTransferProxyContractAddressFetcher: () => Promise<string>) { + super(web3Wrapper, abiDecoder); this._tokenContractsByAddress = {}; this._tokenLogEventEmitters = []; this._tokenTransferProxyContractAddressFetcher = tokenTransferProxyContractAddressFetcher; @@ -277,6 +281,22 @@ export class TokenWrapper extends ContractWrapper { return eventEmitter; } /** + * Gets historical logs without creating a subscription + * @param tokenAddress An address of the token that emmited the logs. + * @param eventName The token 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 `{_from: aUserAddressHex}` + * @return Array of logs that match the parameters + */ + public async getLogsAsync(tokenAddress: string, eventName: TokenEvents, subscriptionOpts: SubscriptionOpts, + indexFilterValues: IndexedFilterValues): Promise<LogWithDecodedArgs[]> { + const logs = await this._getLogsAsync( + tokenAddress, eventName, subscriptionOpts, indexFilterValues, artifacts.TokenArtifact.abi, + ); + return logs; + } + /** * Stops watching for all token events */ public async stopWatchingAllEventsAsync(): Promise<void> { |