From 504beeb2f321c6c35cfcc3edfff1669bdebc939b Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 4 Oct 2017 13:30:00 +0300 Subject: Add filtering by topic --- package.json | 2 +- src/contract_wrappers/contract_wrapper.ts | 26 +++++++++++++++++--- test/exchange_wrapper_test.ts | 40 +++++++++++++++++++++++++++---- test/token_wrapper_test.ts | 25 +++++++++++++++---- yarn.lock | 4 ++-- 5 files changed, 83 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index a86f06a54..a1382fb82 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "tslint-config-0xproject": "^0.0.2", "typedoc": "^0.8.0", "types-bn": "^0.0.1", - "types-ethereumjs-util": "^0.0.5", + "types-ethereumjs-util": "0xProject/types-ethereumjs-util", "typescript": "^2.4.1", "web3-provider-engine": "^13.0.1", "web3-typescript-typings": "^0.6.2", diff --git a/src/contract_wrappers/contract_wrapper.ts b/src/contract_wrappers/contract_wrapper.ts index 6f074a976..7732f2f50 100644 --- a/src/contract_wrappers/contract_wrapper.ts +++ b/src/contract_wrappers/contract_wrapper.ts @@ -1,5 +1,6 @@ import * as _ from 'lodash'; import * as Web3 from 'web3'; +import * as ethUtil from 'ethereumjs-util'; import {Web3Wrapper} from '../web3_wrapper'; import {AbiDecoder} from '../utils/abi_decoder'; import { @@ -13,6 +14,8 @@ import { } from '../types'; import {utils} from '../utils/utils'; +const TOPIC_LENGTH = 32; + export class ContractWrapper { protected _web3Wrapper: Web3Wrapper; private _abiDecoder?: AbiDecoder; @@ -23,11 +26,11 @@ export class ContractWrapper { protected async _getLogsAsync(address: string, eventName: ContractEvents, subscriptionOpts: SubscriptionOpts, indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi): Promise { - // TODO include indexFilterValues in topics - const eventAbi = _.find(abi, {name: eventName}) as Web3.EventAbi; + const eventAbi = _.filter(abi, {name: eventName})[0] as Web3.EventAbi; const eventSignature = this._getEventSignatureFromAbiByName(eventAbi, eventName); const topicForEventSignature = this._web3Wrapper.keccak256(eventSignature); - const topics = [topicForEventSignature]; + const topicsForIndexedArgs = this._getTopicsForIndexedArgs(eventAbi, indexFilterValues); + const topics = [topicForEventSignature, ...topicsForIndexedArgs]; const filter = { fromBlock: subscriptionOpts.fromBlock, toBlock: subscriptionOpts.toBlock, @@ -57,4 +60,21 @@ export class ContractWrapper { const signature = `${eventAbi.name}(${types.join(',')})`; return signature; } + private _getTopicsForIndexedArgs(abi: Web3.EventAbi, indexFilterValues: IndexedFilterValues): Array { + const topics: Array = []; + for (const eventInput of abi.inputs) { + if (eventInput.indexed) { + 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/test/exchange_wrapper_test.ts b/test/exchange_wrapper_test.ts index ab709a446..71c5713ad 100644 --- a/test/exchange_wrapper_test.ts +++ b/test/exchange_wrapper_test.ts @@ -779,10 +779,10 @@ describe('ExchangeWrapper', () => { const fillableAmount = new BigNumber(5); const shouldThrowOnInsufficientBalanceOrAllowance = true; const subscriptionOpts: SubscriptionOpts = { - fromBlock: 0, + fromBlock: 'earliest', toBlock: 'latest', }; - const indexFilterValues = {}; + let txHash: string; before(async () => { [, makerAddress, takerAddress] = userAddresses; const [makerToken, takerToken] = tokenUtils.getNonProtocolTokens(); @@ -793,10 +793,12 @@ describe('ExchangeWrapper', () => { const signedOrder = await fillScenarios.createFillableSignedOrderAsync( makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, ); - await zeroEx.exchange.fillOrderAsync( + txHash = await zeroEx.exchange.fillOrderAsync( signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, ); + await zeroEx.awaitTransactionMinedAsync(txHash); const eventName = ExchangeEvents.LogFill; + const indexFilterValues = {}; const logs = await zeroEx.exchange.getLogsAsync(eventName, subscriptionOpts, indexFilterValues); expect(logs).to.have.length(1); expect(logs[0].event).to.be.equal(eventName); @@ -805,12 +807,42 @@ describe('ExchangeWrapper', () => { const signedOrder = await fillScenarios.createFillableSignedOrderAsync( makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, ); - await zeroEx.exchange.fillOrderAsync( + txHash = await zeroEx.exchange.fillOrderAsync( signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, ); + await zeroEx.awaitTransactionMinedAsync(txHash); const differentEventName = ExchangeEvents.LogCancel; + const indexFilterValues = {}; const logs = await zeroEx.exchange.getLogsAsync(differentEventName, subscriptionOpts, indexFilterValues); expect(logs).to.have.length(0); }); + it('should only get the logs with the correct indexed fields', async () => { + const signedOrder = await fillScenarios.createFillableSignedOrderAsync( + makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + ); + txHash = await zeroEx.exchange.fillOrderAsync( + signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, + ); + await zeroEx.awaitTransactionMinedAsync(txHash); + + const differentMakerAddress = userAddresses[2]; + const anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync( + makerTokenAddress, takerTokenAddress, differentMakerAddress, takerAddress, fillableAmount, + ); + txHash = await zeroEx.exchange.fillOrderAsync( + anotherSignedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, + ); + await zeroEx.awaitTransactionMinedAsync(txHash); + + const eventName = ExchangeEvents.LogFill; + const indexFilterValues = { + maker: differentMakerAddress, + }; + const logs = await zeroEx.exchange.getLogsAsync( + eventName, subscriptionOpts, indexFilterValues, + ); + expect(logs).to.have.length(1); + expect(logs[0].args.maker).to.be.equal(differentMakerAddress); + }); }); }); diff --git a/test/token_wrapper_test.ts b/test/token_wrapper_test.ts index 7cd33057b..da020f714 100644 --- a/test/token_wrapper_test.ts +++ b/test/token_wrapper_test.ts @@ -440,19 +440,20 @@ describe('TokenWrapper', () => { let tokenAddress: string; let tokenTransferProxyAddress: string; const subscriptionOpts: SubscriptionOpts = { - fromBlock: 0, + fromBlock: 'earliest', toBlock: 'latest', }; - const indexFilterValues = {}; + let txHash: string; before(async () => { const token = tokens[0]; tokenAddress = token.address; tokenTransferProxyAddress = await zeroEx.proxy.getContractAddressAsync(); }); it('should get logs with decoded args emitted by Approval', async () => { - const txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase); + txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase); await zeroEx.awaitTransactionMinedAsync(txHash); const eventName = TokenEvents.Approval; + const indexFilterValues = {}; const logs = await zeroEx.token.getLogsAsync( tokenAddress, eventName, subscriptionOpts, indexFilterValues, ); @@ -463,13 +464,29 @@ describe('TokenWrapper', () => { expect(logs[0].args._value).to.be.bignumber.equal(zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS); }); it('should only get the logs with the correct event name', async () => { - const txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase); + txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase); await zeroEx.awaitTransactionMinedAsync(txHash); const differentEventName = TokenEvents.Transfer; + const indexFilterValues = {}; const logs = await zeroEx.token.getLogsAsync( tokenAddress, differentEventName, subscriptionOpts, indexFilterValues, ); expect(logs).to.have.length(0); }); + it('should only get the logs with the correct indexed fields', async () => { + txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase); + await zeroEx.awaitTransactionMinedAsync(txHash); + txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(tokenAddress, addressWithoutFunds); + await zeroEx.awaitTransactionMinedAsync(txHash); + const eventName = TokenEvents.Approval; + const indexFilterValues = { + _owner: coinbase, + }; + const logs = await zeroEx.token.getLogsAsync( + tokenAddress, eventName, subscriptionOpts, indexFilterValues, + ); + expect(logs).to.have.length(1); + expect(logs[0].args._owner).to.be.equal(coinbase); + }); }); }); diff --git a/yarn.lock b/yarn.lock index bb4bb48d4..2d3fbb2fc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4762,9 +4762,9 @@ types-bn@^0.0.1: dependencies: bn.js "4.11.7" -types-ethereumjs-util@^0.0.5: +types-ethereumjs-util@0xProject/types-ethereumjs-util: version "0.0.5" - resolved "https://registry.yarnpkg.com/types-ethereumjs-util/-/types-ethereumjs-util-0.0.5.tgz#a65060741c73d1ee5157b9ba2d502b4fe4a19d1c" + resolved "https://codeload.github.com/0xProject/types-ethereumjs-util/tar.gz/b9ae55d2c2711d89f63f7fc53a78579f2d4fbd74" dependencies: bn.js "^4.11.7" buffer "^5.0.6" -- cgit v1.2.3