diff options
Diffstat (limited to 'cmd/mist/assets/ext/ethereum.js/lib/abi.js')
-rw-r--r-- | cmd/mist/assets/ext/ethereum.js/lib/abi.js | 335 |
1 files changed, 139 insertions, 196 deletions
diff --git a/cmd/mist/assets/ext/ethereum.js/lib/abi.js b/cmd/mist/assets/ext/ethereum.js/lib/abi.js index 1912fff32..1a92bf5e6 100644 --- a/cmd/mist/assets/ext/ethereum.js/lib/abi.js +++ b/cmd/mist/assets/ext/ethereum.js/lib/abi.js @@ -21,247 +21,190 @@ * @date 2014 */ -// TODO: is these line is supposed to be here? -if (process.env.NODE_ENV !== 'build') { - var web3 = require('./web3'); // jshint ignore:line -} - -// TODO: make these be actually accurate instead of falling back onto JS's doubles. -var hexToDec = function (hex) { - return parseInt(hex, 16).toString(); +var web3 = require('./web3'); +var utils = require('./utils'); +var types = require('./types'); +var c = require('./const'); +var f = require('./formatters'); + +var displayTypeError = function (type) { + console.error('parser does not support type: ' + type); }; -var decToHex = function (dec) { - return parseInt(dec).toString(16); +/// 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) === '[]'; }; -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; +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 f.formatInputInt(value.length); + return ""; }; -var findMethodIndex = function (json, methodName) { - return findIndex(json, function (method) { - return method.name === methodName; - }); -}; - -var padLeft = function (string, chars) { - return new Array(chars - string.length + 1).join("0") + string; -}; - -var calcBitPadding = function (type, expected) { - var value = type.slice(expected.length); - if (value === "") { - return 32; - } - return parseInt(value) / 8; -}; - -var calcBytePadding = function (type, expected) { - var value = type.slice(expected.length); - if (value === "") { - return 32; - } - return parseInt(value); -}; - -var calcRealPadding = function (type, expected) { - var value = type.slice(expected.length); - if (value === "") { - return 32; - } - var sizes = value.split('x'); - for (var padding = 0, i = 0; i < sizes; i++) { - padding += (sizes[i] / 8); - } - return padding; -}; - -var setupInputTypes = function () { - - var prefixedType = function (prefix, calcPadding) { - return function (type, value) { - var expected = prefix; - if (type.indexOf(expected) !== 0) { - return false; - } - - var padding = calcPadding(type, expected); - if (typeof value === "number") - value = value.toString(16); - else if (typeof value === "string") - value = web3.toHex(value); - else if (value.indexOf('0x') === 0) - value = value.substr(2); - else - value = (+value).toString(16); - return padLeft(value, padding * 2); - }; - }; +var inputTypes = types.inputTypes(); - var namedType = function (name, padding, formatter) { - return function (type, value) { - if (type !== name) { - return false; - } - - return padLeft(formatter ? formatter(value) : value, padding * 2); - }; - }; - - var formatBool = function (value) { - return value ? '0x1' : '0x0'; - }; - - return [ - prefixedType('uint', calcBitPadding), - prefixedType('int', calcBitPadding), - prefixedType('hash', calcBitPadding), - prefixedType('string', calcBytePadding), - prefixedType('real', calcRealPadding), - prefixedType('ureal', calcRealPadding), - namedType('address', 20), - namedType('bool', 1, formatBool), - ]; -}; - -var inputTypes = setupInputTypes(); - -var toAbiInput = function (json, methodName, params) { +/// Formats input params to bytes +/// @param abi contract method inputs +/// @param array of params that will be formatted to bytes +/// @returns bytes representation of input params +var formatInput = function (inputs, params) { var bytes = ""; - var index = findMethodIndex(json, methodName); - - if (index === -1) { - return; - } + var padding = c.ETH_PADDING * 2; - bytes = "0x" + padLeft(index.toString(16), 2); - var method = json[index]; + /// first we iterate in search for dynamic + inputs.forEach(function (input, index) { + bytes += dynamicTypeBytes(input.type, params[index]); + }); - for (var i = 0; i < method.inputs.length; i++) { - var found = false; - for (var j = 0; j < inputTypes.length && !found; j++) { - found = inputTypes[j](method.inputs[i].type, params[i]); + inputs.forEach(function (input, i) { + var typeMatch = false; + for (var j = 0; j < inputTypes.length && !typeMatch; j++) { + typeMatch = inputTypes[j].type(inputs[i].type, params[i]); } - if (!found) { - console.error('unsupported json type: ' + method.inputs[i].type); + if (!typeMatch) { + displayTypeError(inputs[i].type); } - bytes += found; - } - return bytes; -}; -var setupOutputTypes = function () { + var formatter = inputTypes[j - 1].format; + var toAppend = ""; - var prefixedType = function (prefix, calcPadding) { - return function (type) { - var expected = prefix; - if (type.indexOf(expected) !== 0) { - return -1; - } + if (arrayType(inputs[i].type)) + toAppend = params[i].reduce(function (acc, curr) { + return acc + formatter(curr); + }, ""); + else + toAppend = formatter(params[i]); - var padding = calcPadding(type, expected); - return padding * 2; - }; - }; - - var namedType = function (name, padding) { - return function (type) { - return name === type ? padding * 2 : -1; - }; - }; - - var formatInt = function (value) { - return value.length <= 8 ? +parseInt(value, 16) : hexToDec(value); - }; - - var formatHash = function (value) { - return "0x" + value; - }; - - var formatBool = function (value) { - return value === '1' ? true : false; - }; - - var formatString = function (value) { - return web3.toAscii(value); - }; - - return [ - { padding: prefixedType('uint', calcBitPadding), format: formatInt }, - { padding: prefixedType('int', calcBitPadding), format: formatInt }, - { padding: prefixedType('hash', calcBitPadding), format: formatHash }, - { padding: prefixedType('string', calcBytePadding), format: formatString }, - { padding: prefixedType('real', calcRealPadding), format: formatInt }, - { padding: prefixedType('ureal', calcRealPadding), format: formatInt }, - { padding: namedType('address', 20) }, - { padding: namedType('bool', 1), format: formatBool } - ]; + bytes += toAppend; + }); + return bytes; }; -var outputTypes = setupOutputTypes(); - -var fromAbiOutput = function (json, methodName, output) { - var index = findMethodIndex(json, methodName); +var dynamicBytesLength = function (type) { + if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length. + return c.ETH_PADDING * 2; + return 0; +}; - if (index === -1) { - return; - } +var outputTypes = types.outputTypes(); +/// Formats output bytes back to param list +/// @param contract abi method outputs +/// @param bytes representtion of output +/// @returns array of output params +var formatOutput = function (outs, output) { + output = output.slice(2); - var result = []; - var method = json[index]; - for (var i = 0; i < method.outputs.length; i++) { - var padding = -1; - for (var j = 0; j < outputTypes.length && padding === -1; j++) { - padding = outputTypes[j].padding(method.outputs[i].type); + var padding = c.ETH_PADDING * 2; + + var dynamicPartLength = outs.reduce(function (acc, curr) { + return acc + dynamicBytesLength(curr.type); + }, 0); + + var dynamicPart = output.slice(0, dynamicPartLength); + output = output.slice(dynamicPartLength); + + outs.forEach(function (out, i) { + var typeMatch = false; + for (var j = 0; j < outputTypes.length && !typeMatch; j++) { + typeMatch = outputTypes[j].type(outs[i].type); } - if (padding === -1) { - // not found output parsing - continue; + if (!typeMatch) { + displayTypeError(outs[i].type); } - var res = output.slice(0, padding); + var formatter = outputTypes[j - 1].format; - result.push(formatter ? formatter(res) : ("0x" + res)); - output = output.slice(padding); - } + if (arrayType(outs[i].type)) { + var size = f.formatOutputUInt(dynamicPart.slice(0, padding)); + dynamicPart = dynamicPart.slice(padding); + var array = []; + for (var k = 0; k < size; k++) { + array.push(formatter(output.slice(0, padding))); + output = output.slice(padding); + } + result.push(array); + } + else if (types.prefixedType('string')(outs[i].type)) { + dynamicPart = dynamicPart.slice(padding); + result.push(formatter(output.slice(0, padding))); + output = output.slice(padding); + } else { + result.push(formatter(output.slice(0, padding))); + output = output.slice(padding); + } + }); return result; }; +/// @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) { - parser[method.name] = function () { + var displayName = utils.extractDisplayName(method.name); + var typeName = utils.extractTypeName(method.name); + + var impl = function () { var params = Array.prototype.slice.call(arguments); - return toAbiInput(json, method.name, params); + return formatInput(method.inputs, params); }; + + if (parser[displayName] === undefined) { + parser[displayName] = impl; + } + + parser[displayName][typeName] = impl; }); return parser; }; +/// @param json abi for contract +/// @returns output parser for given json abi var outputParser = function (json) { var parser = {}; json.forEach(function (method) { - parser[method.name] = function (output) { - return fromAbiOutput(json, method.name, output); + + var displayName = utils.extractDisplayName(method.name); + var typeName = utils.extractTypeName(method.name); + + var impl = function (output) { + return formatOutput(method.outputs, output); }; + + if (parser[displayName] === undefined) { + parser[displayName] = impl; + } + + parser[displayName][typeName] = impl; }); return parser; }; -if (typeof(module) !== "undefined") { - module.exports = { - inputParser: inputParser, - outputParser: outputParser - }; -} +/// @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); +}; + +var eventSignatureFromAscii = function (name) { + return web3.sha3(web3.fromAscii(name)); +}; + +module.exports = { + inputParser: inputParser, + outputParser: outputParser, + formatInput: formatInput, + formatOutput: formatOutput, + signatureFromAscii: signatureFromAscii, + eventSignatureFromAscii: eventSignatureFromAscii +}; + |