From 995861de4d61ffae9e60ae3fc08b2775b2e81f7b Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sat, 31 Jan 2015 01:30:19 +0100 Subject: event options --- lib/contract.js | 4 ++++ lib/event.js | 11 +++++++---- lib/filter.js | 17 ++++++++++++----- lib/web3.js | 14 ++++++++++---- 4 files changed, 33 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/contract.js b/lib/contract.js index eff16cca4..6056581d4 100644 --- a/lib/contract.js +++ b/lib/contract.js @@ -131,7 +131,11 @@ var addEventsToContract = function (contract, desc, address) { var o = event.apply(null, params); return web3.eth.watch(o); }; + + // this property should be used by eth.filter to check if object is an event + impl._isEvent = true; + // TODO: we can remove address && topic properties, they are not used anymore since we introduced _isEvent impl.address = address; Object.defineProperty(impl, 'topic', { diff --git a/lib/event.js b/lib/event.js index ae2195381..ea5f5b71e 100644 --- a/lib/event.js +++ b/lib/event.js @@ -20,13 +20,16 @@ * @date 2014 */ +var abi = require('./abi'); + var implementationOfEvent = function (address, signature) { - return function (options) { + // valid options are 'earliest', 'latest', 'offset' and 'max', as defined for 'eth.watch' + return function (indexed, options) { var o = options || {}; - o.address = o.address || address; - o.topics = o.topics || []; - o.topics.push(signature); + o.address = address; + o.topic = []; + o.topic.push(signature); return o; }; }; diff --git a/lib/filter.js b/lib/filter.js index 39309fb27..d97276f78 100644 --- a/lib/filter.js +++ b/lib/filter.js @@ -27,16 +27,19 @@ var web3 = require('./web3'); // jshint ignore:line /// should be used when we want to watch something /// it's using inner polling mechanism and is notified about changes -var Filter = function(options, impl) { - this.impl = impl; - this.callbacks = []; +/// TODO: change 'options' name cause it may be not the best matching one, since we have events +var Filter = function(options, indexed, impl) { - if (typeof options !== "string") { - // evaluate lazy properties + if (options._isEvent) { + return options(indexed); + } else if (typeof options !== "string") { + + // topics property is deprecated, warn about it! if (options.topics) { console.warn('"topics" is deprecated, use "topic" instead'); } + // evaluate lazy properties options = { to: options.to, topic: options.topic, @@ -46,7 +49,11 @@ var Filter = function(options, impl) { skip: options.skip, address: options.address }; + } + + this.impl = impl; + this.callbacks = []; this.id = impl.newFilter(options); web3.provider.startPolling({call: impl.changed, args: [this.id]}, this.id, this.trigger.bind(this)); diff --git a/lib/web3.js b/lib/web3.js index 7b8bbd28a..6bf8f7bc0 100644 --- a/lib/web3.js +++ b/lib/web3.js @@ -278,8 +278,11 @@ var web3 = { return ret; }; }, - watch: function (params) { - return new web3.filter(params, ethWatch); + + /// @param filter may be a string, object or event + /// @param indexed is optional, this may be an object with optional event indexed params + watch: function (filter, indexed) { + return new web3.filter(filter, indexed, ethWatch); } }, @@ -288,8 +291,11 @@ var web3 = { /// shh object prototype shh: { - watch: function (params) { - return new web3.filter(params, shhWatch); + + /// @param filter may be a string, object or event + /// @param indexed is optional, this may be an object with optional event indexed params + watch: function (filter, indexed) { + return new web3.filter(filter, indexed, shhWatch); } }, -- cgit v1.2.3 From 56890862028cc1e6d0fb58db9ada358bf4384de0 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sat, 31 Jan 2015 01:52:36 +0100 Subject: formatters separated --- lib/abi.js | 142 ++++++++----------------------------------------- lib/formatters.js | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+), 119 deletions(-) create mode 100644 lib/formatters.js (limited to 'lib') diff --git a/lib/abi.js b/lib/abi.js index a0c862593..fbf72b12d 100644 --- a/lib/abi.js +++ b/lib/abi.js @@ -21,12 +21,12 @@ * @date 2014 */ -// TODO: is these line is supposed to be here? if (process.env.NODE_ENV !== 'build') { var BigNumber = require('bignumber.js'); // jshint ignore:line } -var web3 = require('./web3'); // jshint ignore:line +var web3 = require('./web3'); +var f = require('./formatters'); BigNumber.config({ ROUNDING_MODE: BigNumber.ROUND_DOWN }); @@ -85,6 +85,7 @@ var filterEvents = function (json) { /// @param number of characters that result string should have /// @param sign, by default 0 /// @returns right aligned string +/// TODO: remove, it was moved to formatters.js var padLeft = function (string, chars, sign) { return new Array(chars - string.length + 1).join(sign ? sign : "0") + string; }; @@ -105,57 +106,16 @@ var namedType = function (name) { }; }; +/// This method should be called if we want to check if givent type is an array type +/// @returns true if it is, otherwise false var arrayType = function (type) { return type.slice(-2) === '[]'; }; -/// Formats input value to byte representation of int -/// If value is negative, return it's two's complement -/// If the value is floating point, round it down -/// @returns right-aligned byte representation of int -var formatInputInt = function (value) { - var padding = ETH_PADDING * 2; - if (value instanceof BigNumber || typeof value === 'number') { - if (typeof value === 'number') - value = new BigNumber(value); - value = value.round(); - - if (value.lessThan(0)) - value = new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).plus(value).plus(1); - value = value.toString(16); - } - else if (value.indexOf('0x') === 0) - value = value.substr(2); - else if (typeof value === 'string') - value = formatInputInt(new BigNumber(value)); - else - value = (+value).toString(16); - return padLeft(value, padding); -}; - -/// Formats input value to byte representation of string -/// @returns left-algined byte representation of string -var formatInputString = function (value) { - return web3.fromAscii(value, ETH_PADDING).substr(2); -}; - -/// Formats input value to byte representation of bool -/// @returns right-aligned byte representation bool -var formatInputBool = function (value) { - return '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0'); -}; - -/// Formats input value to byte representation of real -/// Values are multiplied by 2^m and encoded as integers -/// @returns byte representation of real -var formatInputReal = function (value) { - return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128))); -}; - var dynamicTypeBytes = function (type, value) { // TODO: decide what to do with array of strings if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length. - return formatInputInt(value.length); + return f.formatInputInt(value.length); return ""; }; @@ -164,14 +124,14 @@ var dynamicTypeBytes = function (type, value) { var setupInputTypes = function () { return [ - { type: prefixedType('uint'), format: formatInputInt }, - { type: prefixedType('int'), format: formatInputInt }, - { type: prefixedType('hash'), format: formatInputInt }, - { type: prefixedType('string'), format: formatInputString }, - { type: prefixedType('real'), format: formatInputReal }, - { type: prefixedType('ureal'), format: formatInputReal }, - { type: namedType('address'), format: formatInputInt }, - { type: namedType('bool'), format: formatInputBool } + { type: prefixedType('uint'), format: f.formatInputInt }, + { type: prefixedType('int'), format: f.formatInputInt }, + { type: prefixedType('hash'), format: f.formatInputInt }, + { type: prefixedType('string'), format: f.formatInputString }, + { type: prefixedType('real'), format: f.formatInputReal }, + { type: prefixedType('ureal'), format: f.formatInputReal }, + { type: namedType('address'), format: f.formatInputInt }, + { type: namedType('bool'), format: f.formatInputBool } ]; }; @@ -217,62 +177,6 @@ var toAbiInput = function (json, methodName, params) { return bytes; }; -/// Check if input value is negative -/// @param value is hex format -/// @returns true if it is negative, otherwise false -var signedIsNegative = function (value) { - return (new BigNumber(value.substr(0, 1), 16).toString(2).substr(0, 1)) === '1'; -}; - -/// Formats input right-aligned input bytes to int -/// @returns right-aligned input bytes formatted to int -var formatOutputInt = function (value) { - value = value || "0"; - // check if it's negative number - // it it is, return two's complement - if (signedIsNegative(value)) { - return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1); - } - return new BigNumber(value, 16); -}; - -/// Formats big right-aligned input bytes to uint -/// @returns right-aligned input bytes formatted to uint -var formatOutputUInt = function (value) { - value = value || "0"; - return new BigNumber(value, 16); -}; - -/// @returns input bytes formatted to real -var formatOutputReal = function (value) { - return formatOutputInt(value).dividedBy(new BigNumber(2).pow(128)); -}; - -/// @returns input bytes formatted to ureal -var formatOutputUReal = function (value) { - return formatOutputUInt(value).dividedBy(new BigNumber(2).pow(128)); -}; - -/// @returns right-aligned input bytes formatted to hex -var formatOutputHash = function (value) { - return "0x" + value; -}; - -/// @returns right-aligned input bytes formatted to bool -var formatOutputBool = function (value) { - return value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false; -}; - -/// @returns left-aligned input bytes formatted to ascii string -var formatOutputString = function (value) { - return web3.toAscii(value); -}; - -/// @returns right-aligned input bytes formatted to address -var formatOutputAddress = function (value) { - return "0x" + value.slice(value.length - 40, value.length); -}; - var dynamicBytesLength = function (type) { if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length. return ETH_PADDING * 2; @@ -284,14 +188,14 @@ var dynamicBytesLength = function (type) { var setupOutputTypes = function () { return [ - { type: prefixedType('uint'), format: formatOutputUInt }, - { type: prefixedType('int'), format: formatOutputInt }, - { type: prefixedType('hash'), format: formatOutputHash }, - { type: prefixedType('string'), format: formatOutputString }, - { type: prefixedType('real'), format: formatOutputReal }, - { type: prefixedType('ureal'), format: formatOutputUReal }, - { type: namedType('address'), format: formatOutputAddress }, - { type: namedType('bool'), format: formatOutputBool } + { type: prefixedType('uint'), format: f.formatOutputUInt }, + { type: prefixedType('int'), format: f.formatOutputInt }, + { type: prefixedType('hash'), format: f.formatOutputHash }, + { type: prefixedType('string'), format: f.formatOutputString }, + { type: prefixedType('real'), format: f.formatOutputReal }, + { type: prefixedType('ureal'), format: f.formatOutputUReal }, + { type: namedType('address'), format: f.formatOutputAddress }, + { type: namedType('bool'), format: f.formatOutputBool } ]; }; @@ -328,7 +232,7 @@ var fromAbiOutput = function (json, methodName, output) { var formatter = outputTypes[j - 1].format; if (arrayType(method.outputs[i].type)) { - var size = formatOutputUInt(dynamicPart.slice(0, padding)); + var size = f.formatOutputUInt(dynamicPart.slice(0, padding)); dynamicPart = dynamicPart.slice(padding); var array = []; for (var k = 0; k < size; k++) { diff --git a/lib/formatters.js b/lib/formatters.js new file mode 100644 index 000000000..54475ef9c --- /dev/null +++ b/lib/formatters.js @@ -0,0 +1,156 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file formatters.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +if (process.env.NODE_ENV !== 'build') { + var BigNumber = require('bignumber.js'); // jshint ignore:line +} + +var web3 = require('./web3'); + +BigNumber.config({ ROUNDING_MODE: BigNumber.ROUND_DOWN }); + +var ETH_PADDING = 32; + +/// @param string string to be padded +/// @param number of characters that result string should have +/// @param sign, by default 0 +/// @returns right aligned string +var padLeft = function (string, chars, sign) { + return new Array(chars - string.length + 1).join(sign ? sign : "0") + string; +}; + +/// Formats input value to byte representation of int +/// If value is negative, return it's two's complement +/// If the value is floating point, round it down +/// @returns right-aligned byte representation of int +var formatInputInt = function (value) { + var padding = ETH_PADDING * 2; + if (value instanceof BigNumber || typeof value === 'number') { + if (typeof value === 'number') + value = new BigNumber(value); + value = value.round(); + + if (value.lessThan(0)) + value = new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).plus(value).plus(1); + value = value.toString(16); + } + else if (value.indexOf('0x') === 0) + value = value.substr(2); + else if (typeof value === 'string') + value = formatInputInt(new BigNumber(value)); + else + value = (+value).toString(16); + return padLeft(value, padding); +}; + +/// Formats input value to byte representation of string +/// @returns left-algined byte representation of string +var formatInputString = function (value) { + return web3.fromAscii(value, ETH_PADDING).substr(2); +}; + +/// Formats input value to byte representation of bool +/// @returns right-aligned byte representation bool +var formatInputBool = function (value) { + return '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0'); +}; + +/// Formats input value to byte representation of real +/// Values are multiplied by 2^m and encoded as integers +/// @returns byte representation of real +var formatInputReal = function (value) { + return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128))); +}; + + +/// Check if input value is negative +/// @param value is hex format +/// @returns true if it is negative, otherwise false +var signedIsNegative = function (value) { + return (new BigNumber(value.substr(0, 1), 16).toString(2).substr(0, 1)) === '1'; +}; + +/// Formats input right-aligned input bytes to int +/// @returns right-aligned input bytes formatted to int +var formatOutputInt = function (value) { + value = value || "0"; + // check if it's negative number + // it it is, return two's complement + if (signedIsNegative(value)) { + return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1); + } + return new BigNumber(value, 16); +}; + +/// Formats big right-aligned input bytes to uint +/// @returns right-aligned input bytes formatted to uint +var formatOutputUInt = function (value) { + value = value || "0"; + return new BigNumber(value, 16); +}; + +/// @returns input bytes formatted to real +var formatOutputReal = function (value) { + return formatOutputInt(value).dividedBy(new BigNumber(2).pow(128)); +}; + +/// @returns input bytes formatted to ureal +var formatOutputUReal = function (value) { + return formatOutputUInt(value).dividedBy(new BigNumber(2).pow(128)); +}; + +/// @returns right-aligned input bytes formatted to hex +var formatOutputHash = function (value) { + return "0x" + value; +}; + +/// @returns right-aligned input bytes formatted to bool +var formatOutputBool = function (value) { + return value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false; +}; + +/// @returns left-aligned input bytes formatted to ascii string +var formatOutputString = function (value) { + return web3.toAscii(value); +}; + +/// @returns right-aligned input bytes formatted to address +var formatOutputAddress = function (value) { + return "0x" + value.slice(value.length - 40, value.length); +}; + + +module.exports = { + formatInputInt: formatInputInt, + formatInputString: formatInputString, + formatInputBool: formatInputBool, + formatInputReal: formatInputReal, + formatOutputInt: formatOutputInt, + formatOutputUInt: formatOutputUInt, + formatOutputReal: formatOutputReal, + formatOutputUReal: formatOutputUReal, + formatOutputHash: formatOutputHash, + formatOutputBool: formatOutputBool, + formatOutputString: formatOutputString, + formatOutputAddress: formatOutputAddress +}; + -- cgit v1.2.3 From 2491c99b37241b8770bca516d5641b2d00a7a660 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sat, 31 Jan 2015 02:54:17 +0100 Subject: abi.js cleanup && new types.js, utils.js --- lib/abi.js | 85 ++++++------------------------------------------------- lib/contract.js | 2 +- lib/event.js | 25 +++++++++++++++- lib/formatters.js | 1 + lib/types.js | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib/utils.js | 39 +++++++++++++++++++++++++ 6 files changed, 153 insertions(+), 78 deletions(-) create mode 100644 lib/types.js create mode 100644 lib/utils.js (limited to 'lib') diff --git a/lib/abi.js b/lib/abi.js index fbf72b12d..fcf787419 100644 --- a/lib/abi.js +++ b/lib/abi.js @@ -26,6 +26,8 @@ if (process.env.NODE_ENV !== 'build') { } var web3 = require('./web3'); +var utils = require('./utils'); +var types = require('./types'); var f = require('./formatters'); BigNumber.config({ ROUNDING_MODE: BigNumber.ROUND_DOWN }); @@ -35,22 +37,9 @@ var ETH_PADDING = 32; /// method signature length in bytes var ETH_METHOD_SIGNATURE_LENGTH = 4; -/// Finds first index of array element matching pattern -/// @param array -/// @param callback pattern -/// @returns index of element -var findIndex = function (array, callback) { - var end = false; - var i = 0; - for (; i < array.length && !end; i++) { - end = callback(array[i]); - } - return end ? i - 1 : -1; -}; - /// @returns a function that is used as a pattern for 'findIndex' var findMethodIndex = function (json, methodName) { - return findIndex(json, function (method) { + return utils.findIndex(json, function (method) { return method.name === methodName; }); }; @@ -81,31 +70,6 @@ var filterEvents = function (json) { }); }; -/// @param string string to be padded -/// @param number of characters that result string should have -/// @param sign, by default 0 -/// @returns right aligned string -/// TODO: remove, it was moved to formatters.js -var padLeft = function (string, chars, sign) { - return new Array(chars - string.length + 1).join(sign ? sign : "0") + string; -}; - -/// @param expected type prefix (string) -/// @returns function which checks if type has matching prefix. if yes, returns true, otherwise false -var prefixedType = function (prefix) { - return function (type) { - return type.indexOf(prefix) === 0; - }; -}; - -/// @param expected type name (string) -/// @returns function which checks if type is matching expected one. if yes, returns true, otherwise false -var namedType = function (name) { - return function (type) { - return name === type; - }; -}; - /// This method should be called if we want to check if givent type is an array type /// @returns true if it is, otherwise false var arrayType = function (type) { @@ -119,23 +83,7 @@ var dynamicTypeBytes = function (type, value) { return ""; }; -/// Setups input formatters for solidity types -/// @returns an array of input formatters -var setupInputTypes = function () { - - return [ - { type: prefixedType('uint'), format: f.formatInputInt }, - { type: prefixedType('int'), format: f.formatInputInt }, - { type: prefixedType('hash'), format: f.formatInputInt }, - { type: prefixedType('string'), format: f.formatInputString }, - { type: prefixedType('real'), format: f.formatInputReal }, - { type: prefixedType('ureal'), format: f.formatInputReal }, - { type: namedType('address'), format: f.formatInputInt }, - { type: namedType('bool'), format: f.formatInputBool } - ]; -}; - -var inputTypes = setupInputTypes(); +var inputTypes = types.inputTypes(); /// Formats input params to bytes /// @param contract json abi @@ -183,23 +131,7 @@ var dynamicBytesLength = function (type) { return 0; }; -/// Setups output formaters for solidity types -/// @returns an array of output formatters -var setupOutputTypes = function () { - - return [ - { type: prefixedType('uint'), format: f.formatOutputUInt }, - { type: prefixedType('int'), format: f.formatOutputInt }, - { type: prefixedType('hash'), format: f.formatOutputHash }, - { type: prefixedType('string'), format: f.formatOutputString }, - { type: prefixedType('real'), format: f.formatOutputReal }, - { type: prefixedType('ureal'), format: f.formatOutputUReal }, - { type: namedType('address'), format: f.formatOutputAddress }, - { type: namedType('bool'), format: f.formatOutputBool } - ]; -}; - -var outputTypes = setupOutputTypes(); +var outputTypes = types.outputTypes(); /// Formats output bytes back to param list /// @param contract json abi @@ -241,7 +173,7 @@ var fromAbiOutput = function (json, methodName, output) { } result.push(array); } - else if (prefixedType('string')(method.outputs[i].type)) { + else if (types.prefixedType('string')(method.outputs[i].type)) { dynamicPart = dynamicPart.slice(padding); result.push(formatter(output.slice(0, padding))); output = output.slice(padding); @@ -269,9 +201,10 @@ var methodTypeName = function (method) { /// @param json abi for contract /// @returns input parser object for given json abi +/// TODO: refactor creating the parser, do not double logic from contract var inputParser = function (json) { var parser = {}; - filterFunctions(json).forEach(function (method) { + json.forEach(function (method) { var displayName = methodDisplayName(method.name); var typeName = methodTypeName(method.name); @@ -294,7 +227,7 @@ var inputParser = function (json) { /// @returns output parser for given json abi var outputParser = function (json) { var parser = {}; - filterFunctions(json).forEach(function (method) { + json.forEach(function (method) { var displayName = methodDisplayName(method.name); var typeName = methodTypeName(method.name); diff --git a/lib/contract.js b/lib/contract.js index 6056581d4..4c92825f1 100644 --- a/lib/contract.js +++ b/lib/contract.js @@ -127,7 +127,7 @@ var addEventsToContract = function (contract, desc, address) { var impl = function () { var params = Array.prototype.slice.call(arguments); var signature = abi.methodSignature(e.name); - var event = eventImpl(address, signature); + var event = eventImpl(address, signature, e); var o = event.apply(null, params); return web3.eth.watch(o); }; diff --git a/lib/event.js b/lib/event.js index ea5f5b71e..c01fea6ef 100644 --- a/lib/event.js +++ b/lib/event.js @@ -21,8 +21,31 @@ */ var abi = require('./abi'); +var utils = require('./utils'); + +var inputWithName = function (inputs, name) { + var index = utils.findIndex(inputs, function (input) { + return input.name === name; + }); + if (index === -1) { + console.error('indexed param ' + name + ' not found in the abi'); + return undefined; + } + return inputs[index]; +}; + +var indexedParamsToTopics = function (inputs, indexed) { + Object.keys(indexed).map(function (key) { + var inp = inputWithName(key); + var value = indexed[key]; + if (value instanceof Array) { + + } + }); +}; + +var implementationOfEvent = function (address, signature, event) { -var implementationOfEvent = function (address, signature) { // valid options are 'earliest', 'latest', 'offset' and 'max', as defined for 'eth.watch' return function (indexed, options) { diff --git a/lib/formatters.js b/lib/formatters.js index 54475ef9c..ea7ddca26 100644 --- a/lib/formatters.js +++ b/lib/formatters.js @@ -24,6 +24,7 @@ if (process.env.NODE_ENV !== 'build') { var BigNumber = require('bignumber.js'); // jshint ignore:line } +// TODO: remove web3 dependency from here! var web3 = require('./web3'); BigNumber.config({ ROUNDING_MODE: BigNumber.ROUND_DOWN }); diff --git a/lib/types.js b/lib/types.js new file mode 100644 index 000000000..a39f2f1fc --- /dev/null +++ b/lib/types.js @@ -0,0 +1,79 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file types.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +var f = require('./formatters'); + +/// @param expected type prefix (string) +/// @returns function which checks if type has matching prefix. if yes, returns true, otherwise false +var prefixedType = function (prefix) { + return function (type) { + return type.indexOf(prefix) === 0; + }; +}; + +/// @param expected type name (string) +/// @returns function which checks if type is matching expected one. if yes, returns true, otherwise false +var namedType = function (name) { + return function (type) { + return name === type; + }; +}; + +/// Setups input formatters for solidity types +/// @returns an array of input formatters +var inputTypes = function () { + + return [ + { type: prefixedType('uint'), format: f.formatInputInt }, + { type: prefixedType('int'), format: f.formatInputInt }, + { type: prefixedType('hash'), format: f.formatInputInt }, + { type: prefixedType('string'), format: f.formatInputString }, + { type: prefixedType('real'), format: f.formatInputReal }, + { type: prefixedType('ureal'), format: f.formatInputReal }, + { type: namedType('address'), format: f.formatInputInt }, + { type: namedType('bool'), format: f.formatInputBool } + ]; +}; + +/// Setups output formaters for solidity types +/// @returns an array of output formatters +var outputTypes = function () { + + return [ + { type: prefixedType('uint'), format: f.formatOutputUInt }, + { type: prefixedType('int'), format: f.formatOutputInt }, + { type: prefixedType('hash'), format: f.formatOutputHash }, + { type: prefixedType('string'), format: f.formatOutputString }, + { type: prefixedType('real'), format: f.formatOutputReal }, + { type: prefixedType('ureal'), format: f.formatOutputUReal }, + { type: namedType('address'), format: f.formatOutputAddress }, + { type: namedType('bool'), format: f.formatOutputBool } + ]; +}; + +module.exports = { + prefixedType: prefixedType, + namedType: namedType, + inputTypes: inputTypes, + outputTypes: outputTypes +}; + diff --git a/lib/utils.js b/lib/utils.js new file mode 100644 index 000000000..c00d4cb34 --- /dev/null +++ b/lib/utils.js @@ -0,0 +1,39 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file utils.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +/// Finds first index of array element matching pattern +/// @param array +/// @param callback pattern +/// @returns index of element +var findIndex = function (array, callback) { + var end = false; + var i = 0; + for (; i < array.length && !end; i++) { + end = callback(array[i]); + } + return end ? i - 1 : -1; +}; + +module.exports = { + findIndex: findIndex +}; + -- cgit v1.2.3 From 80c97ca21b168e7f94cae6333be5439b6db2fe1d Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sat, 31 Jan 2015 03:42:13 +0100 Subject: events --- lib/event.js | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/event.js b/lib/event.js index c01fea6ef..efb85b1fc 100644 --- a/lib/event.js +++ b/lib/event.js @@ -25,27 +25,36 @@ var utils = require('./utils'); var inputWithName = function (inputs, name) { var index = utils.findIndex(inputs, function (input) { - return input.name === name; + return input.name === name; }); + if (index === -1) { - console.error('indexed param ' + name + ' not found in the abi'); - return undefined; + console.error('indexed paray with name ' + name + ' not found'); + return undefined; } return inputs[index]; }; -var indexedParamsToTopics = function (inputs, indexed) { - Object.keys(indexed).map(function (key) { - var inp = inputWithName(key); +var indexedParamsToTopics = function (event, indexed) { + // sort keys? + return Object.keys(indexed).map(function (key) { + // TODO: simplify this! + var parser = abi.inputParser([{ + name: 'test', + inputs: [inputWithName(event.inputs, key)] + }]); + var value = indexed[key]; if (value instanceof Array) { - + return value.map(function (v) { + return parser.test(v); + }); } + return parser.test(value); }); }; var implementationOfEvent = function (address, signature, event) { - // valid options are 'earliest', 'latest', 'offset' and 'max', as defined for 'eth.watch' return function (indexed, options) { @@ -53,6 +62,9 @@ var implementationOfEvent = function (address, signature, event) { o.address = address; o.topic = []; o.topic.push(signature); + if (indexed) { + o.topic = o.topic.concat(indexedParamsToTopics(event, indexed)); + } return o; }; }; -- cgit v1.2.3 From 0b82a05a75a0a7592e4fe391120f90d7cee495ac Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sat, 31 Jan 2015 04:09:48 +0100 Subject: events --- lib/filter.js | 6 ++---- lib/web3.js | 8 +++++--- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/filter.js b/lib/filter.js index d97276f78..4cb297f37 100644 --- a/lib/filter.js +++ b/lib/filter.js @@ -28,11 +28,9 @@ var web3 = require('./web3'); // jshint ignore:line /// should be used when we want to watch something /// it's using inner polling mechanism and is notified about changes /// TODO: change 'options' name cause it may be not the best matching one, since we have events -var Filter = function(options, indexed, impl) { +var Filter = function(options, impl) { - if (options._isEvent) { - return options(indexed); - } else if (typeof options !== "string") { + if (typeof options !== "string") { // topics property is deprecated, warn about it! if (options.topics) { diff --git a/lib/web3.js b/lib/web3.js index 6bf8f7bc0..88dc6931b 100644 --- a/lib/web3.js +++ b/lib/web3.js @@ -282,7 +282,10 @@ var web3 = { /// @param filter may be a string, object or event /// @param indexed is optional, this may be an object with optional event indexed params watch: function (filter, indexed) { - return new web3.filter(filter, indexed, ethWatch); + if (filter._isEvent) { + return filter(indexed); + } + return new web3.filter(filter, ethWatch); } }, @@ -293,9 +296,8 @@ var web3 = { shh: { /// @param filter may be a string, object or event - /// @param indexed is optional, this may be an object with optional event indexed params watch: function (filter, indexed) { - return new web3.filter(filter, indexed, shhWatch); + return new web3.filter(filter, shhWatch); } }, -- cgit v1.2.3 From 4bdf52fc1e5030d53a8b7337051e12ebd0509009 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sat, 31 Jan 2015 13:54:39 +0100 Subject: toAscii && fromAscii moved to utils --- lib/abi.js | 37 +++++++------------------------------ lib/formatters.js | 7 +++---- lib/utils.js | 44 +++++++++++++++++++++++++++++++++++++++++++- lib/web3.js | 38 ++++---------------------------------- 4 files changed, 57 insertions(+), 69 deletions(-) (limited to 'lib') diff --git a/lib/abi.js b/lib/abi.js index fcf787419..1fd3a58fc 100644 --- a/lib/abi.js +++ b/lib/abi.js @@ -37,23 +37,6 @@ var ETH_PADDING = 32; /// method signature length in bytes var ETH_METHOD_SIGNATURE_LENGTH = 4; -/// @returns a function that is used as a pattern for 'findIndex' -var findMethodIndex = function (json, methodName) { - return utils.findIndex(json, function (method) { - return method.name === methodName; - }); -}; - -/// @returns method with given method name -var getMethodWithName = function (json, methodName) { - var index = findMethodIndex(json, methodName); - if (index === -1) { - console.error('method ' + methodName + ' not found in the abi'); - return undefined; - } - return json[index]; -}; - /// Filters all function from input abi /// @returns abi array with filtered objects of type 'function' var filterFunctions = function (json) { @@ -86,14 +69,11 @@ var dynamicTypeBytes = function (type, value) { var inputTypes = types.inputTypes(); /// Formats input params to bytes -/// @param contract json abi -/// @param name of the method that we want to use +/// @param abi contract method /// @param array of params that will be formatted to bytes /// @returns bytes representation of input params -var toAbiInput = function (json, methodName, params) { +var toAbiInput = function (method, params) { var bytes = ""; - - var method = getMethodWithName(json, methodName); var padding = ETH_PADDING * 2; /// first we iterate in search for dynamic @@ -134,15 +114,13 @@ var dynamicBytesLength = function (type) { var outputTypes = types.outputTypes(); /// Formats output bytes back to param list -/// @param contract json abi -/// @param name of the method that we want to use +/// @param contract abi method /// @param bytes representtion of output /// @returns array of output params -var fromAbiOutput = function (json, methodName, output) { +var fromAbiOutput = function (method, output) { output = output.slice(2); var result = []; - var method = getMethodWithName(json, methodName); var padding = ETH_PADDING * 2; var dynamicPartLength = method.outputs.reduce(function (acc, curr) { @@ -194,7 +172,7 @@ var methodDisplayName = function (method) { /// @returns overloaded part of method's name var methodTypeName = function (method) { - /// TODO: make it not vulnerable + /// TODO: make it invulnerable var length = method.indexOf('('); return length !== -1 ? method.substr(length + 1, method.length - 1 - (length + 1)) : ""; }; @@ -210,7 +188,7 @@ var inputParser = function (json) { var impl = function () { var params = Array.prototype.slice.call(arguments); - return toAbiInput(json, method.name, params); + return toAbiInput(method, params); }; if (parser[displayName] === undefined) { @@ -233,7 +211,7 @@ var outputParser = function (json) { var typeName = methodTypeName(method.name); var impl = function (output) { - return fromAbiOutput(json, method.name, output); + return fromAbiOutput(method, output); }; if (parser[displayName] === undefined) { @@ -258,7 +236,6 @@ module.exports = { methodSignature: methodSignature, methodDisplayName: methodDisplayName, methodTypeName: methodTypeName, - getMethodWithName: getMethodWithName, filterFunctions: filterFunctions, filterEvents: filterEvents }; diff --git a/lib/formatters.js b/lib/formatters.js index ea7ddca26..d8781e21e 100644 --- a/lib/formatters.js +++ b/lib/formatters.js @@ -24,8 +24,7 @@ if (process.env.NODE_ENV !== 'build') { var BigNumber = require('bignumber.js'); // jshint ignore:line } -// TODO: remove web3 dependency from here! -var web3 = require('./web3'); +var utils = require('./utils'); BigNumber.config({ ROUNDING_MODE: BigNumber.ROUND_DOWN }); @@ -66,7 +65,7 @@ var formatInputInt = function (value) { /// Formats input value to byte representation of string /// @returns left-algined byte representation of string var formatInputString = function (value) { - return web3.fromAscii(value, ETH_PADDING).substr(2); + return utils.fromAscii(value, ETH_PADDING).substr(2); }; /// Formats input value to byte representation of bool @@ -131,7 +130,7 @@ var formatOutputBool = function (value) { /// @returns left-aligned input bytes formatted to ascii string var formatOutputString = function (value) { - return web3.toAscii(value); + return utils.toAscii(value); }; /// @returns right-aligned input bytes formatted to address diff --git a/lib/utils.js b/lib/utils.js index c00d4cb34..f9fcd3389 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -33,7 +33,49 @@ var findIndex = function (array, callback) { return end ? i - 1 : -1; }; +/// @returns ascii string representation of hex value prefixed with 0x +var toAscii = function(hex) { +// Find termination + var str = ""; + var i = 0, l = hex.length; + if (hex.substring(0, 2) === '0x') { + i = 2; + } + for (; i < l; i+=2) { + var code = parseInt(hex.substr(i, 2), 16); + if (code === 0) { + break; + } + + str += String.fromCharCode(code); + } + + return str; +}; + +var toHex = function(str) { + var hex = ""; + for(var i = 0; i < str.length; i++) { + var n = str.charCodeAt(i).toString(16); + hex += n.length < 2 ? '0' + n : n; + } + + return hex; +}; + +/// @returns hex representation (prefixed by 0x) of ascii string +var fromAscii = function(str, pad) { + pad = pad === undefined ? 0 : pad; + var hex = toHex(str); + while (hex.length < pad*2) + hex += "00"; + return "0x" + hex; +}; + + module.exports = { - findIndex: findIndex + findIndex: findIndex, + toAscii: toAscii, + fromAscii: fromAscii }; diff --git a/lib/web3.js b/lib/web3.js index 88dc6931b..c99c76421 100644 --- a/lib/web3.js +++ b/lib/web3.js @@ -27,6 +27,8 @@ if (process.env.NODE_ENV !== 'build') { var BigNumber = require('bignumber.js'); } +var utils = require('./utils'); + var ETH_UNITS = [ 'wei', 'Kwei', @@ -192,43 +194,11 @@ var web3 = { _events: {}, providers: {}, - toHex: function(str) { - var hex = ""; - for(var i = 0; i < str.length; i++) { - var n = str.charCodeAt(i).toString(16); - hex += n.length < 2 ? '0' + n : n; - } - - return hex; - }, - /// @returns ascii string representation of hex value prefixed with 0x - toAscii: function(hex) { - // Find termination - var str = ""; - var i = 0, l = hex.length; - if (hex.substring(0, 2) === '0x') - i = 2; - for(; i < l; i+=2) { - var code = parseInt(hex.substr(i, 2), 16); - if(code === 0) { - break; - } - - str += String.fromCharCode(code); - } - - return str; - }, + toAscii: utils.toAscii, /// @returns hex representation (prefixed by 0x) of ascii string - fromAscii: function(str, pad) { - pad = pad === undefined ? 0 : pad; - var hex = this.toHex(str); - while(hex.length < pad*2) - hex += "00"; - return "0x" + hex; - }, + fromAscii: utils.fromAscii, /// @returns decimal representaton of hex value prefixed by 0x toDecimal: function (val) { -- cgit v1.2.3 From a8a2e3231c2ced50989dc5d23659f7482a667f69 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sat, 31 Jan 2015 14:05:48 +0100 Subject: constants separated to const.js file --- lib/abi.js | 20 +++++--------------- lib/const.js | 33 +++++++++++++++++++++++++++++++++ lib/formatters.js | 10 ++++------ 3 files changed, 42 insertions(+), 21 deletions(-) create mode 100644 lib/const.js (limited to 'lib') diff --git a/lib/abi.js b/lib/abi.js index 1fd3a58fc..01d2debb7 100644 --- a/lib/abi.js +++ b/lib/abi.js @@ -21,22 +21,12 @@ * @date 2014 */ -if (process.env.NODE_ENV !== 'build') { - var BigNumber = require('bignumber.js'); // jshint ignore:line -} - var web3 = require('./web3'); var utils = require('./utils'); var types = require('./types'); +var c = require('./const'); var f = require('./formatters'); -BigNumber.config({ ROUNDING_MODE: BigNumber.ROUND_DOWN }); - -var ETH_PADDING = 32; - -/// method signature length in bytes -var ETH_METHOD_SIGNATURE_LENGTH = 4; - /// Filters all function from input abi /// @returns abi array with filtered objects of type 'function' var filterFunctions = function (json) { @@ -74,7 +64,7 @@ var inputTypes = types.inputTypes(); /// @returns bytes representation of input params var toAbiInput = function (method, params) { var bytes = ""; - var padding = ETH_PADDING * 2; + var padding = c.ETH_PADDING * 2; /// first we iterate in search for dynamic method.inputs.forEach(function (input, index) { @@ -107,7 +97,7 @@ var toAbiInput = function (method, params) { var dynamicBytesLength = function (type) { if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length. - return ETH_PADDING * 2; + return c.ETH_PADDING * 2; return 0; }; @@ -121,7 +111,7 @@ var fromAbiOutput = function (method, output) { output = output.slice(2); var result = []; - var padding = ETH_PADDING * 2; + var padding = c.ETH_PADDING * 2; var dynamicPartLength = method.outputs.reduce(function (acc, curr) { return acc + dynamicBytesLength(curr.type); @@ -227,7 +217,7 @@ var outputParser = function (json) { /// @param method name for which we want to get method signature /// @returns (promise) contract method signature for method with given name var methodSignature = function (name) { - return web3.sha3(web3.fromAscii(name)).slice(0, 2 + ETH_METHOD_SIGNATURE_LENGTH * 2); + return web3.sha3(web3.fromAscii(name)).slice(0, 2 + c.ETH_METHOD_SIGNATURE_LENGTH * 2); }; module.exports = { diff --git a/lib/const.js b/lib/const.js new file mode 100644 index 000000000..69ed5a09b --- /dev/null +++ b/lib/const.js @@ -0,0 +1,33 @@ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file const.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +/// required to define ETH_BIGNUMBER_ROUNDING_MODE +if (process.env.NODE_ENV !== 'build') { + var BigNumber = require('bignumber.js'); // jshint ignore:line +} + +module.exports = { + ETH_PADDING: 32, + ETH_METHOD_SIGNATURE_LENGTH: 4, + ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN } +}; + diff --git a/lib/formatters.js b/lib/formatters.js index d8781e21e..857a01a40 100644 --- a/lib/formatters.js +++ b/lib/formatters.js @@ -25,10 +25,7 @@ if (process.env.NODE_ENV !== 'build') { } var utils = require('./utils'); - -BigNumber.config({ ROUNDING_MODE: BigNumber.ROUND_DOWN }); - -var ETH_PADDING = 32; +var c = require('./const'); /// @param string string to be padded /// @param number of characters that result string should have @@ -43,10 +40,11 @@ var padLeft = function (string, chars, sign) { /// If the value is floating point, round it down /// @returns right-aligned byte representation of int var formatInputInt = function (value) { - var padding = ETH_PADDING * 2; + var padding = c.ETH_PADDING * 2; if (value instanceof BigNumber || typeof value === 'number') { if (typeof value === 'number') value = new BigNumber(value); + BigNumber.config(c.ETH_BIGNUMBER_ROUNDING_MODE); value = value.round(); if (value.lessThan(0)) @@ -65,7 +63,7 @@ var formatInputInt = function (value) { /// Formats input value to byte representation of string /// @returns left-algined byte representation of string var formatInputString = function (value) { - return utils.fromAscii(value, ETH_PADDING).substr(2); + return utils.fromAscii(value, c.ETH_PADDING).substr(2); }; /// Formats input value to byte representation of bool -- cgit v1.2.3 From b20e972bec52781de806fb050e72d44b729c6541 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sat, 31 Jan 2015 15:22:05 +0100 Subject: few methods moved to utils --- lib/abi.js | 51 +++++++++------------------------------------------ lib/const.js | 2 +- lib/contract.js | 53 +++++++++++++++++++++++++++-------------------------- lib/event.js | 2 +- lib/utils.js | 34 +++++++++++++++++++++++++++++++++- 5 files changed, 71 insertions(+), 71 deletions(-) (limited to 'lib') diff --git a/lib/abi.js b/lib/abi.js index 01d2debb7..8121c1a05 100644 --- a/lib/abi.js +++ b/lib/abi.js @@ -27,22 +27,6 @@ var types = require('./types'); var c = require('./const'); var f = require('./formatters'); -/// Filters all function from input abi -/// @returns abi array with filtered objects of type 'function' -var filterFunctions = function (json) { - return json.filter(function (current) { - return current.type === 'function'; - }); -}; - -/// Filters all events form input abi -/// @returns abi array with filtered objects of type 'event' -var filterEvents = function (json) { - return json.filter(function (current) { - return current.type === 'event'; - }); -}; - /// This method should be called if we want to check if givent type is an array type /// @returns true if it is, otherwise false var arrayType = function (type) { @@ -154,27 +138,14 @@ var fromAbiOutput = function (method, output) { return result; }; -/// @returns display name for method eg. multiply(uint256) -> multiply -var methodDisplayName = function (method) { - var length = method.indexOf('('); - return length !== -1 ? method.substr(0, length) : method; -}; - -/// @returns overloaded part of method's name -var methodTypeName = function (method) { - /// TODO: make it invulnerable - var length = method.indexOf('('); - return length !== -1 ? method.substr(length + 1, method.length - 1 - (length + 1)) : ""; -}; - /// @param json abi for contract /// @returns input parser object for given json abi /// TODO: refactor creating the parser, do not double logic from contract var inputParser = function (json) { var parser = {}; json.forEach(function (method) { - var displayName = methodDisplayName(method.name); - var typeName = methodTypeName(method.name); + var displayName = utils.extractDisplayName(method.name); + var typeName = utils.extractTypeName(method.name); var impl = function () { var params = Array.prototype.slice.call(arguments); @@ -197,8 +168,8 @@ var outputParser = function (json) { var parser = {}; json.forEach(function (method) { - var displayName = methodDisplayName(method.name); - var typeName = methodTypeName(method.name); + var displayName = utils.extractDisplayName(method.name); + var typeName = utils.extractTypeName(method.name); var impl = function (output) { return fromAbiOutput(method, output); @@ -214,19 +185,15 @@ var outputParser = function (json) { return parser; }; -/// @param method name for which we want to get method signature -/// @returns (promise) contract method signature for method with given name -var methodSignature = function (name) { - return web3.sha3(web3.fromAscii(name)).slice(0, 2 + c.ETH_METHOD_SIGNATURE_LENGTH * 2); +/// @param function/event name for which we want to get signature +/// @returns signature of function/event with given name +var signatureFromAscii = function (name) { + return web3.sha3(web3.fromAscii(name)).slice(0, 2 + c.ETH_SIGNATURE_LENGTH * 2); }; module.exports = { inputParser: inputParser, outputParser: outputParser, - methodSignature: methodSignature, - methodDisplayName: methodDisplayName, - methodTypeName: methodTypeName, - filterFunctions: filterFunctions, - filterEvents: filterEvents + signatureFromAscii: signatureFromAscii }; diff --git a/lib/const.js b/lib/const.js index 69ed5a09b..22f6dc690 100644 --- a/lib/const.js +++ b/lib/const.js @@ -27,7 +27,7 @@ if (process.env.NODE_ENV !== 'build') { module.exports = { ETH_PADDING: 32, - ETH_METHOD_SIGNATURE_LENGTH: 4, + ETH_SIGNATURE_LENGTH: 4, ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN } }; diff --git a/lib/contract.js b/lib/contract.js index 4c92825f1..94a6d7dac 100644 --- a/lib/contract.js +++ b/lib/contract.js @@ -22,8 +22,18 @@ var web3 = require('./web3'); var abi = require('./abi'); +var utils = require('./utils'); var eventImpl = require('./event'); +var exportNatspecGlobals = function (vars) { + // it's used byt natspec.js + // TODO: figure out better way to solve this + web3._currentContractAbi = vars.abi; + web3._currentContractAddress = vars.address; + web3._currentContractMethodName = vars.method; + web3._currentContractMethodParams = vars.params; +}; + var addFunctionRelatedPropertiesToContract = function (contract) { contract.call = function (options) { @@ -53,14 +63,14 @@ var addFunctionsToContract = function (contract, desc, address) { var outputParser = abi.outputParser(desc); // create contract functions - abi.filterFunctions(desc).forEach(function (method) { + utils.filterFunctions(desc).forEach(function (method) { - var displayName = abi.methodDisplayName(method.name); - var typeName = abi.methodTypeName(method.name); + var displayName = utils.extractDisplayName(method.name); + var typeName = utils.extractTypeName(method.name); var impl = function () { var params = Array.prototype.slice.call(arguments); - var signature = abi.methodSignature(method.name); + var signature = abi.signatureFromAscii(method.name); var parsed = inputParser[displayName][typeName].apply(null, params); var options = contract._options || {}; @@ -75,12 +85,13 @@ var addFunctionsToContract = function (contract, desc, address) { contract._isTransact = null; if (isTransact) { - // it's used byt natspec.js - // TODO: figure out better way to solve this - web3._currentContractAbi = desc; - web3._currentContractAddress = address; - web3._currentContractMethodName = method.name; - web3._currentContractMethodParams = params; + + exportNatspecGlobals({ + abi: desc, + address: address, + method: method.name, + params: params + }); // transactions do not have any output, cause we do not know, when they will be processed web3.eth.transact(options); @@ -112,8 +123,8 @@ var addEventRelatedPropertiesToContract = function (contract, desc, address) { Object.defineProperty(contract, 'topic', { get: function() { - return abi.filterEvents(desc).map(function (e) { - return abi.methodSignature(e.name); + return utils.filterEvents(desc).map(function (e) { + return abi.signatureFromAscii(e.name); }); } }); @@ -122,11 +133,11 @@ var addEventRelatedPropertiesToContract = function (contract, desc, address) { var addEventsToContract = function (contract, desc, address) { // create contract events - abi.filterEvents(desc).forEach(function (e) { + utils.filterEvents(desc).forEach(function (e) { var impl = function () { var params = Array.prototype.slice.call(arguments); - var signature = abi.methodSignature(e.name); + var signature = abi.signatureFromAscii(e.name); var event = eventImpl(address, signature, e); var o = event.apply(null, params); return web3.eth.watch(o); @@ -135,18 +146,8 @@ var addEventsToContract = function (contract, desc, address) { // this property should be used by eth.filter to check if object is an event impl._isEvent = true; - // TODO: we can remove address && topic properties, they are not used anymore since we introduced _isEvent - impl.address = address; - - Object.defineProperty(impl, 'topic', { - get: function() { - return [abi.methodSignature(e.name)]; - } - }); - - // TODO: rename these methods, cause they are used not only for methods - var displayName = abi.methodDisplayName(e.name); - var typeName = abi.methodTypeName(e.name); + var displayName = utils.extractDisplayName(e.name); + var typeName = utils.extractTypeName(e.name); if (contract[displayName] === undefined) { contract[displayName] = impl; diff --git a/lib/event.js b/lib/event.js index efb85b1fc..43ea96d12 100644 --- a/lib/event.js +++ b/lib/event.js @@ -29,7 +29,7 @@ var inputWithName = function (inputs, name) { }); if (index === -1) { - console.error('indexed paray with name ' + name + ' not found'); + console.error('indexed param with name ' + name + ' not found'); return undefined; } return inputs[index]; diff --git a/lib/utils.js b/lib/utils.js index f9fcd3389..5cd6ec8d6 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -72,10 +72,42 @@ var fromAscii = function(str, pad) { return "0x" + hex; }; +/// @returns display name for function/event eg. multiply(uint256) -> multiply +var extractDisplayName = function (name) { + var length = name.indexOf('('); + return length !== -1 ? name.substr(0, length) : name; +}; + +/// @returns overloaded part of function/event name +var extractTypeName = function (name) { + /// TODO: make it invulnerable + var length = name.indexOf('('); + return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)) : ""; +}; + +/// Filters all function from input abi +/// @returns abi array with filtered objects of type 'function' +var filterFunctions = function (json) { + return json.filter(function (current) { + return current.type === 'function'; + }); +}; + +/// Filters all events form input abi +/// @returns abi array with filtered objects of type 'event' +var filterEvents = function (json) { + return json.filter(function (current) { + return current.type === 'event'; + }); +}; module.exports = { findIndex: findIndex, toAscii: toAscii, - fromAscii: fromAscii + fromAscii: fromAscii, + extractDisplayName: extractDisplayName, + extractTypeName: extractTypeName, + filterFunctions: filterFunctions, + filterEvents: filterEvents }; -- cgit v1.2.3 From 589c4fb30f2e68972b898c5ce084cda5b0831266 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sat, 31 Jan 2015 15:48:49 +0100 Subject: formatInput && formatOutput simplified --- lib/abi.js | 40 +++++++++++++++++++++++----------------- lib/event.js | 10 +++------- 2 files changed, 26 insertions(+), 24 deletions(-) (limited to 'lib') diff --git a/lib/abi.js b/lib/abi.js index 8121c1a05..ecff1e5d6 100644 --- a/lib/abi.js +++ b/lib/abi.js @@ -27,6 +27,10 @@ var types = require('./types'); var c = require('./const'); var f = require('./formatters'); +var displayTypeError = function (type) { + console.error('parser does not support type: ' + type); +}; + /// This method should be called if we want to check if givent type is an array type /// @returns true if it is, otherwise false var arrayType = function (type) { @@ -43,31 +47,31 @@ var dynamicTypeBytes = function (type, value) { var inputTypes = types.inputTypes(); /// Formats input params to bytes -/// @param abi contract method +/// @param abi contract method inputs /// @param array of params that will be formatted to bytes /// @returns bytes representation of input params -var toAbiInput = function (method, params) { +var formatInput = function (inputs, params) { var bytes = ""; var padding = c.ETH_PADDING * 2; /// first we iterate in search for dynamic - method.inputs.forEach(function (input, index) { + inputs.forEach(function (input, index) { bytes += dynamicTypeBytes(input.type, params[index]); }); - method.inputs.forEach(function (input, i) { + inputs.forEach(function (input, i) { var typeMatch = false; for (var j = 0; j < inputTypes.length && !typeMatch; j++) { - typeMatch = inputTypes[j].type(method.inputs[i].type, params[i]); + typeMatch = inputTypes[j].type(inputs[i].type, params[i]); } if (!typeMatch) { - console.error('input parser does not support type: ' + method.inputs[i].type); + displayTypeError(inputs[i].type); } var formatter = inputTypes[j - 1].format; var toAppend = ""; - if (arrayType(method.inputs[i].type)) + if (arrayType(inputs[i].type)) toAppend = params[i].reduce(function (acc, curr) { return acc + formatter(curr); }, ""); @@ -88,34 +92,34 @@ var dynamicBytesLength = function (type) { var outputTypes = types.outputTypes(); /// Formats output bytes back to param list -/// @param contract abi method +/// @param contract abi method outputs /// @param bytes representtion of output /// @returns array of output params -var fromAbiOutput = function (method, output) { +var formatOutput = function (outs, output) { output = output.slice(2); var result = []; var padding = c.ETH_PADDING * 2; - var dynamicPartLength = method.outputs.reduce(function (acc, curr) { + var dynamicPartLength = outs.reduce(function (acc, curr) { return acc + dynamicBytesLength(curr.type); }, 0); var dynamicPart = output.slice(0, dynamicPartLength); output = output.slice(dynamicPartLength); - method.outputs.forEach(function (out, i) { + outs.forEach(function (out, i) { var typeMatch = false; for (var j = 0; j < outputTypes.length && !typeMatch; j++) { - typeMatch = outputTypes[j].type(method.outputs[i].type); + typeMatch = outputTypes[j].type(outs[i].type); } if (!typeMatch) { - console.error('output parser does not support type: ' + method.outputs[i].type); + displayTypeError(outs[i].type); } var formatter = outputTypes[j - 1].format; - if (arrayType(method.outputs[i].type)) { + if (arrayType(outs[i].type)) { var size = f.formatOutputUInt(dynamicPart.slice(0, padding)); dynamicPart = dynamicPart.slice(padding); var array = []; @@ -125,7 +129,7 @@ var fromAbiOutput = function (method, output) { } result.push(array); } - else if (types.prefixedType('string')(method.outputs[i].type)) { + else if (types.prefixedType('string')(outs[i].type)) { dynamicPart = dynamicPart.slice(padding); result.push(formatter(output.slice(0, padding))); output = output.slice(padding); @@ -149,7 +153,7 @@ var inputParser = function (json) { var impl = function () { var params = Array.prototype.slice.call(arguments); - return toAbiInput(method, params); + return formatInput(method.inputs, params); }; if (parser[displayName] === undefined) { @@ -172,7 +176,7 @@ var outputParser = function (json) { var typeName = utils.extractTypeName(method.name); var impl = function (output) { - return fromAbiOutput(method, output); + return formatOutput(method.outputs, output); }; if (parser[displayName] === undefined) { @@ -194,6 +198,8 @@ var signatureFromAscii = function (name) { module.exports = { inputParser: inputParser, outputParser: outputParser, + formatInput: formatInput, + formatOutput: formatOutput, signatureFromAscii: signatureFromAscii }; diff --git a/lib/event.js b/lib/event.js index 43ea96d12..812ef9115 100644 --- a/lib/event.js +++ b/lib/event.js @@ -38,19 +38,15 @@ var inputWithName = function (inputs, name) { var indexedParamsToTopics = function (event, indexed) { // sort keys? return Object.keys(indexed).map(function (key) { - // TODO: simplify this! - var parser = abi.inputParser([{ - name: 'test', - inputs: [inputWithName(event.inputs, key)] - }]); + var inputs = [inputWithName(event.inputs, key)]; var value = indexed[key]; if (value instanceof Array) { return value.map(function (v) { - return parser.test(v); + return abi.formatInput(inputs, [v]); }); } - return parser.test(value); + return abi.formatInput(inputs, [value]); }); }; -- cgit v1.2.3 From 688030ecb615cbf97c428cf1dd2e337380079168 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sat, 31 Jan 2015 16:01:41 +0100 Subject: eth.filter next param optional --- lib/web3.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/web3.js b/lib/web3.js index c99c76421..c3126afc4 100644 --- a/lib/web3.js +++ b/lib/web3.js @@ -250,10 +250,11 @@ var web3 = { }, /// @param filter may be a string, object or event - /// @param indexed is optional, this may be an object with optional event indexed params - watch: function (filter, indexed) { + /// @param indexed is optional, this is an object with optional event indexed params + /// @param options is optional, this is an object with optional event options ('max'...) + watch: function (filter, indexed, options) { if (filter._isEvent) { - return filter(indexed); + return filter(indexed, options); } return new web3.filter(filter, ethWatch); } -- cgit v1.2.3