github.com/jonasnick/go-ethereum@v0.7.12-0.20150216215225-22176f05d387/cmd/mist/assets/ext/ethereum.js/lib/contract.js (about) 1 /* 2 This file is part of ethereum.js. 3 4 ethereum.js is free software: you can redistribute it and/or modify 5 it under the terms of the GNU Lesser General Public License as published by 6 the Free Software Foundation, either version 3 of the License, or 7 (at your option) any later version. 8 9 ethereum.js is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU Lesser General Public License for more details. 13 14 You should have received a copy of the GNU Lesser General Public License 15 along with ethereum.js. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 /** @file contract.js 18 * @authors: 19 * Marek Kotewicz <marek@ethdev.com> 20 * @date 2014 21 */ 22 23 var web3 = require('./web3'); 24 var abi = require('./abi'); 25 var utils = require('./utils'); 26 var eventImpl = require('./event'); 27 28 var exportNatspecGlobals = function (vars) { 29 // it's used byt natspec.js 30 // TODO: figure out better way to solve this 31 web3._currentContractAbi = vars.abi; 32 web3._currentContractAddress = vars.address; 33 web3._currentContractMethodName = vars.method; 34 web3._currentContractMethodParams = vars.params; 35 }; 36 37 var addFunctionRelatedPropertiesToContract = function (contract) { 38 39 contract.call = function (options) { 40 contract._isTransact = false; 41 contract._options = options; 42 return contract; 43 }; 44 45 contract.transact = function (options) { 46 contract._isTransact = true; 47 contract._options = options; 48 return contract; 49 }; 50 51 contract._options = {}; 52 ['gas', 'gasPrice', 'value', 'from'].forEach(function(p) { 53 contract[p] = function (v) { 54 contract._options[p] = v; 55 return contract; 56 }; 57 }); 58 59 }; 60 61 var addFunctionsToContract = function (contract, desc, address) { 62 var inputParser = abi.inputParser(desc); 63 var outputParser = abi.outputParser(desc); 64 65 // create contract functions 66 utils.filterFunctions(desc).forEach(function (method) { 67 68 var displayName = utils.extractDisplayName(method.name); 69 var typeName = utils.extractTypeName(method.name); 70 71 var impl = function () { 72 var params = Array.prototype.slice.call(arguments); 73 var signature = abi.signatureFromAscii(method.name); 74 var parsed = inputParser[displayName][typeName].apply(null, params); 75 76 var options = contract._options || {}; 77 options.to = address; 78 options.data = signature + parsed; 79 80 var isTransact = contract._isTransact === true || (contract._isTransact !== false && !method.constant); 81 var collapse = options.collapse !== false; 82 83 // reset 84 contract._options = {}; 85 contract._isTransact = null; 86 87 if (isTransact) { 88 89 exportNatspecGlobals({ 90 abi: desc, 91 address: address, 92 method: method.name, 93 params: params 94 }); 95 96 // transactions do not have any output, cause we do not know, when they will be processed 97 web3.eth.transact(options); 98 return; 99 } 100 101 var output = web3.eth.call(options); 102 var ret = outputParser[displayName][typeName](output); 103 if (collapse) 104 { 105 if (ret.length === 1) 106 ret = ret[0]; 107 else if (ret.length === 0) 108 ret = null; 109 } 110 return ret; 111 }; 112 113 if (contract[displayName] === undefined) { 114 contract[displayName] = impl; 115 } 116 117 contract[displayName][typeName] = impl; 118 }); 119 }; 120 121 var addEventRelatedPropertiesToContract = function (contract, desc, address) { 122 contract.address = address; 123 contract._onWatchEventResult = function (data) { 124 var matchingEvent = event.getMatchingEvent(utils.filterEvents(desc)); 125 var parser = eventImpl.outputParser(matchingEvent); 126 return parser(data); 127 }; 128 129 Object.defineProperty(contract, 'topic', { 130 get: function() { 131 return utils.filterEvents(desc).map(function (e) { 132 return abi.eventSignatureFromAscii(e.name); 133 }); 134 } 135 }); 136 137 }; 138 139 var addEventsToContract = function (contract, desc, address) { 140 // create contract events 141 utils.filterEvents(desc).forEach(function (e) { 142 143 var impl = function () { 144 var params = Array.prototype.slice.call(arguments); 145 var signature = abi.eventSignatureFromAscii(e.name); 146 var event = eventImpl.inputParser(address, signature, e); 147 var o = event.apply(null, params); 148 o._onWatchEventResult = function (data) { 149 var parser = eventImpl.outputParser(e); 150 return parser(data); 151 }; 152 return web3.eth.watch(o); 153 }; 154 155 // this property should be used by eth.filter to check if object is an event 156 impl._isEvent = true; 157 158 var displayName = utils.extractDisplayName(e.name); 159 var typeName = utils.extractTypeName(e.name); 160 161 if (contract[displayName] === undefined) { 162 contract[displayName] = impl; 163 } 164 165 contract[displayName][typeName] = impl; 166 167 }); 168 }; 169 170 171 /** 172 * This method should be called when we want to call / transact some solidity method from javascript 173 * it returns an object which has same methods available as solidity contract description 174 * usage example: 175 * 176 * var abi = [{ 177 * name: 'myMethod', 178 * inputs: [{ name: 'a', type: 'string' }], 179 * outputs: [{name: 'd', type: 'string' }] 180 * }]; // contract abi 181 * 182 * var myContract = web3.eth.contract('0x0123123121', abi); // creation of contract object 183 * 184 * myContract.myMethod('this is test string param for call'); // myMethod call (implicit, default) 185 * myContract.call().myMethod('this is test string param for call'); // myMethod call (explicit) 186 * myContract.transact().myMethod('this is test string param for transact'); // myMethod transact 187 * 188 * @param address - address of the contract, which should be called 189 * @param desc - abi json description of the contract, which is being created 190 * @returns contract object 191 */ 192 193 var contract = function (address, desc) { 194 195 // workaround for invalid assumption that method.name is the full anonymous prototype of the method. 196 // it's not. it's just the name. the rest of the code assumes it's actually the anonymous 197 // prototype, so we make it so as a workaround. 198 // TODO: we may not want to modify input params, maybe use copy instead? 199 desc.forEach(function (method) { 200 if (method.name.indexOf('(') === -1) { 201 var displayName = method.name; 202 var typeName = method.inputs.map(function(i){return i.type; }).join(); 203 method.name = displayName + '(' + typeName + ')'; 204 } 205 }); 206 207 var result = {}; 208 addFunctionRelatedPropertiesToContract(result); 209 addFunctionsToContract(result, desc, address); 210 addEventRelatedPropertiesToContract(result, desc, address); 211 addEventsToContract(result, desc, address); 212 213 return result; 214 }; 215 216 module.exports = contract; 217