diff options
Diffstat (limited to 'src/contract_wrappers/contract_wrapper.ts')
-rw-r--r-- | src/contract_wrappers/contract_wrapper.ts | 66 |
1 files changed, 64 insertions, 2 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; + } } |