UNPKG

10.9 kBJavaScriptView Raw
1/*
2 This file is part of web3.js.
3
4 web3.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 web3.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 web3.js. If not, see <http://www.gnu.org/licenses/>.
16 */
17/**
18 * @file utils.js
19 * @author Marek Kotewicz <marek@parity.io>
20 * @author Fabian Vogelsteller <fabian@ethereum.org>
21 * @date 2017
22 */
23
24
25var _ = require('underscore');
26var ethjsUnit = require('ethjs-unit');
27var utils = require('./utils.js');
28var soliditySha3 = require('./soliditySha3.js');
29var randomHex = require('randomhex');
30
31
32
33/**
34 * Fires an error in an event emitter and callback and returns the eventemitter
35 *
36 * @method _fireError
37 * @param {Object} error a string, a error, or an object with {message, data}
38 * @param {Object} emitter
39 * @param {Function} reject
40 * @param {Function} callback
41 * @return {Object} the emitter
42 */
43var _fireError = function (error, emitter, reject, callback) {
44 /*jshint maxcomplexity: 10 */
45
46 // add data if given
47 if(_.isObject(error) && !(error instanceof Error) && error.data) {
48 if(_.isObject(error.data) || _.isArray(error.data)) {
49 error.data = JSON.stringify(error.data, null, 2);
50 }
51
52 error = error.message +"\n"+ error.data;
53 }
54
55 if(_.isString(error)) {
56 error = new Error(error);
57 }
58
59 if (_.isFunction(callback)) {
60 callback(error);
61 }
62 if (_.isFunction(reject)) {
63 // suppress uncatched error if an error listener is present
64 // OR suppress uncatched error if an callback listener is present
65 if (emitter &&
66 (_.isFunction(emitter.listeners) &&
67 emitter.listeners('error').length) || _.isFunction(callback)) {
68 emitter.catch(function(){});
69 }
70 // reject later, to be able to return emitter
71 setTimeout(function () {
72 reject(error);
73 }, 1);
74 }
75
76 if(emitter && _.isFunction(emitter.emit)) {
77 // emit later, to be able to return emitter
78 setTimeout(function () {
79 emitter.emit('error', error);
80 emitter.removeAllListeners();
81 }, 1);
82 }
83
84 return emitter;
85};
86
87/**
88 * Should be used to create full function/event name from json abi
89 *
90 * @method _jsonInterfaceMethodToString
91 * @param {Object} json
92 * @return {String} full function/event name
93 */
94var _jsonInterfaceMethodToString = function (json) {
95 if (_.isObject(json) && json.name && json.name.indexOf('(') !== -1) {
96 return json.name;
97 }
98
99 return json.name + '(' + _flattenTypes(false, json.inputs).join(',') + ')';
100};
101
102
103/**
104 * Should be used to flatten json abi inputs/outputs into an array of type-representing-strings
105 *
106 * @method _flattenTypes
107 * @param {bool} includeTuple
108 * @param {Object} puts
109 * @return {Array} parameters as strings
110 */
111var _flattenTypes = function(includeTuple, puts)
112{
113 // console.log("entered _flattenTypes. inputs/outputs: " + puts)
114 var types = [];
115
116 puts.forEach(function(param) {
117 if (typeof param.components === 'object') {
118 if (param.type.substring(0, 5) !== 'tuple') {
119 throw new Error('components found but type is not tuple; report on GitHub');
120 }
121 var suffix = '';
122 var arrayBracket = param.type.indexOf('[');
123 if (arrayBracket >= 0) { suffix = param.type.substring(arrayBracket); }
124 var result = _flattenTypes(includeTuple, param.components);
125 // console.log("result should have things: " + result)
126 if(_.isArray(result) && includeTuple) {
127 // console.log("include tuple word, and its an array. joining...: " + result.types)
128 types.push('tuple(' + result.join(',') + ')' + suffix);
129 }
130 else if(!includeTuple) {
131 // console.log("don't include tuple, but its an array. joining...: " + result)
132 types.push('(' + result.join(',') + ')' + suffix);
133 }
134 else {
135 // console.log("its a single type within a tuple: " + result.types)
136 types.push('(' + result + ')');
137 }
138 } else {
139 // console.log("its a type and not directly in a tuple: " + param.type)
140 types.push(param.type);
141 }
142 });
143
144 return types;
145};
146
147
148/**
149 * Should be called to get ascii from it's hex representation
150 *
151 * @method hexToAscii
152 * @param {String} hex
153 * @returns {String} ascii string representation of hex value
154 */
155var hexToAscii = function(hex) {
156 if (!utils.isHexStrict(hex))
157 throw new Error('The parameter must be a valid HEX string.');
158
159 var str = "";
160 var i = 0, l = hex.length;
161 if (hex.substring(0, 2) === '0x') {
162 i = 2;
163 }
164 for (; i < l; i+=2) {
165 var code = parseInt(hex.substr(i, 2), 16);
166 str += String.fromCharCode(code);
167 }
168
169 return str;
170};
171
172/**
173 * Should be called to get hex representation (prefixed by 0x) of ascii string
174 *
175 * @method asciiToHex
176 * @param {String} str
177 * @returns {String} hex representation of input string
178 */
179var asciiToHex = function(str) {
180 if(!str)
181 return "0x00";
182 var hex = "";
183 for(var i = 0; i < str.length; i++) {
184 var code = str.charCodeAt(i);
185 var n = code.toString(16);
186 hex += n.length < 2 ? '0' + n : n;
187 }
188
189 return "0x" + hex;
190};
191
192
193
194/**
195 * Returns value of unit in Wei
196 *
197 * @method getUnitValue
198 * @param {String} unit the unit to convert to, default ether
199 * @returns {BN} value of the unit (in Wei)
200 * @throws error if the unit is not correct:w
201 */
202var getUnitValue = function (unit) {
203 unit = unit ? unit.toLowerCase() : 'ether';
204 if (!ethjsUnit.unitMap[unit]) {
205 throw new Error('This unit "'+ unit +'" doesn\'t exist, please use the one of the following units' + JSON.stringify(ethjsUnit.unitMap, null, 2));
206 }
207 return unit;
208};
209
210/**
211 * Takes a number of wei and converts it to any other ether unit.
212 *
213 * Possible units are:
214 * SI Short SI Full Effigy Other
215 * - kwei femtoether babbage
216 * - mwei picoether lovelace
217 * - gwei nanoether shannon nano
218 * - -- microether szabo micro
219 * - -- milliether finney milli
220 * - ether -- --
221 * - kether -- grand
222 * - mether
223 * - gether
224 * - tether
225 *
226 * @method fromWei
227 * @param {Number|String} number can be a number, number string or a HEX of a decimal
228 * @param {String} unit the unit to convert to, default ether
229 * @return {String|Object} When given a BN object it returns one as well, otherwise a number
230 */
231var fromWei = function(number, unit) {
232 unit = getUnitValue(unit);
233
234 if(!utils.isBN(number) && !_.isString(number)) {
235 throw new Error('Please pass numbers as strings or BigNumber objects to avoid precision errors.');
236 }
237
238 return utils.isBN(number) ? ethjsUnit.fromWei(number, unit) : ethjsUnit.fromWei(number, unit).toString(10);
239};
240
241/**
242 * Takes a number of a unit and converts it to wei.
243 *
244 * Possible units are:
245 * SI Short SI Full Effigy Other
246 * - kwei femtoether babbage
247 * - mwei picoether lovelace
248 * - gwei nanoether shannon nano
249 * - -- microether szabo micro
250 * - -- microether szabo micro
251 * - -- milliether finney milli
252 * - ether -- --
253 * - kether -- grand
254 * - mether
255 * - gether
256 * - tether
257 *
258 * @method toWei
259 * @param {Number|String|BN} number can be a number, number string or a HEX of a decimal
260 * @param {String} unit the unit to convert from, default ether
261 * @return {String|Object} When given a BN object it returns one as well, otherwise a number
262 */
263var toWei = function(number, unit) {
264 unit = getUnitValue(unit);
265
266 if(!utils.isBN(number) && !_.isString(number)) {
267 throw new Error('Please pass numbers as strings or BigNumber objects to avoid precision errors.');
268 }
269
270 return utils.isBN(number) ? ethjsUnit.toWei(number, unit) : ethjsUnit.toWei(number, unit).toString(10);
271};
272
273
274
275
276/**
277 * Converts to a checksum address
278 *
279 * @method toChecksumAddress
280 * @param {String} address the given HEX address
281 * @return {String}
282 */
283var toChecksumAddress = function (address) {
284 if (typeof address === 'undefined') return '';
285
286 if(!/^(0x)?[0-9a-f]{40}$/i.test(address))
287 throw new Error('Given address "'+ address +'" is not a valid Ethereum address.');
288
289
290
291 address = address.toLowerCase().replace(/^0x/i,'');
292 var addressHash = utils.sha3(address).replace(/^0x/i,'');
293 var checksumAddress = '0x';
294
295 for (var i = 0; i < address.length; i++ ) {
296 // If ith character is 9 to f then make it uppercase
297 if (parseInt(addressHash[i], 16) > 7) {
298 checksumAddress += address[i].toUpperCase();
299 } else {
300 checksumAddress += address[i];
301 }
302 }
303 return checksumAddress;
304};
305
306
307
308module.exports = {
309 _fireError: _fireError,
310 _jsonInterfaceMethodToString: _jsonInterfaceMethodToString,
311 _flattenTypes: _flattenTypes,
312 // extractDisplayName: extractDisplayName,
313 // extractTypeName: extractTypeName,
314 randomHex: randomHex,
315 _: _,
316 BN: utils.BN,
317 isBN: utils.isBN,
318 isBigNumber: utils.isBigNumber,
319 isHex: utils.isHex,
320 isHexStrict: utils.isHexStrict,
321 sha3: utils.sha3,
322 keccak256: utils.sha3,
323 soliditySha3: soliditySha3,
324 isAddress: utils.isAddress,
325 checkAddressChecksum: utils.checkAddressChecksum,
326 toChecksumAddress: toChecksumAddress,
327 toHex: utils.toHex,
328 toBN: utils.toBN,
329
330 bytesToHex: utils.bytesToHex,
331 hexToBytes: utils.hexToBytes,
332
333 hexToNumberString: utils.hexToNumberString,
334
335 hexToNumber: utils.hexToNumber,
336 toDecimal: utils.hexToNumber, // alias
337
338 numberToHex: utils.numberToHex,
339 fromDecimal: utils.numberToHex, // alias
340
341 hexToUtf8: utils.hexToUtf8,
342 hexToString: utils.hexToUtf8,
343 toUtf8: utils.hexToUtf8,
344
345 utf8ToHex: utils.utf8ToHex,
346 stringToHex: utils.utf8ToHex,
347 fromUtf8: utils.utf8ToHex,
348
349 hexToAscii: hexToAscii,
350 toAscii: hexToAscii,
351 asciiToHex: asciiToHex,
352 fromAscii: asciiToHex,
353
354 unitMap: ethjsUnit.unitMap,
355 toWei: toWei,
356 fromWei: fromWei,
357
358 padLeft: utils.leftPad,
359 leftPad: utils.leftPad,
360 padRight: utils.rightPad,
361 rightPad: utils.rightPad,
362 toTwosComplement: utils.toTwosComplement
363};
364