aboutsummaryrefslogtreecommitdiffstats
path: root/cmd/mist/assets/ext/ethereum.js/lib/abi.js
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/mist/assets/ext/ethereum.js/lib/abi.js')
-rw-r--r--cmd/mist/assets/ext/ethereum.js/lib/abi.js335
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
+};
+