diff options
author | Leonid Logvinov <logvinov.leon@gmail.com> | 2017-10-05 19:34:30 +0800 |
---|---|---|
committer | Leonid Logvinov <logvinov.leon@gmail.com> | 2017-10-05 20:35:37 +0800 |
commit | 7dd63523939822203d938511472c84b8ff418aaf (patch) | |
tree | 68e75aa486e673fc7faf2dc69e0527844b842e81 /src/utils | |
parent | e37a3155cd52d35da3eef9a8dc450b9b3df0b888 (diff) | |
download | dexon-sol-tools-7dd63523939822203d938511472c84b8ff418aaf.tar dexon-sol-tools-7dd63523939822203d938511472c84b8ff418aaf.tar.gz dexon-sol-tools-7dd63523939822203d938511472c84b8ff418aaf.tar.bz2 dexon-sol-tools-7dd63523939822203d938511472c84b8ff418aaf.tar.lz dexon-sol-tools-7dd63523939822203d938511472c84b8ff418aaf.tar.xz dexon-sol-tools-7dd63523939822203d938511472c84b8ff418aaf.tar.zst dexon-sol-tools-7dd63523939822203d938511472c84b8ff418aaf.zip |
Implement subscriptions based on ethereumjs-blockstream
Diffstat (limited to 'src/utils')
-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 | 80 |
3 files changed, 81 insertions, 41 deletions
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..ee39b6836 --- /dev/null +++ b/src/utils/filter_utils.ts @@ -0,0 +1,80 @@ +import * as _ from 'lodash'; +import * as Web3 from 'web3'; +import * as uuid from 'uuid/v4'; +import * as ethUtil from 'ethereumjs-util'; +import {ContractEvents, IndexedFilterValues, SubscriptionOpts} from '../types'; + +const TOPIC_LENGTH = 32; + +export const filterUtils = { + generateUUID(): string { + return uuid(); + }, + getFilter(keccak256: (data: string) => string, 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 = 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])) { + 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; + }, +}; |