From 5d21d10437703b6890c82105adec87d91646ddf4 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 3 Oct 2017 11:37:52 +0300 Subject: Update web3-typescript-typings --- package.json | 4 +- yarn.lock | 147 ++++++++++++++++------------------------------------------- 2 files changed, 42 insertions(+), 109 deletions(-) diff --git a/package.json b/package.json index 6a179f97e..a86f06a54 100644 --- a/package.json +++ b/package.json @@ -85,12 +85,12 @@ "types-ethereumjs-util": "^0.0.5", "typescript": "^2.4.1", "web3-provider-engine": "^13.0.1", - "web3-typescript-typings": "^0.6.0", + "web3-typescript-typings": "^0.6.2", "webpack": "^3.1.0" }, "dependencies": { "@types/bignumber.js": "^4.0.2", - "0x-json-schemas": "^0.6.0", + "0x-json-schemas": "^0.6.1", "bignumber.js": "^4.0.2", "compare-versions": "^3.0.1", "es6-promisify": "^5.0.0", diff --git a/yarn.lock b/yarn.lock index c3b7f66e4..bb4bb48d4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,9 +2,9 @@ # yarn lockfile v1 -"0x-json-schemas@^0.5.1": - version "0.5.1" - resolved "https://registry.yarnpkg.com/0x-json-schemas/-/0x-json-schemas-0.5.1.tgz#fce6c2962e44930884a838e01f5b605ddd217686" +"0x-json-schemas@^0.6.1": + version "0.6.1" + resolved "https://registry.yarnpkg.com/0x-json-schemas/-/0x-json-schemas-0.6.1.tgz#ff1b09542422dd9292dd7618a7c5c21d41c99cbf" dependencies: jsonschema "^1.2.0" @@ -1000,10 +1000,6 @@ camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" -caseless@~0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" - caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" @@ -1046,7 +1042,7 @@ chai@^4.0.1: pathval "^1.0.0" type-detect "^4.0.0" -chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: +chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: @@ -1222,15 +1218,15 @@ core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" -coveralls@^2.13.1: - version "2.13.1" - resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-2.13.1.tgz#d70bb9acc1835ec4f063ff9dac5423c17b11f178" +coveralls@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-3.0.0.tgz#22ef730330538080d29b8c151dc9146afde88a99" dependencies: - js-yaml "3.6.1" - lcov-parse "0.0.10" - log-driver "1.2.5" - minimist "1.2.0" - request "2.79.0" + js-yaml "^3.6.1" + lcov-parse "^0.0.10" + log-driver "^1.2.5" + minimist "^1.2.0" + request "^2.79.0" create-ecdh@^4.0.0: version "4.0.0" @@ -1608,9 +1604,9 @@ escope@^3.6.0: esrecurse "^4.1.0" estraverse "^4.1.1" -esprima@^2.6.0: - version "2.7.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" +esprima@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" esrecurse@^4.1.0: version "4.2.0" @@ -2050,16 +2046,6 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -generate-function@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" - -generate-object-property@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" - dependencies: - is-property "^1.0.0" - get-caller-file@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" @@ -2185,15 +2171,6 @@ har-schema@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" -har-validator@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" - dependencies: - chalk "^1.1.1" - commander "^2.9.0" - is-my-json-valid "^2.12.4" - pinkie-promise "^2.0.0" - har-validator@~4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" @@ -2494,15 +2471,6 @@ is-hex-prefixed@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" -is-my-json-valid@^2.12.4: - version "2.16.0" - resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz#f079dd9bfdae65ee2038aae8acbc86ab109e3693" - dependencies: - generate-function "^2.0.0" - generate-object-property "^1.1.0" - jsonpointer "^4.0.0" - xtend "^4.0.0" - is-number@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" @@ -2535,10 +2503,6 @@ is-primitive@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" -is-property@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" - is-regex@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" @@ -2653,12 +2617,12 @@ js-tokens@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" -js-yaml@3.6.1: - version "3.6.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.6.1.tgz#6e5fe67d8b205ce4d22fad05b7781e8dadcc4b30" +js-yaml@^3.6.1: + version "3.10.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" dependencies: argparse "^1.0.7" - esprima "^2.6.0" + esprima "^4.0.0" jsbn@~0.1.0: version "0.1.1" @@ -2728,10 +2692,6 @@ jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" -jsonpointer@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" - jsonschema@*, jsonschema@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.2.0.tgz#d6ebaf70798db7b3a20c544f6c9ef9319b077de2" @@ -2800,7 +2760,7 @@ lcid@^1.0.0: dependencies: invert-kv "^1.0.0" -lcov-parse@0.0.10: +lcov-parse@^0.0.10: version "0.0.10" resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-0.0.10.tgz#1b0b8ff9ac9c7889250582b70b71315d9da6d9a3" @@ -2915,6 +2875,10 @@ lodash.create@3.1.1: lodash._basecreate "^3.0.0" lodash._isiterateecall "^3.0.0" +lodash.get@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + lodash.isarguments@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" @@ -2939,7 +2903,7 @@ lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.4, lodash@^4.2.0: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" -log-driver@1.2.5: +log-driver@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.5.tgz#7ae4ec257302fd790d557cb10c97100d857b0056" @@ -3162,7 +3126,7 @@ minimist@0.0.8, minimist@~0.0.1: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" -minimist@1.2.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@~1.2.0: +minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" @@ -3236,14 +3200,15 @@ native-promise-only@^0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/native-promise-only/-/native-promise-only-0.8.1.tgz#20a318c30cb45f71fe7adfbf7b21c99c1472ef11" -nise@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/nise/-/nise-1.0.1.tgz#0da92b10a854e97c0f496f6c2845a301280b3eef" +nise@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/nise/-/nise-1.1.0.tgz#37e41b9bf0041ccb83d1bf03e79440bbc0db10ad" dependencies: formatio "^1.2.0" just-extend "^1.1.22" lolex "^1.6.0" path-to-regexp "^1.7.0" + text-encoding "^0.6.4" node-abi@^2.0.0: version "2.0.3" @@ -3781,10 +3746,6 @@ punycode@^1.2.4, punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" -qs@~6.3.0: - version "6.3.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c" - qs@~6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" @@ -3997,32 +3958,7 @@ request-promise-native@^1.0.4: stealthy-require "^1.1.0" tough-cookie ">=2.3.0" -request@2.79.0: - version "2.79.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" - dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - caseless "~0.11.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~2.1.1" - har-validator "~2.0.6" - hawk "~3.1.3" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - oauth-sign "~0.8.1" - qs "~6.3.0" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "~0.4.1" - uuid "^3.0.0" - -request@^2.54.0, request@^2.67.0, request@^2.81.0: +request@^2.54.0, request@^2.67.0, request@^2.79.0, request@^2.81.0: version "2.81.0" resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" dependencies: @@ -4255,15 +4191,16 @@ single-line-log@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/single-line-log/-/single-line-log-0.4.1.tgz#87a55649f749d783ec0dcd804e8140d9873c7cee" -sinon@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/sinon/-/sinon-3.2.0.tgz#8848a66ab6e8b80b5532e3824f59f83ea2628c77" +sinon@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-4.0.0.tgz#a54a5f0237aa1dd2215e5e81c89b42b50c4fdb6b" dependencies: diff "^3.1.0" formatio "1.2.0" + lodash.get "^4.4.2" lolex "^2.1.2" native-promise-only "^0.8.1" - nise "^1.0.1" + nise "^1.1.0" path-to-regexp "^1.7.0" samsam "^1.1.3" text-encoding "0.6.4" @@ -4637,7 +4574,7 @@ test-exclude@^4.1.1: read-pkg-up "^1.0.1" require-main-filename "^1.0.1" -text-encoding@0.6.4: +text-encoding@0.6.4, text-encoding@^0.6.4: version "0.6.4" resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.6.4.tgz#e399a982257a276dae428bb92845cb71bdc26d19" @@ -4781,10 +4718,6 @@ tunnel-agent@^0.6.0: dependencies: safe-buffer "^5.0.1" -tunnel-agent@~0.4.1: - version "0.4.3" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" - tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" @@ -5005,9 +4938,9 @@ web3-provider-engine@^8.4.0: xhr "^2.2.0" xtend "^4.0.1" -web3-typescript-typings@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/web3-typescript-typings/-/web3-typescript-typings-0.6.0.tgz#ed8f01cfa3ef2c7ff2f1b0cafe7c682d0c6dc333" +web3-typescript-typings@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/web3-typescript-typings/-/web3-typescript-typings-0.6.2.tgz#5dd9bf4dcd1d6dd6897c87d055d1f5cc8f98dfbd" dependencies: bignumber.js "^4.0.2" -- cgit v1.2.3 From 5410924810fa597b495b1ee065a68195d3725b7c Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 3 Oct 2017 11:38:16 +0300 Subject: Add type aliases for web3 types --- src/types.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/types.ts b/src/types.ts index 02230b0ab..d9059e7be 100644 --- a/src/types.ts +++ b/src/types.ts @@ -234,6 +234,8 @@ export enum ExchangeContractErrs { BatchOrdersMustHaveAtLeastOneItem = 'BATCH_ORDERS_MUST_HAVE_AT_LEAST_ONE_ITEM', } +export type RawLog = Web3.LogEntry; + export interface ContractEvent { logIndex: number; transactionIndex: number; @@ -460,3 +462,5 @@ export interface MethodOpts { export interface OrderTransactionOpts { shouldValidate: boolean; } + +export type FilterObject = Web3.FilterObject; -- cgit v1.2.3 From ea08fc8642018a348f130d829758601b6752f4a8 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 3 Oct 2017 11:38:47 +0300 Subject: Add getLogsAsync to web3_wrapper --- src/web3_wrapper.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/web3_wrapper.ts b/src/web3_wrapper.ts index 0bf80a6e4..653205988 100644 --- a/src/web3_wrapper.ts +++ b/src/web3_wrapper.ts @@ -9,10 +9,12 @@ export class Web3Wrapper { private web3: Web3; private defaults: Partial; private networkIdIfExists?: number; + private jsonRpcRequestId: number; constructor(provider: Web3.Provider, defaults: Partial) { this.web3 = new Web3(); this.web3.setProvider(provider); this.defaults = defaults; + this.jsonRpcRequestId = 0; } public setProvider(provider: Web3.Provider) { delete this.networkIdIfExists; @@ -100,6 +102,16 @@ export class Web3Wrapper { const addresses: string[] = await promisify(this.web3.eth.getAccounts)(); return addresses; } + public async getLogsAsync(filter: Web3.FilterObject): Promise { + const payload = { + jsonrpc: '2.0', + id: this.jsonRpcRequestId++, + method: 'eth_getLogs', + params: [filter], + }; + const logs = await this.sendRawPayloadAsync(payload); + return logs; + } private getContractInstance(abi: Web3.ContractAbi, address: string): A { const web3ContractInstance = this.web3.eth.contract(abi).at(address); const contractInstance = new Contract(web3ContractInstance, this.defaults) as any as A; @@ -109,4 +121,10 @@ export class Web3Wrapper { const networkId = await promisify(this.web3.version.getNetwork)(); return networkId; } + private async sendRawPayloadAsync(payload: Web3.JSONRPCRequestPayload): Promise { + const sendAsync = this.web3.currentProvider.sendAsync.bind(this.web3.currentProvider); + const response = await promisify(sendAsync)(payload); + const result = response.result; + return result; + } } -- cgit v1.2.3 From 7b545aa0e0dfcdb923d64494614f303bc3b3036a Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 3 Oct 2017 11:39:11 +0300 Subject: Re-export new types --- src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/index.ts b/src/index.ts index 9730d3fef..8e81d83a7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -35,4 +35,6 @@ export { DecodedLogArgs, MethodOpts, OrderTransactionOpts, + FilterObject, + RawLog, } from './types'; -- cgit v1.2.3 From 835c17c9612b184208c72c15a3ca0c815057ccf3 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 3 Oct 2017 11:39:34 +0300 Subject: Add zeroEx.getLogsAsync --- src/0x.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/0x.ts b/src/0x.ts index e6fdf68e1..ae29b8d70 100644 --- a/src/0x.ts +++ b/src/0x.ts @@ -31,6 +31,8 @@ import { DecodedLogArgs, TransactionReceiptWithDecodedLogs, LogWithDecodedArgs, + FilterObject, + RawLog, } from './types'; import {zeroExConfigSchema} from './schemas/zero_ex_config_schema'; @@ -321,6 +323,15 @@ export class ZeroEx { }); return txReceiptPromise; } + /** + * Gets historical logs without creating a subscription + * @param filter Filter object + * @return Array of logs that match the filter + */ + public async getLogsAsync(filter: FilterObject): Promise { + const logs = await this._web3Wrapper.getLogsAsync(filter); + return logs; + } /* * HACK: `TokenWrapper` needs a token transfer proxy address. `TokenTransferProxy` address is fetched from * an `ExchangeWrapper`. `ExchangeWrapper` needs `TokenWrapper` to validate orders, creating a dependency cycle. -- cgit v1.2.3 From b859f4b8abfe839980213be3c495be0b974d197f Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 3 Oct 2017 11:39:46 +0300 Subject: Add tests for zeroEx.getLogsAsync --- test/0x.js_test.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/0x.js_test.ts b/test/0x.js_test.ts index cc6b91e99..df6efc4bf 100644 --- a/test/0x.js_test.ts +++ b/test/0x.js_test.ts @@ -256,4 +256,30 @@ describe('ZeroEx library', () => { .to.be.rejectedWith(ZeroExError.ContractDoesNotExist); }); }); + describe('#getLogs', () => { + const exchangeAuthorizationLog = { + logIndex: '0x00', + transactionIndex: '0x00', + transactionHash: '0x36db2d7f92cd000834f4f96fa75dafdbeea31e2b389f3f56fc9020cc5e699ab6', + blockHash: '0x1fc0ee4950e9a25072cf643a26a5fb94b214021bcf6fe635f9174f78d891d85a', + blockNumber: '0x14', + address: '0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c', + data: '0x0', + topics: [ + '0x94bb87f4c15c4587ff559a7584006fa01ddf9299359be6b512b94527aa961aca', + '0x000000000000000000000000b69e673309512a9d726f87304c6984054f87a93b', + '0x0000000000000000000000005409ed021d9299bf6814279a6a1411a7e866a631', + ], + type: 'mined', + }; + it('gets historical logs', async () => { + const filter = { + fromBlock: 0, + toBlock: 'latest', + }; + const logs = await zeroEx.getLogsAsync(filter); + expect(logs).to.have.length(1); + expect(logs[0]).to.be.deep.equal(exchangeAuthorizationLog); + }); + }); }); -- cgit v1.2.3 From 40e0706954fb464fc8c546341d067f9b8eddc45e Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 3 Oct 2017 11:43:22 +0300 Subject: Add changes to CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c1072f24..c1e5b8b8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # CHANGELOG +v0.20.0 - _October 3, 2017_ + * Add `zeroEx.getLogsAsync` (#178) + v0.19.0 - _September 29, 2017_ * Made order validation optional (#172) * Added Ropsten testnet support (#173) -- cgit v1.2.3 From 16af052a168f64b6ba12b336cce9d404d383ce84 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 3 Oct 2017 12:03:43 +0300 Subject: Don't text for an exact block hash --- test/0x.js_test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/0x.js_test.ts b/test/0x.js_test.ts index df6efc4bf..0a4eb9a42 100644 --- a/test/0x.js_test.ts +++ b/test/0x.js_test.ts @@ -261,7 +261,6 @@ describe('ZeroEx library', () => { logIndex: '0x00', transactionIndex: '0x00', transactionHash: '0x36db2d7f92cd000834f4f96fa75dafdbeea31e2b389f3f56fc9020cc5e699ab6', - blockHash: '0x1fc0ee4950e9a25072cf643a26a5fb94b214021bcf6fe635f9174f78d891d85a', blockNumber: '0x14', address: '0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c', data: '0x0', @@ -279,7 +278,7 @@ describe('ZeroEx library', () => { }; const logs = await zeroEx.getLogsAsync(filter); expect(logs).to.have.length(1); - expect(logs[0]).to.be.deep.equal(exchangeAuthorizationLog); + expect(logs[0]).to.be.deep.include(exchangeAuthorizationLog); }); }); }); -- cgit v1.2.3 From a9681072ee4b45bda23b754fa46175b68c09b8b9 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 3 Oct 2017 12:20:33 +0300 Subject: Factor out tryToDecodeLogOrNoOp --- src/0x.ts | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/0x.ts b/src/0x.ts index ae29b8d70..275689f30 100644 --- a/src/0x.ts +++ b/src/0x.ts @@ -302,17 +302,7 @@ export class ZeroEx { const transactionReceipt = await this._web3Wrapper.getTransactionReceiptAsync(txHash); if (!_.isNull(transactionReceipt)) { intervalUtils.clearAsyncExcludingInterval(intervalId); - const logsWithDecodedArgs = _.map(transactionReceipt.logs, (log: Web3.LogEntry) => { - const decodedLog = this._abiDecoder.decodeLog(log); - if (_.isUndefined(decodedLog)) { - return log; - } - const logWithDecodedArgs: LogWithDecodedArgs = { - ...log, - ...decodedLog, - }; - return logWithDecodedArgs; - }); + const logsWithDecodedArgs = _.map(transactionReceipt.logs, this.tryToDecodeLogOrNoOp.bind(this)); const transactionReceiptWithDecodedLogArgs: TransactionReceiptWithDecodedLogs = { ...transactionReceipt, logs: logsWithDecodedArgs, @@ -332,6 +322,17 @@ export class ZeroEx { const logs = await this._web3Wrapper.getLogsAsync(filter); return logs; } + private tryToDecodeLogOrNoOp(log: Web3.LogEntry): LogWithDecodedArgs|Web3.LogEntry { + const decodedLog = this._abiDecoder.decodeLog(log); + if (_.isUndefined(decodedLog)) { + return log; + } + const logWithDecodedArgs: LogWithDecodedArgs = { + ...log, + ...decodedLog, + }; + return logWithDecodedArgs; + } /* * HACK: `TokenWrapper` needs a token transfer proxy address. `TokenTransferProxy` address is fetched from * an `ExchangeWrapper`. `ExchangeWrapper` needs `TokenWrapper` to validate orders, creating a dependency cycle. -- cgit v1.2.3 From 6bbdc98ba29633828f0533c8bb40a200cf142436 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 3 Oct 2017 12:31:46 +0300 Subject: Move log decoding to AbiDecoder --- src/0x.ts | 23 ++--------------- src/utils/abi_decoder.ts | 67 +++++++++++++++++++++++++----------------------- 2 files changed, 37 insertions(+), 53 deletions(-) diff --git a/src/0x.ts b/src/0x.ts index 275689f30..d89c07aa6 100644 --- a/src/0x.ts +++ b/src/0x.ts @@ -302,7 +302,8 @@ export class ZeroEx { const transactionReceipt = await this._web3Wrapper.getTransactionReceiptAsync(txHash); if (!_.isNull(transactionReceipt)) { intervalUtils.clearAsyncExcludingInterval(intervalId); - const logsWithDecodedArgs = _.map(transactionReceipt.logs, this.tryToDecodeLogOrNoOp.bind(this)); + const tryToDecodeLogOrNoOp = this._abiDecoder.tryToDecodeLogOrNoOp.bind(this._abiDecoder); + const logsWithDecodedArgs = _.map(transactionReceipt.logs, tryToDecodeLogOrNoOp); const transactionReceiptWithDecodedLogArgs: TransactionReceiptWithDecodedLogs = { ...transactionReceipt, logs: logsWithDecodedArgs, @@ -313,26 +314,6 @@ export class ZeroEx { }); return txReceiptPromise; } - /** - * Gets historical logs without creating a subscription - * @param filter Filter object - * @return Array of logs that match the filter - */ - public async getLogsAsync(filter: FilterObject): Promise { - const logs = await this._web3Wrapper.getLogsAsync(filter); - return logs; - } - private tryToDecodeLogOrNoOp(log: Web3.LogEntry): LogWithDecodedArgs|Web3.LogEntry { - const decodedLog = this._abiDecoder.decodeLog(log); - if (_.isUndefined(decodedLog)) { - return log; - } - const logWithDecodedArgs: LogWithDecodedArgs = { - ...log, - ...decodedLog, - }; - return logWithDecodedArgs; - } /* * HACK: `TokenWrapper` needs a token transfer proxy address. `TokenTransferProxy` address is fetched from * an `ExchangeWrapper`. `ExchangeWrapper` needs `TokenWrapper` to validate orders, creating a dependency cycle. diff --git a/src/utils/abi_decoder.ts b/src/utils/abi_decoder.ts index 61c8eecd4..88053aade 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} from '../types'; +import {AbiType, DecodedLogArgs, DecodedArgs, LogWithDecodedArgs} from '../types'; import * as SolidityCoder from 'web3/lib/solidity/coder'; export class AbiDecoder { @@ -10,40 +10,43 @@ export class AbiDecoder { constructor(abiArrays: Web3.AbiDefinition[][]) { _.map(abiArrays, this.addABI.bind(this)); } - public decodeLog(logItem: Web3.LogEntry): DecodedArgs|undefined { - const methodId = logItem.topics[0]; + public tryToDecodeLogOrNoOp(log: Web3.LogEntry): LogWithDecodedArgs|Web3.LogEntry { + const methodId = log.topics[0]; const event = this.methodIds[methodId]; - if (!_.isUndefined(event)) { - const logData = logItem.data; - const decodedParams: DecodedLogArgs = {}; - let dataIndex = 0; - let topicsIndex = 1; + if (_.isUndefined(event)) { + return log; + } + const logData = log.data; + const decodedParams: DecodedLogArgs = {}; + let dataIndex = 0; + let topicsIndex = 1; - const nonIndexedInputs = _.filter(event.inputs, input => !input.indexed); - const dataTypes = _.map(nonIndexedInputs, input => input.type); - const decodedData = SolidityCoder.decodeParams(dataTypes, logData.slice(2)); - _.map(event.inputs, (param: Web3.EventParameter) => { - let value; - if (param.indexed) { - value = logItem.topics[topicsIndex]; - topicsIndex++; - } else { - value = decodedData[dataIndex]; - dataIndex++; - } - if (param.type === 'address') { - value = this.padZeros(new BigNumber(value).toString(16)); - } else if (param.type === 'uint256' || param.type === 'uint8' || param.type === 'int' ) { - value = new BigNumber(value); - } - decodedParams[param.name] = value; - }); + const nonIndexedInputs = _.filter(event.inputs, input => !input.indexed); + const dataTypes = _.map(nonIndexedInputs, input => input.type); + const decodedData = SolidityCoder.decodeParams(dataTypes, logData.slice(2)); - return { - event: event.name, - args: decodedParams, - }; - } + _.map(event.inputs, (param: Web3.EventParameter) => { + let value; + if (param.indexed) { + value = log.topics[topicsIndex]; + topicsIndex++; + } else { + value = decodedData[dataIndex]; + dataIndex++; + } + if (param.type === 'address') { + value = this.padZeros(new BigNumber(value).toString(16)); + } else if (param.type === 'uint256' || param.type === 'uint8' || param.type === 'int' ) { + value = new BigNumber(value); + } + decodedParams[param.name] = value; + }); + + return { + ...log, + event: event.name, + args: decodedParams, + }; } private addABI(abiArray: Web3.AbiDefinition[]): void { _.map(abiArray, (abi: Web3.AbiDefinition) => { -- cgit v1.2.3 From 671bc7c91731828a4ee484994dacf7d3beb800e3 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 3 Oct 2017 15:49:37 +0300 Subject: Add NO_ABI_DECODER and ContractEvents --- src/types.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/types.ts b/src/types.ts index d9059e7be..0567b5e6a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -15,6 +15,7 @@ export enum ZeroExError { InvalidJump = 'INVALID_JUMP', OutOfGas = 'OUT_OF_GAS', NoNetworkId = 'NO_NETWORK_ID', + NoAbiDecoder = 'NO_ABI_DECODER', } /** @@ -340,6 +341,8 @@ export enum TokenEvents { Approval = 'Approval', } +export type ContractEvents = TokenEvents|ExchangeEvents; + export interface IndexedFilterValues { [index: string]: ContractEventArg; } -- cgit v1.2.3 From 44abf283ec80cbb33f0b6aad12cd1a7dc657debd Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 3 Oct 2017 15:50:25 +0300 Subject: Add keccak256 on web3_wrapper --- src/web3_wrapper.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/web3_wrapper.ts b/src/web3_wrapper.ts index 653205988..7576f3d40 100644 --- a/src/web3_wrapper.ts +++ b/src/web3_wrapper.ts @@ -112,6 +112,10 @@ export class Web3Wrapper { const logs = await this.sendRawPayloadAsync(payload); return logs; } + public keccak256(data: string): string { + const hash = this.web3.sha3(data); + return hash; + } private getContractInstance(abi: Web3.ContractAbi, address: string): A { const web3ContractInstance = this.web3.eth.contract(abi).at(address); const contractInstance = new Contract(web3ContractInstance, this.defaults) as any as A; -- cgit v1.2.3 From db08896274699aaf967751927dcacd0c21e3aaaf Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 3 Oct 2017 15:51:09 +0300 Subject: Remove old tests --- src/0x.ts | 1 + test/0x.js_test.ts | 25 ------------------------- 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/src/0x.ts b/src/0x.ts index d89c07aa6..c187fc5c2 100644 --- a/src/0x.ts +++ b/src/0x.ts @@ -202,6 +202,7 @@ export class ZeroEx { this._web3Wrapper = new Web3Wrapper(provider, defaults); this.token = new TokenWrapper( this._web3Wrapper, + this._abiDecoder, this._getTokenTransferProxyAddressAsync.bind(this), ); const exchageContractAddressIfExists = _.isUndefined(config) ? undefined : config.exchangeContractAddress; diff --git a/test/0x.js_test.ts b/test/0x.js_test.ts index 0a4eb9a42..cc6b91e99 100644 --- a/test/0x.js_test.ts +++ b/test/0x.js_test.ts @@ -256,29 +256,4 @@ describe('ZeroEx library', () => { .to.be.rejectedWith(ZeroExError.ContractDoesNotExist); }); }); - describe('#getLogs', () => { - const exchangeAuthorizationLog = { - logIndex: '0x00', - transactionIndex: '0x00', - transactionHash: '0x36db2d7f92cd000834f4f96fa75dafdbeea31e2b389f3f56fc9020cc5e699ab6', - blockNumber: '0x14', - address: '0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c', - data: '0x0', - topics: [ - '0x94bb87f4c15c4587ff559a7584006fa01ddf9299359be6b512b94527aa961aca', - '0x000000000000000000000000b69e673309512a9d726f87304c6984054f87a93b', - '0x0000000000000000000000005409ed021d9299bf6814279a6a1411a7e866a631', - ], - type: 'mined', - }; - it('gets historical logs', async () => { - const filter = { - fromBlock: 0, - toBlock: 'latest', - }; - const logs = await zeroEx.getLogsAsync(filter); - expect(logs).to.have.length(1); - expect(logs[0]).to.be.deep.include(exchangeAuthorizationLog); - }); - }); }); -- cgit v1.2.3 From efa85f844bcf59aa63d940a89d5899462239878a Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 3 Oct 2017 15:51:52 +0300 Subject: Add tryToDecodeLogOrNoOp and _getEventSignatureFromAbiByName on contract_wrapper --- src/contract_wrappers/contract_wrapper.ts | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/contract_wrappers/contract_wrapper.ts b/src/contract_wrappers/contract_wrapper.ts index 2a55b53d9..bc65f692d 100644 --- a/src/contract_wrappers/contract_wrapper.ts +++ b/src/contract_wrappers/contract_wrapper.ts @@ -1,13 +1,23 @@ import * as _ from 'lodash'; import * as Web3 from 'web3'; import {Web3Wrapper} from '../web3_wrapper'; -import {ZeroExError, Artifact} from '../types'; +import {AbiDecoder} from '../utils/abi_decoder'; +import {ZeroExError, Artifact, LogWithDecodedArgs, RawLog, ContractEvents} from '../types'; import {utils} from '../utils/utils'; export class ContractWrapper { protected _web3Wrapper: Web3Wrapper; - constructor(web3Wrapper: Web3Wrapper) { + private _abiDecoder?: AbiDecoder; + constructor(web3Wrapper: Web3Wrapper, abiDecoder?: AbiDecoder) { this._web3Wrapper = web3Wrapper; + this._abiDecoder = abiDecoder; + } + protected tryToDecodeLogOrNoOp(log: Web3.LogEntry): LogWithDecodedArgs|RawLog { + if (_.isUndefined(this._abiDecoder)) { + throw new Error(ZeroExError.NoAbiDecoder); + } + const logWithDecodedArgs = this._abiDecoder.tryToDecodeLogOrNoOp(log); + return logWithDecodedArgs; } protected async _instantiateContractIfExistsAsync(artifact: Artifact, addressIfExists?: string, @@ -16,4 +26,10 @@ export class ContractWrapper { await this._web3Wrapper.getContractInstanceFromArtifactAsync(artifact, addressIfExists); return contractInstance; } + protected _getEventSignatureFromAbiByName(abi: Web3.ContractAbi, eventName: ContractEvents): string { + const eventAbi = _.filter(abi, {name: eventName})[0] as Web3.EventAbi; + const types = _.map(eventAbi.inputs, 'type'); + const signature = `${eventAbi.name}(${types.join(',')})`; + return signature; + } } -- cgit v1.2.3 From 87374d7f46b6365078d20e8e0660520080facebe Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 3 Oct 2017 15:52:28 +0300 Subject: Refactor abi decoder --- src/utils/abi_decoder.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/abi_decoder.ts b/src/utils/abi_decoder.ts index 88053aade..2b420bd1f 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} from '../types'; +import {AbiType, DecodedLogArgs, DecodedArgs, LogWithDecodedArgs, RawLog} from '../types'; import * as SolidityCoder from 'web3/lib/solidity/coder'; export class AbiDecoder { @@ -10,7 +10,7 @@ export class AbiDecoder { constructor(abiArrays: Web3.AbiDefinition[][]) { _.map(abiArrays, this.addABI.bind(this)); } - public tryToDecodeLogOrNoOp(log: Web3.LogEntry): LogWithDecodedArgs|Web3.LogEntry { + public tryToDecodeLogOrNoOp(log: Web3.LogEntry): LogWithDecodedArgs|RawLog { const methodId = log.topics[0]; const event = this.methodIds[methodId]; if (_.isUndefined(event)) { -- cgit v1.2.3 From 0a12fa7f4e83562d48e143c30cb59645aa6b9b7a Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 3 Oct 2017 15:53:23 +0300 Subject: Implement getLogsAsync on token contract --- src/contract_wrappers/contract_wrapper.ts | 2 +- src/contract_wrappers/token_wrapper.ts | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/contract_wrappers/contract_wrapper.ts b/src/contract_wrappers/contract_wrapper.ts index bc65f692d..0c8864ee1 100644 --- a/src/contract_wrappers/contract_wrapper.ts +++ b/src/contract_wrappers/contract_wrapper.ts @@ -12,7 +12,7 @@ export class ContractWrapper { this._web3Wrapper = web3Wrapper; this._abiDecoder = abiDecoder; } - protected tryToDecodeLogOrNoOp(log: Web3.LogEntry): LogWithDecodedArgs|RawLog { + protected _tryToDecodeLogOrNoOp(log: Web3.LogEntry): LogWithDecodedArgs|RawLog { if (_.isUndefined(this._abiDecoder)) { throw new Error(ZeroExError.NoAbiDecoder); } diff --git a/src/contract_wrappers/token_wrapper.ts b/src/contract_wrappers/token_wrapper.ts index f7f0a0ce3..04c03edbd 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; - constructor(web3Wrapper: Web3Wrapper, tokenTransferProxyContractAddressFetcher: () => Promise) { - super(web3Wrapper); + constructor(web3Wrapper: Web3Wrapper, abiDecoder: AbiDecoder, + tokenTransferProxyContractAddressFetcher: () => Promise) { + super(web3Wrapper, abiDecoder); this._tokenContractsByAddress = {}; this._tokenLogEventEmitters = []; this._tokenTransferProxyContractAddressFetcher = tokenTransferProxyContractAddressFetcher; @@ -276,6 +280,21 @@ export class TokenWrapper extends ContractWrapper { this._tokenLogEventEmitters.push(eventEmitter); return eventEmitter; } + public async getLogsAsync(tokenAddress: string, eventName: TokenEvents, + subscriptionOpts: SubscriptionOpts, + indexFilterValues: IndexedFilterValues): Promise> { + // TODO include indexFilterValues in topics + const eventSignature = this._getEventSignatureFromAbiByName(artifacts.TokenArtifact.abi, eventName); + const filter = { + fromBlock: subscriptionOpts.fromBlock, + toBlock: subscriptionOpts.toBlock, + address: tokenAddress, + topics: [this._web3Wrapper.keccak256(eventSignature)], + }; + const logs = await this._web3Wrapper.getLogsAsync(filter); + const logsWithDecodedArguments = _.map(logs, this._tryToDecodeLogOrNoOp.bind(this)); + return logsWithDecodedArguments; + } /** * Stops watching for all token events */ -- cgit v1.2.3 From 087645e59fb78a1ce20bbbcabe12317f11324e93 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 3 Oct 2017 15:53:37 +0300 Subject: Add tests for zeroEx.token.getLogsAsync --- test/token_wrapper_test.ts | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/test/token_wrapper_test.ts b/test/token_wrapper_test.ts index 68dca0769..aacd9de40 100644 --- a/test/token_wrapper_test.ts +++ b/test/token_wrapper_test.ts @@ -14,6 +14,7 @@ import { ContractEvent, TransferContractEventArgs, ApprovalContractEventArgs, + LogWithDecodedArgs, } from '../src'; import {BlockchainLifecycle} from './utils/blockchain_lifecycle'; import {TokenUtils} from './utils/token_utils'; @@ -435,4 +436,40 @@ describe('TokenWrapper', () => { })().catch(done); }); }); + describe('#getLogsAsync', () => { + let tokenAddress: string; + let tokenTransferProxyAddress: string; + const subscriptionOpts: SubscriptionOpts = { + fromBlock: 0, + toBlock: 'latest', + }; + const indexFilterValues = {}; + 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); + await zeroEx.awaitTransactionMinedAsync(txHash); + const eventName = TokenEvents.Approval; + const logs = await zeroEx.token.getLogsAsync( + tokenAddress, eventName, subscriptionOpts, indexFilterValues, + ) as LogWithDecodedArgs[]; + expect(logs).to.have.length(1); + expect(logs[0].event).to.be.equal(eventName); + expect(logs[0].args._owner).to.be.equal(coinbase); + expect(logs[0].args._spender).to.be.equal(tokenTransferProxyAddress); + 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); + await zeroEx.awaitTransactionMinedAsync(txHash); + const differentEventName = TokenEvents.Transfer; + const logs = await zeroEx.token.getLogsAsync( + tokenAddress, differentEventName, subscriptionOpts, indexFilterValues, + ) as LogWithDecodedArgs[]; + expect(logs).to.have.length(0); + }); + }); }); -- cgit v1.2.3 From e6c138be5ab56856a454f7f04b6e1e54f1d41f18 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 3 Oct 2017 16:37:09 +0300 Subject: Add _getLogsAsync on contract_wrapper --- src/contract_wrappers/contract_wrapper.ts | 25 ++++++++++++++++++++++++- src/contract_wrappers/token_wrapper.ts | 18 +++++------------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/contract_wrappers/contract_wrapper.ts b/src/contract_wrappers/contract_wrapper.ts index 0c8864ee1..6b2517fc9 100644 --- a/src/contract_wrappers/contract_wrapper.ts +++ b/src/contract_wrappers/contract_wrapper.ts @@ -2,7 +2,15 @@ import * as _ from 'lodash'; import * as Web3 from 'web3'; import {Web3Wrapper} from '../web3_wrapper'; import {AbiDecoder} from '../utils/abi_decoder'; -import {ZeroExError, Artifact, LogWithDecodedArgs, RawLog, ContractEvents} from '../types'; +import { + ZeroExError, + Artifact, + LogWithDecodedArgs, + RawLog, + ContractEvents, + SubscriptionOpts, + IndexedFilterValues, +} from '../types'; import {utils} from '../utils/utils'; export class ContractWrapper { @@ -12,6 +20,21 @@ export class ContractWrapper { this._web3Wrapper = web3Wrapper; this._abiDecoder = abiDecoder; } + protected async _getLogsAsync(address: string, eventName: ContractEvents, subscriptionOpts: SubscriptionOpts, + indexFilterValues: IndexedFilterValues, + abi: Web3.ContractAbi): Promise> { + // TODO include indexFilterValues in topics + const eventSignature = this._getEventSignatureFromAbiByName(abi, eventName); + const filter = { + fromBlock: subscriptionOpts.fromBlock, + toBlock: subscriptionOpts.toBlock, + address, + topics: [this._web3Wrapper.keccak256(eventSignature)], + }; + 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(ZeroExError.NoAbiDecoder); diff --git a/src/contract_wrappers/token_wrapper.ts b/src/contract_wrappers/token_wrapper.ts index 04c03edbd..b932686d4 100644 --- a/src/contract_wrappers/token_wrapper.ts +++ b/src/contract_wrappers/token_wrapper.ts @@ -280,20 +280,12 @@ export class TokenWrapper extends ContractWrapper { this._tokenLogEventEmitters.push(eventEmitter); return eventEmitter; } - public async getLogsAsync(tokenAddress: string, eventName: TokenEvents, - subscriptionOpts: SubscriptionOpts, + public async getLogsAsync(tokenAddress: string, eventName: TokenEvents, subscriptionOpts: SubscriptionOpts, indexFilterValues: IndexedFilterValues): Promise> { - // TODO include indexFilterValues in topics - const eventSignature = this._getEventSignatureFromAbiByName(artifacts.TokenArtifact.abi, eventName); - const filter = { - fromBlock: subscriptionOpts.fromBlock, - toBlock: subscriptionOpts.toBlock, - address: tokenAddress, - topics: [this._web3Wrapper.keccak256(eventSignature)], - }; - const logs = await this._web3Wrapper.getLogsAsync(filter); - const logsWithDecodedArguments = _.map(logs, this._tryToDecodeLogOrNoOp.bind(this)); - return logsWithDecodedArguments; + const logs = await this._getLogsAsync( + tokenAddress, eventName, subscriptionOpts, indexFilterValues, artifacts.TokenArtifact.abi, + ); + return logs; } /** * Stops watching for all token events -- cgit v1.2.3 From 837618c7a016b9b66d70f3c0e9682c97a9d4cf8a Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 3 Oct 2017 16:44:16 +0300 Subject: Implement zeroEx.exchange.getLogsAsync --- src/contract_wrappers/exchange_wrapper.ts | 17 +++++++++++++++++ src/contract_wrappers/token_wrapper.ts | 9 +++++++++ 2 files changed, 26 insertions(+) diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index d02a6e642..78c2f4173 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'; @@ -655,6 +656,22 @@ export class ExchangeWrapper extends ContractWrapper { this._exchangeLogEventEmitters.push(eventEmitter); 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> { + 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 */ diff --git a/src/contract_wrappers/token_wrapper.ts b/src/contract_wrappers/token_wrapper.ts index b932686d4..175671f74 100644 --- a/src/contract_wrappers/token_wrapper.ts +++ b/src/contract_wrappers/token_wrapper.ts @@ -280,6 +280,15 @@ export class TokenWrapper extends ContractWrapper { this._tokenLogEventEmitters.push(eventEmitter); return eventEmitter; } + /** + * Gets historical logs without creating a subscription + * @param tokenAddress An address of the token that emited 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> { const logs = await this._getLogsAsync( -- cgit v1.2.3 From 451ded4963aaaa40ff4d00bcb0d589b06b45ce24 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 3 Oct 2017 19:05:44 +0300 Subject: Add tests for zeroEx.exchange.getLogsAsync --- src/0x.ts | 6 ++++- src/contract_wrappers/contract_wrapper.ts | 2 +- src/contract_wrappers/exchange_wrapper.ts | 8 +++--- src/contract_wrappers/token_wrapper.ts | 2 +- test/exchange_wrapper_test.ts | 42 +++++++++++++++++++++++++++++++ test/token_wrapper_test.ts | 4 +-- 6 files changed, 56 insertions(+), 8 deletions(-) diff --git a/src/0x.ts b/src/0x.ts index c187fc5c2..c5e8e0066 100644 --- a/src/0x.ts +++ b/src/0x.ts @@ -206,7 +206,11 @@ export class ZeroEx { this._getTokenTransferProxyAddressAsync.bind(this), ); const exchageContractAddressIfExists = _.isUndefined(config) ? undefined : config.exchangeContractAddress; - this.exchange = new ExchangeWrapper(this._web3Wrapper, this.token, exchageContractAddressIfExists); + this.exchange = new ExchangeWrapper( + this._web3Wrapper, + this._abiDecoder, + this.token, + exchageContractAddressIfExists); this.proxy = new TokenTransferProxyWrapper( this._web3Wrapper, this._getTokenTransferProxyAddressAsync.bind(this), diff --git a/src/contract_wrappers/contract_wrapper.ts b/src/contract_wrappers/contract_wrapper.ts index 6b2517fc9..d6c7d915a 100644 --- a/src/contract_wrappers/contract_wrapper.ts +++ b/src/contract_wrappers/contract_wrapper.ts @@ -22,7 +22,7 @@ export class ContractWrapper { } protected async _getLogsAsync(address: string, eventName: ContractEvents, subscriptionOpts: SubscriptionOpts, indexFilterValues: IndexedFilterValues, - abi: Web3.ContractAbi): Promise> { + abi: Web3.ContractAbi): Promise { // TODO include indexFilterValues in topics const eventSignature = this._getEventSignatureFromAbiByName(abi, eventName); const filter = { diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index 78c2f4173..b3a35d5bf 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -40,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; @@ -80,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 = []; @@ -665,7 +667,7 @@ export class ExchangeWrapper extends ContractWrapper { * @return Array of logs that match the parameters */ public async getLogsAsync(eventName: ExchangeEvents, subscriptionOpts: SubscriptionOpts, - indexFilterValues: IndexedFilterValues): Promise> { + indexFilterValues: IndexedFilterValues): Promise { const exchangeContractAddress = await this.getContractAddressAsync(); const logs = await this._getLogsAsync( exchangeContractAddress, eventName, subscriptionOpts, indexFilterValues, artifacts.ExchangeArtifact.abi, diff --git a/src/contract_wrappers/token_wrapper.ts b/src/contract_wrappers/token_wrapper.ts index 175671f74..95f5491c9 100644 --- a/src/contract_wrappers/token_wrapper.ts +++ b/src/contract_wrappers/token_wrapper.ts @@ -290,7 +290,7 @@ export class TokenWrapper extends ContractWrapper { * @return Array of logs that match the parameters */ public async getLogsAsync(tokenAddress: string, eventName: TokenEvents, subscriptionOpts: SubscriptionOpts, - indexFilterValues: IndexedFilterValues): Promise> { + indexFilterValues: IndexedFilterValues): Promise { const logs = await this._getLogsAsync( tokenAddress, eventName, subscriptionOpts, indexFilterValues, artifacts.TokenArtifact.abi, ); diff --git a/test/exchange_wrapper_test.ts b/test/exchange_wrapper_test.ts index 45a2d3907..ab709a446 100644 --- a/test/exchange_wrapper_test.ts +++ b/test/exchange_wrapper_test.ts @@ -771,4 +771,46 @@ describe('ExchangeWrapper', () => { expect(zrxAddress).to.equal(zrxToken.address); }); }); + describe('#getLogsAsync', () => { + let makerTokenAddress: string; + let takerTokenAddress: string; + let makerAddress: string; + let takerAddress: string; + const fillableAmount = new BigNumber(5); + const shouldThrowOnInsufficientBalanceOrAllowance = true; + const subscriptionOpts: SubscriptionOpts = { + fromBlock: 0, + toBlock: 'latest', + }; + const indexFilterValues = {}; + before(async () => { + [, makerAddress, takerAddress] = userAddresses; + const [makerToken, takerToken] = tokenUtils.getNonProtocolTokens(); + makerTokenAddress = makerToken.address; + takerTokenAddress = takerToken.address; + }); + it('should get logs with decoded args emitted by LogFill', async () => { + const signedOrder = await fillScenarios.createFillableSignedOrderAsync( + makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + ); + await zeroEx.exchange.fillOrderAsync( + signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, + ); + const eventName = ExchangeEvents.LogFill; + const logs = await zeroEx.exchange.getLogsAsync(eventName, subscriptionOpts, indexFilterValues); + expect(logs).to.have.length(1); + expect(logs[0].event).to.be.equal(eventName); + }); + it('should only get the logs with the correct event name', async () => { + const signedOrder = await fillScenarios.createFillableSignedOrderAsync( + makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + ); + await zeroEx.exchange.fillOrderAsync( + signedOrder, fillableAmount, shouldThrowOnInsufficientBalanceOrAllowance, takerAddress, + ); + const differentEventName = ExchangeEvents.LogCancel; + const logs = await zeroEx.exchange.getLogsAsync(differentEventName, subscriptionOpts, indexFilterValues); + expect(logs).to.have.length(0); + }); + }); }); diff --git a/test/token_wrapper_test.ts b/test/token_wrapper_test.ts index aacd9de40..7cd33057b 100644 --- a/test/token_wrapper_test.ts +++ b/test/token_wrapper_test.ts @@ -455,7 +455,7 @@ describe('TokenWrapper', () => { const eventName = TokenEvents.Approval; const logs = await zeroEx.token.getLogsAsync( tokenAddress, eventName, subscriptionOpts, indexFilterValues, - ) as LogWithDecodedArgs[]; + ); expect(logs).to.have.length(1); expect(logs[0].event).to.be.equal(eventName); expect(logs[0].args._owner).to.be.equal(coinbase); @@ -468,7 +468,7 @@ describe('TokenWrapper', () => { const differentEventName = TokenEvents.Transfer; const logs = await zeroEx.token.getLogsAsync( tokenAddress, differentEventName, subscriptionOpts, indexFilterValues, - ) as LogWithDecodedArgs[]; + ); expect(logs).to.have.length(0); }); }); -- cgit v1.2.3 From 7c49224c7b9ce41cf0eb0026f2b5d73e8726b089 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 3 Oct 2017 19:14:03 +0300 Subject: Don't export RawLog --- src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 8e81d83a7..3359743e9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -36,5 +36,4 @@ export { MethodOpts, OrderTransactionOpts, FilterObject, - RawLog, } from './types'; -- cgit v1.2.3 From ad7ce6c91640c0cb475b6baa3118d0ba8d8f8a46 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 3 Oct 2017 19:14:34 +0300 Subject: Update CHANGELOG --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1e5b8b8d..b3ce29f82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ # CHANGELOG v0.20.0 - _October 3, 2017_ - * Add `zeroEx.getLogsAsync` (#178) + * Add `zeroEx.token.getLogsAsync` (#178) + * Add `zeroEx.exchange.getLogsAsync` (#178) v0.19.0 - _September 29, 2017_ * Made order validation optional (#172) -- cgit v1.2.3 From f26d49f077a9a8b606159f22c05aaf2601dc8f57 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 4 Oct 2017 11:47:48 +0300 Subject: Use Noop instead of NoOp --- src/0x.ts | 6 ++++-- src/utils/abi_decoder.ts | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/0x.ts b/src/0x.ts index c5e8e0066..ba68a6e1e 100644 --- a/src/0x.ts +++ b/src/0x.ts @@ -307,8 +307,10 @@ export class ZeroEx { const transactionReceipt = await this._web3Wrapper.getTransactionReceiptAsync(txHash); if (!_.isNull(transactionReceipt)) { intervalUtils.clearAsyncExcludingInterval(intervalId); - const tryToDecodeLogOrNoOp = this._abiDecoder.tryToDecodeLogOrNoOp.bind(this._abiDecoder); - const logsWithDecodedArgs = _.map(transactionReceipt.logs, tryToDecodeLogOrNoOp); + const logsWithDecodedArgs = _.map( + transactionReceipt.logs, + this._abiDecoder.tryToDecodeLogOrNoop.bind(this._abiDecoder), + ); const transactionReceiptWithDecodedLogArgs: TransactionReceiptWithDecodedLogs = { ...transactionReceipt, logs: logsWithDecodedArgs, diff --git a/src/utils/abi_decoder.ts b/src/utils/abi_decoder.ts index 2b420bd1f..75d78629c 100644 --- a/src/utils/abi_decoder.ts +++ b/src/utils/abi_decoder.ts @@ -10,7 +10,7 @@ export class AbiDecoder { constructor(abiArrays: Web3.AbiDefinition[][]) { _.map(abiArrays, this.addABI.bind(this)); } - public tryToDecodeLogOrNoOp(log: Web3.LogEntry): LogWithDecodedArgs|RawLog { + public tryToDecodeLogOrNoop(log: Web3.LogEntry): LogWithDecodedArgs|RawLog { const methodId = log.topics[0]; const event = this.methodIds[methodId]; if (_.isUndefined(event)) { -- cgit v1.2.3 From f65bfc1ab1425e4866b5b7b7ecf2a30e0eb018a7 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 4 Oct 2017 11:51:36 +0300 Subject: Extract topics to its variable --- src/contract_wrappers/contract_wrapper.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/contract_wrappers/contract_wrapper.ts b/src/contract_wrappers/contract_wrapper.ts index d6c7d915a..921b5a6c2 100644 --- a/src/contract_wrappers/contract_wrapper.ts +++ b/src/contract_wrappers/contract_wrapper.ts @@ -24,22 +24,25 @@ export class ContractWrapper { indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi): Promise { // TODO include indexFilterValues in topics - const eventSignature = this._getEventSignatureFromAbiByName(abi, eventName); + 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 filter = { fromBlock: subscriptionOpts.fromBlock, toBlock: subscriptionOpts.toBlock, address, - topics: [this._web3Wrapper.keccak256(eventSignature)], + topics, }; const logs = await this._web3Wrapper.getLogsAsync(filter); - const logsWithDecodedArguments = _.map(logs, this._tryToDecodeLogOrNoOp.bind(this)); + const logsWithDecodedArguments = _.map(logs, this._tryToDecodeLogOrNoop.bind(this)); return logsWithDecodedArguments; } - protected _tryToDecodeLogOrNoOp(log: Web3.LogEntry): LogWithDecodedArgs|RawLog { + protected _tryToDecodeLogOrNoop(log: Web3.LogEntry): LogWithDecodedArgs|RawLog { if (_.isUndefined(this._abiDecoder)) { throw new Error(ZeroExError.NoAbiDecoder); } - const logWithDecodedArgs = this._abiDecoder.tryToDecodeLogOrNoOp(log); + const logWithDecodedArgs = this._abiDecoder.tryToDecodeLogOrNoop(log); return logWithDecodedArgs; } protected async _instantiateContractIfExistsAsync(artifact: Artifact, @@ -49,8 +52,7 @@ export class ContractWrapper { await this._web3Wrapper.getContractInstanceFromArtifactAsync(artifact, addressIfExists); return contractInstance; } - protected _getEventSignatureFromAbiByName(abi: Web3.ContractAbi, eventName: ContractEvents): string { - const eventAbi = _.filter(abi, {name: eventName})[0] as Web3.EventAbi; + protected _getEventSignatureFromAbiByName(eventAbi: Web3.EventAbi, eventName: ContractEvents): string { const types = _.map(eventAbi.inputs, 'type'); const signature = `${eventAbi.name}(${types.join(',')})`; return signature; -- cgit v1.2.3 From d1e4f6efdd14dc3b7c73b1d95f360cedaf4df03b Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 4 Oct 2017 11:53:02 +0300 Subject: Move NoAbiDecoder to InternalZeroExErrors --- src/contract_wrappers/contract_wrapper.ts | 4 ++-- src/types.ts | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/contract_wrappers/contract_wrapper.ts b/src/contract_wrappers/contract_wrapper.ts index 921b5a6c2..cffd2f6f3 100644 --- a/src/contract_wrappers/contract_wrapper.ts +++ b/src/contract_wrappers/contract_wrapper.ts @@ -3,7 +3,7 @@ import * as Web3 from 'web3'; import {Web3Wrapper} from '../web3_wrapper'; import {AbiDecoder} from '../utils/abi_decoder'; import { - ZeroExError, + InternalZeroExError, Artifact, LogWithDecodedArgs, RawLog, @@ -40,7 +40,7 @@ export class ContractWrapper { } protected _tryToDecodeLogOrNoop(log: Web3.LogEntry): LogWithDecodedArgs|RawLog { if (_.isUndefined(this._abiDecoder)) { - throw new Error(ZeroExError.NoAbiDecoder); + throw new Error(InternalZeroExError.NoAbiDecoder); } const logWithDecodedArgs = this._abiDecoder.tryToDecodeLogOrNoop(log); return logWithDecodedArgs; diff --git a/src/types.ts b/src/types.ts index 0567b5e6a..a6a24ef8e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -15,6 +15,9 @@ export enum ZeroExError { InvalidJump = 'INVALID_JUMP', OutOfGas = 'OUT_OF_GAS', NoNetworkId = 'NO_NETWORK_ID', +} + +export enum InternalZeroExError { NoAbiDecoder = 'NO_ABI_DECODER', } -- cgit v1.2.3 From aa995ff9941c4f319985e23a14d0a87fc7b9ea1c Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 4 Oct 2017 11:53:44 +0300 Subject: Use _.find instead of _.filter --- src/contract_wrappers/contract_wrapper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/contract_wrappers/contract_wrapper.ts b/src/contract_wrappers/contract_wrapper.ts index cffd2f6f3..6f074a976 100644 --- a/src/contract_wrappers/contract_wrapper.ts +++ b/src/contract_wrappers/contract_wrapper.ts @@ -24,7 +24,7 @@ export class ContractWrapper { indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi): Promise { // TODO include indexFilterValues in topics - const eventAbi = _.filter(abi, {name: eventName})[0] as Web3.EventAbi; + const eventAbi = _.find(abi, {name: eventName}) as Web3.EventAbi; const eventSignature = this._getEventSignatureFromAbiByName(eventAbi, eventName); const topicForEventSignature = this._web3Wrapper.keccak256(eventSignature); const topics = [topicForEventSignature]; -- cgit v1.2.3 From 2b9418b7009a54c5943dd42b34db8f82ddf50e99 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 4 Oct 2017 11:54:34 +0300 Subject: Fix a typo --- src/contract_wrappers/token_wrapper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/contract_wrappers/token_wrapper.ts b/src/contract_wrappers/token_wrapper.ts index 95f5491c9..91af223e4 100644 --- a/src/contract_wrappers/token_wrapper.ts +++ b/src/contract_wrappers/token_wrapper.ts @@ -282,7 +282,7 @@ export class TokenWrapper extends ContractWrapper { } /** * Gets historical logs without creating a subscription - * @param tokenAddress An address of the token that emited the logs. + * @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 -- cgit v1.2.3 From a6f4f83b5b0440a3f63112514c6abe6be74df3f9 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 4 Oct 2017 11:55:29 +0300 Subject: Add a comment --- src/utils/abi_decoder.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/abi_decoder.ts b/src/utils/abi_decoder.ts index 75d78629c..b601dd2f4 100644 --- a/src/utils/abi_decoder.ts +++ b/src/utils/abi_decoder.ts @@ -10,6 +10,7 @@ export class AbiDecoder { constructor(abiArrays: Web3.AbiDefinition[][]) { _.map(abiArrays, this.addABI.bind(this)); } + // This method can only decode logs from the 0x smart contracts public tryToDecodeLogOrNoop(log: Web3.LogEntry): LogWithDecodedArgs|RawLog { const methodId = log.topics[0]; const event = this.methodIds[methodId]; -- cgit v1.2.3 From 499e60c4a3719ce0699f75f1993a5336d0074bc7 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 4 Oct 2017 12:48:45 +0300 Subject: Use 0x.length instead of 2 --- src/utils/abi_decoder.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/abi_decoder.ts b/src/utils/abi_decoder.ts index b601dd2f4..4646016f2 100644 --- a/src/utils/abi_decoder.ts +++ b/src/utils/abi_decoder.ts @@ -24,7 +24,7 @@ export class AbiDecoder { const nonIndexedInputs = _.filter(event.inputs, input => !input.indexed); const dataTypes = _.map(nonIndexedInputs, input => input.type); - const decodedData = SolidityCoder.decodeParams(dataTypes, logData.slice(2)); + const decodedData = SolidityCoder.decodeParams(dataTypes, logData.slice('0x'.length)); _.map(event.inputs, (param: Web3.EventParameter) => { let value; -- cgit v1.2.3 From 944f51d66c5afb92008ddd1bff9fe83ce51a5e10 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 4 Oct 2017 12:55:16 +0300 Subject: Use SolidityTypes --- src/types.ts | 2 ++ src/utils/abi_decoder.ts | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/types.ts b/src/types.ts index a6a24ef8e..92b873886 100644 --- a/src/types.ts +++ b/src/types.ts @@ -202,6 +202,8 @@ export interface TokenTransferProxyContract extends Web3.ContractInstance { export enum SolidityTypes { Address = 'address', Uint256 = 'uint256', + Uint8 = 'uint8', + Uint = 'uint', } export enum ExchangeContractErrCodes { diff --git a/src/utils/abi_decoder.ts b/src/utils/abi_decoder.ts index 4646016f2..e9ba3bc5a 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} from '../types'; +import {AbiType, DecodedLogArgs, DecodedArgs, LogWithDecodedArgs, RawLog, SolidityTypes} from '../types'; import * as SolidityCoder from 'web3/lib/solidity/coder'; export class AbiDecoder { @@ -35,9 +35,11 @@ export class AbiDecoder { value = decodedData[dataIndex]; dataIndex++; } - if (param.type === 'address') { + if (param.type === SolidityTypes.Address) { value = this.padZeros(new BigNumber(value).toString(16)); - } else if (param.type === 'uint256' || param.type === 'uint8' || param.type === 'int' ) { + } else if (param.type === SolidityTypes.Uint256 || + param.type === SolidityTypes.Uint8 || + param.type === SolidityTypes.Uint ) { value = new BigNumber(value); } decodedParams[param.name] = value; -- cgit v1.2.3 From 9af47eb063406753456f16bf3efb916666c76d7f Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 4 Oct 2017 12:59:46 +0300 Subject: Use a ternary and add a comment --- src/utils/abi_decoder.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/utils/abi_decoder.ts b/src/utils/abi_decoder.ts index e9ba3bc5a..542591251 100644 --- a/src/utils/abi_decoder.ts +++ b/src/utils/abi_decoder.ts @@ -27,14 +27,8 @@ export class AbiDecoder { const decodedData = SolidityCoder.decodeParams(dataTypes, logData.slice('0x'.length)); _.map(event.inputs, (param: Web3.EventParameter) => { - let value; - if (param.indexed) { - value = log.topics[topicsIndex]; - topicsIndex++; - } else { - value = decodedData[dataIndex]; - dataIndex++; - } + // Indexed parameters are stored in topics. Non-indexed ones in decodedData + let value = param.indexed ? log.topics[topicsIndex++] : decodedData[dataIndex++]; if (param.type === SolidityTypes.Address) { value = this.padZeros(new BigNumber(value).toString(16)); } else if (param.type === SolidityTypes.Uint256 || -- cgit v1.2.3 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 From 8fb5e8724310d034659be6d00d287bb73ced1eae Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 4 Oct 2017 14:22:17 +0300 Subject: Allign brackets --- src/0x.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/0x.ts b/src/0x.ts index ba68a6e1e..3180c52f6 100644 --- a/src/0x.ts +++ b/src/0x.ts @@ -210,7 +210,8 @@ export class ZeroEx { this._web3Wrapper, this._abiDecoder, this.token, - exchageContractAddressIfExists); + exchageContractAddressIfExists, + ); this.proxy = new TokenTransferProxyWrapper( this._web3Wrapper, this._getTokenTransferProxyAddressAsync.bind(this), -- cgit v1.2.3 From cc3871aca54a9c4dc0906e2b726c2c079787f142 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 4 Oct 2017 14:22:47 +0300 Subject: Use find --- src/contract_wrappers/contract_wrapper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/contract_wrappers/contract_wrapper.ts b/src/contract_wrappers/contract_wrapper.ts index 7732f2f50..4d08f04e6 100644 --- a/src/contract_wrappers/contract_wrapper.ts +++ b/src/contract_wrappers/contract_wrapper.ts @@ -26,7 +26,7 @@ export class ContractWrapper { protected async _getLogsAsync(address: string, eventName: ContractEvents, subscriptionOpts: SubscriptionOpts, indexFilterValues: IndexedFilterValues, abi: Web3.ContractAbi): Promise { - const eventAbi = _.filter(abi, {name: eventName})[0] as Web3.EventAbi; + 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); -- cgit v1.2.3 From 11c48ced00ef4c25aeffd47504685f0a3bf3e7e3 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 4 Oct 2017 14:23:42 +0300 Subject: Reduce nesting --- src/contract_wrappers/contract_wrapper.ts | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/contract_wrappers/contract_wrapper.ts b/src/contract_wrappers/contract_wrapper.ts index 4d08f04e6..743dfc9b2 100644 --- a/src/contract_wrappers/contract_wrapper.ts +++ b/src/contract_wrappers/contract_wrapper.ts @@ -63,16 +63,17 @@ export class ContractWrapper { 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); - } + 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; -- cgit v1.2.3 From e5bdf60460330a24597e018f3611e7bc939c1362 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 4 Oct 2017 14:25:15 +0300 Subject: Move ZRX_NOT_IN_TOKEN_REGISTRY to InternalZeroExError --- src/types.ts | 2 +- test/utils/token_utils.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/types.ts b/src/types.ts index 92b873886..35bb6af78 100644 --- a/src/types.ts +++ b/src/types.ts @@ -7,7 +7,6 @@ export enum ZeroExError { UserHasNoAssociatedAddress = 'USER_HAS_NO_ASSOCIATED_ADDRESSES', InvalidSignature = 'INVALID_SIGNATURE', ContractNotDeployedOnNetwork = 'CONTRACT_NOT_DEPLOYED_ON_NETWORK', - ZrxNotInTokenRegistry = 'ZRX_NOT_IN_TOKEN_REGISTRY', InsufficientAllowanceForTransfer = 'INSUFFICIENT_ALLOWANCE_FOR_TRANSFER', InsufficientBalanceForTransfer = 'INSUFFICIENT_BALANCE_FOR_TRANSFER', InsufficientEthBalanceForDeposit = 'INSUFFICIENT_ETH_BALANCE_FOR_DEPOSIT', @@ -19,6 +18,7 @@ export enum ZeroExError { export enum InternalZeroExError { NoAbiDecoder = 'NO_ABI_DECODER', + ZrxNotInTokenRegistry = 'ZRX_NOT_IN_TOKEN_REGISTRY', } /** diff --git a/test/utils/token_utils.ts b/test/utils/token_utils.ts index 60cf4527b..51cb9411c 100644 --- a/test/utils/token_utils.ts +++ b/test/utils/token_utils.ts @@ -1,5 +1,5 @@ import * as _ from 'lodash'; -import {Token, ZeroExError} from '../../src'; +import {Token, InternalZeroExError} from '../../src/types'; const PROTOCOL_TOKEN_SYMBOL = 'ZRX'; @@ -11,7 +11,7 @@ export class TokenUtils { public getProtocolTokenOrThrow(): Token { const zrxToken = _.find(this.tokens, {symbol: PROTOCOL_TOKEN_SYMBOL}); if (_.isUndefined(zrxToken)) { - throw new Error(ZeroExError.ZrxNotInTokenRegistry); + throw new Error(InternalZeroExError.ZrxNotInTokenRegistry); } return zrxToken; } -- cgit v1.2.3