diff options
Diffstat (limited to 'src/utils')
-rw-r--r-- | src/utils/abi_decoder.ts | 2 | ||||
-rw-r--r-- | src/utils/assert.ts | 3 | ||||
-rw-r--r-- | src/utils/constants.ts | 1 | ||||
-rw-r--r-- | src/utils/event_utils.ts | 41 | ||||
-rw-r--r-- | src/utils/filter_utils.ts | 82 |
5 files changed, 87 insertions, 42 deletions
diff --git a/src/utils/abi_decoder.ts b/src/utils/abi_decoder.ts index 542591251..52b114c12 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, DecodedArgs, LogWithDecodedArgs, RawLog, SolidityTypes} from '../types'; +import {AbiType, DecodedLogArgs, LogWithDecodedArgs, RawLog, SolidityTypes} from '../types'; import * as SolidityCoder from 'web3/lib/solidity/coder'; export class AbiDecoder { diff --git a/src/utils/assert.ts b/src/utils/assert.ts index eb084129c..0b7a11939 100644 --- a/src/utils/assert.ts +++ b/src/utils/assert.ts @@ -17,6 +17,9 @@ export const assert = { isString(variableName: string, value: string): void { this.assert(_.isString(value), this.typeAssertionMessage(variableName, 'string', value)); }, + isFunction(variableName: string, value: any): void { + this.assert(_.isFunction(value), this.typeAssertionMessage(variableName, 'function', value)); + }, isHexString(variableName: string, value: string): void { this.assert(_.isString(value) && HEX_REGEX.test(value), this.typeAssertionMessage(variableName, 'HexString', value)); diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 1b11d7055..a066fe869 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -7,4 +7,5 @@ export const constants = { INVALID_JUMP_PATTERN: 'invalid JUMP at', OUT_OF_GAS_PATTERN: 'out of gas', UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1), + DEFAULT_BLOCK_POLLING_INTERVAL: 1000, }; diff --git a/src/utils/event_utils.ts b/src/utils/event_utils.ts deleted file mode 100644 index e8f30e1a8..000000000 --- a/src/utils/event_utils.ts +++ /dev/null @@ -1,41 +0,0 @@ -import * as _ from 'lodash'; -import {EventCallback, ContractEventArg, ContractEvent, ContractEventObj, ContractEventEmitter} from '../types'; -import * as BigNumber from 'bignumber.js'; -import promisify = require('es6-promisify'); - -export const eventUtils = { - wrapEventEmitter(event: ContractEventObj): ContractEventEmitter { - const watch = (eventCallback: EventCallback) => { - const bignumberWrappingEventCallback = eventUtils._getBigNumberWrappingEventCallback(eventCallback); - event.watch(bignumberWrappingEventCallback); - }; - const zeroExEvent = { - watch, - stopWatchingAsync: async () => { - await promisify(event.stopWatching, event)(); - }, - }; - return zeroExEvent; - }, - /** - * Wraps eventCallback function so that all the BigNumber arguments are wrapped in a newer version of BigNumber. - * @param eventCallback Event callback function to be wrapped - * @return Wrapped event callback function - */ - _getBigNumberWrappingEventCallback(eventCallback: EventCallback): EventCallback { - const bignumberWrappingEventCallback = (err: Error, event: ContractEvent) => { - if (_.isNull(err)) { - const wrapIfBigNumber = (value: ContractEventArg): ContractEventArg => { - // HACK: The old version of BigNumber used by Web3@0.19.0 does not support the `isBigNumber` - // and checking for a BigNumber instance using `instanceof` does not work either. We therefore - // check if the value constructor is a bignumber constructor. - const isWeb3BigNumber = _.startsWith(value.constructor.toString(), 'function BigNumber('); - return isWeb3BigNumber ? new BigNumber(value) : value; - }; - event.args = _.mapValues(event.args, wrapIfBigNumber); - } - eventCallback(err, event); - }; - return bignumberWrappingEventCallback; - }, -}; diff --git a/src/utils/filter_utils.ts b/src/utils/filter_utils.ts new file mode 100644 index 000000000..e09a95a6e --- /dev/null +++ b/src/utils/filter_utils.ts @@ -0,0 +1,82 @@ +import * as _ from 'lodash'; +import * as Web3 from 'web3'; +import * as uuid from 'uuid/v4'; +import * as ethUtil from 'ethereumjs-util'; +import * as jsSHA3 from 'js-sha3'; +import {ContractEvents, IndexedFilterValues, SubscriptionOpts} from '../types'; + +const TOPIC_LENGTH = 32; + +export const filterUtils = { + generateUUID(): string { + return uuid(); + }, + getFilter(address: string, eventName: ContractEvents, + indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi, + subscriptionOpts?: SubscriptionOpts): Web3.FilterObject { + const eventAbi = _.find(abi, {name: eventName}) as Web3.EventAbi; + const eventSignature = filterUtils.getEventSignatureFromAbiByName(eventAbi, eventName); + const topicForEventSignature = ethUtil.addHexPrefix(jsSHA3.keccak256(eventSignature)); + const topicsForIndexedArgs = filterUtils.getTopicsForIndexedArgs(eventAbi, indexFilterValues); + const topics = [topicForEventSignature, ...topicsForIndexedArgs]; + let filter: Web3.FilterObject = { + address, + topics, + }; + if (!_.isUndefined(subscriptionOpts)) { + filter = { + ...subscriptionOpts, + ...filter, + }; + } + return filter; + }, + getEventSignatureFromAbiByName(eventAbi: Web3.EventAbi, eventName: ContractEvents): string { + const types = _.map(eventAbi.inputs, 'type'); + const signature = `${eventAbi.name}(${types.join(',')})`; + return signature; + }, + 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])) { + // Null is a wildcard topic in a JSON-RPC call + 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; + }, + matchesFilter(log: Web3.LogEntry, filter: Web3.FilterObject): boolean { + if (!_.isUndefined(filter.address) && log.address !== filter.address) { + return false; + } + if (!_.isUndefined(filter.topics)) { + return filterUtils.matchesTopics(log.topics, filter.topics); + } + return true; + }, + matchesTopics(logTopics: string[], filterTopics: Array<string[]|string|null>): boolean { + const matchesTopic = _.zipWith(logTopics, filterTopics, filterUtils.matchesTopic.bind(filterUtils)); + const matchesTopics = _.every(matchesTopic); + return matchesTopics; + }, + matchesTopic(logTopic: string, filterTopic: string[]|string|null): boolean { + if (_.isArray(filterTopic)) { + return _.includes(filterTopic, logTopic); + } + if (_.isString(filterTopic)) { + return filterTopic === logTopic; + } + // null topic is a wildcard + return true; + }, +}; |