/* 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 event.js * @author Marek Kotewicz * @date 2014 */ var utils = require('../utils/utils'); var coder = require('../solidity/coder'); var web3 = require('../web3'); var formatters = require('./formatters'); var sha3 = require('../utils/sha3'); /** * This prototype should be used to create event filters */ var SolidityEvent = function (json, address) { this._params = json.inputs; this._name = utils.transformToFullName(json); this._address = address; this._anonymous = json.anonymous; }; /** * Should be used to get filtered param types * * @method types * @param {Bool} decide if returned typed should be indexed * @return {Array} array of types */ SolidityEvent.prototype.types = function (indexed) { return this._params.filter(function (i) { return i.indexed === indexed; }).map(function (i) { return i.type; }); }; /** * Should be used to get event display name * * @method displayName * @return {String} event display name */ SolidityEvent.prototype.displayName = function () { return utils.extractDisplayName(this._name); }; /** * Should be used to get event type name * * @method typeName * @return {String} event type name */ SolidityEvent.prototype.typeName = function () { return utils.extractTypeName(this._name); }; /** * Should be used to get event signature * * @method signature * @return {String} event signature */ SolidityEvent.prototype.signature = function () { return sha3(this._name); }; /** * Should be used to encode indexed params and options to one final object * * @method encode * @param {Object} indexed * @param {Object} options * @return {Object} everything combined together and encoded */ SolidityEvent.prototype.encode = function (indexed, options) { indexed = indexed || {}; options = options || {}; var result = {}; ['fromBlock', 'toBlock'].filter(function (f) { return options[f] !== undefined; }).forEach(function (f) { result[f] = formatters.inputBlockNumberFormatter(options[f]); }); result.topics = []; if (!this._anonymous) { result.address = this._address; result.topics.push('0x' + this.signature()); } var indexedTopics = this._params.filter(function (i) { return i.indexed === true; }).map(function (i) { var value = indexed[i.name]; if (value === undefined || value === null) { return null; } if (utils.isArray(value)) { return value.map(function (v) { return '0x' + coder.encodeParam(i.type, v); }); } return '0x' + coder.encodeParam(i.type, value); }); result.topics = result.topics.concat(indexedTopics); return result; }; /** * Should be used to decode indexed params and options * * @method decode * @param {Object} data * @return {Object} result object with decoded indexed && not indexed params */ SolidityEvent.prototype.decode = function (data) { data.data = data.data || ''; data.topics = data.topics || []; var argTopics = this._anonymous ? data.topics : data.topics.slice(1); var indexedData = argTopics.map(function (topics) { return topics.slice(2); }).join(""); var indexedParams = coder.decodeParams(this.types(true), indexedData); var notIndexedData = data.data.slice(2); var notIndexedParams = coder.decodeParams(this.types(false), notIndexedData); var result = formatters.outputLogFormatter(data); result.event = this.displayName(); result.address = data.address; result.args = this._params.reduce(function (acc, current) { acc[current.name] = current.indexed ? indexedParams.shift() : notIndexedParams.shift(); return acc; }, {}); delete result.data; delete result.topics; return result; }; /** * Should be used to create new filter object from event * * @method execute * @param {Object} indexed * @param {Object} options * @return {Object} filter object */ SolidityEvent.prototype.execute = function (indexed, options) { var o = this.encode(indexed, options); var formatter = this.decode.bind(this); return web3.eth.filter(o, undefined, undefined, formatter); }; /** * Should be used to attach event to contract object * * @method attachToContract * @param {Contract} */ SolidityEvent.prototype.attachToContract = function (contract) { var execute = this.execute.bind(this); var displayName = this.displayName(); if (!contract[displayName]) { contract[displayName] = execute; } contract[displayName][this.typeName()] = this.execute.bind(this, contract); }; module.exports = SolidityEvent;