aboutsummaryrefslogtreecommitdiffstats
path: root/lib/abi.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/abi.js')
-rw-r--r--lib/abi.js225
1 files changed, 113 insertions, 112 deletions
diff --git a/lib/abi.js b/lib/abi.js
index 1a88317bc..b51fbab59 100644
--- a/lib/abi.js
+++ b/lib/abi.js
@@ -35,6 +35,10 @@ var decToHex = function (dec) {
return parseInt(dec).toString(16);
};
+/// Finds first index of array element matching pattern
+/// @param array
+/// @param callback pattern
+/// @returns index of element
var findIndex = function (array, callback) {
var end = false;
var i = 0;
@@ -44,106 +48,96 @@ var findIndex = function (array, callback) {
return end ? i - 1 : -1;
};
+/// @returns a function that is used as a pattern for 'findIndex'
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;
+/// @param string string to be padded
+/// @param number of characters that result string should have
+/// @param sign, by default 0
+/// @returns right aligned string
+var padLeft = function (string, chars, sign) {
+ return new Array(chars - string.length + 1).join(sign ? sign : "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);
+/// @param expected type prefix (string)
+/// @returns function which checks if type has matching prefix. if yes, returns true, otherwise false
+var prefixedType = function (prefix) {
+ return function (type) {
+ return type.indexOf(prefix) === 0;
+ };
};
-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;
+/// @param expected type name (string)
+/// @returns function which checks if type is matching expected one. if yes, returns true, otherwise false
+var namedType = function (name) {
+ return function (type) {
+ return name === type;
+ };
};
+/// Setups input formatters for solidity types
+/// @returns an array of input formatters
var setupInputTypes = function () {
- // convert from int, decimal-string, prefixed hex string whatever into a bare hex string.
- var formatStandard = function (value) {
- if (typeof value === "number")
- return value.toString(16);
- else if (typeof value === "string" && value.indexOf('0x') === 0)
- return value.substr(2);
- else if (typeof value === "string")
- return web3.toHex(value);
- else
- return (+value).toString(16);
- };
-
- var prefixedType = function (prefix, calcPadding) {
- return function (type, value) {
- var expected = prefix;
- if (type.indexOf(expected) !== 0) {
- return false;
+ /// Formats input value to byte representation of int
+ /// @returns right-aligned byte representation of int
+ var formatInt = function (value) {
+ var padding = 32 * 2;
+ if (typeof value === 'number') {
+ if (value < 0) {
+
+ // two's complement
+ // TODO: fix big numbers support
+ value = ((value) >>> 0).toString(16);
+ return padLeft(value, padding, 'f');
}
+ value = value.toString(16);
- var padding = calcPadding(type, expected);
- if (padding > 32)
- return false; // not allowed to be so big.
- padding = 32; // override as per the new ABI.
-
- if (prefix === "string")
- return web3.fromAscii(value, padding).substr(2);
- return padLeft(formatStandard(value), padding * 2);
- };
+ }
+ else if (value.indexOf('0x') === 0)
+ value = value.substr(2);
+ else if (typeof value === 'string')
+ value = value.toHex(value);
+ else
+ value = (+value).toString(16);
+ return padLeft(value, padding);
};
- var namedType = function (name, padding, formatter) {
- return function (type, value) {
- if (type !== name) {
- return false;
- }
-
- padding = 32; //override as per the new ABI.
-
- return padLeft(formatter ? formatter(value) : value, padding * 2);
- };
+ /// Formats input value to byte representation of string
+ /// @returns left-algined byte representation of string
+ var formatString = function (value) {
+ return web3.fromAscii(value, 32).substr(2);
};
+ /// Formats input value to byte representation of bool
+ /// @returns right-aligned byte representation bool
var formatBool = function (value) {
- return value ? '01' : '00';
+ return '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0');
};
return [
- prefixedType('uint', calcBitPadding),
- prefixedType('int', calcBitPadding),
- prefixedType('hash', calcBitPadding),
- prefixedType('string', calcBytePadding),
- prefixedType('real', calcRealPadding),
- prefixedType('ureal', calcRealPadding),
- namedType('address', 20, formatStandard),
- namedType('bool', 1, formatBool),
+ { type: prefixedType('uint'), format: formatInt },
+ { type: prefixedType('int'), format: formatInt },
+ { type: prefixedType('hash'), format: formatInt },
+ { type: prefixedType('string'), format: formatString },
+ { type: prefixedType('real'), format: formatInt },
+ { type: prefixedType('ureal'), format: formatInt },
+ { type: namedType('address'), format: formatInt },
+ { type: namedType('bool'), format: formatBool }
];
};
var inputTypes = setupInputTypes();
+/// Formats input params to bytes
+/// @param contract json abi
+/// @param name of the method that we want to use
+/// @param array of params that will be formatted to bytes
+/// @returns bytes representation of input params
var toAbiInput = function (json, methodName, params) {
var bytes = "";
var index = findMethodIndex(json, methodName);
@@ -153,74 +147,72 @@ var toAbiInput = function (json, methodName, params) {
}
var method = json[index];
+ var padding = 32 * 2;
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]);
+ var typeMatch = false;
+ for (var j = 0; j < inputTypes.length && !typeMatch; j++) {
+ typeMatch = inputTypes[j].type(method.inputs[i].type, params[i]);
}
- if (!found) {
- console.error('unsupported json type: ' + method.inputs[i].type);
+ if (!typeMatch) {
+ console.error('input parser does not support type: ' + method.inputs[i].type);
}
- bytes += found;
+
+ var formatter = inputTypes[j - 1].format;
+ bytes += (formatter ? formatter(params[i]) : params[i]);
}
return bytes;
};
+/// Setups output formaters for solidity types
+/// @returns an array of output formatters
var setupOutputTypes = function () {
- var prefixedType = function (prefix, calcPadding) {
- return function (type) {
- var expected = prefix;
- if (type.indexOf(expected) !== 0) {
- return -1;
- }
-
- var padding = calcPadding(type, expected);
- if (padding > 32)
- return -1; // not allowed to be so big.
- padding = 32; // override as per the new ABI.
- return padding * 2;
- };
- };
-
- var namedType = function (name, padding) {
- return function (type) {
- padding = 32; // override as per the new ABI.
- return name === type ? padding * 2 : -1;
- };
- };
-
+ /// Formats input right-aligned input bytes to int
+ /// @returns right-aligned input bytes formatted to int
var formatInt = function (value) {
return value.length <= 8 ? +parseInt(value, 16) : hexToDec(value);
};
+ /// @returns right-aligned input bytes formatted to hex
var formatHash = function (value) {
return "0x" + value;
};
+ /// @returns right-aligned input bytes formatted to bool
var formatBool = function (value) {
- return value === '1' ? true : false;
+ return value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false;
};
+ /// @returns left-aligned input bytes formatted to ascii string
var formatString = function (value) {
return web3.toAscii(value);
};
+ /// @returns right-aligned input bytes formatted to address
+ var formatAddress = function (value) {
+ return "0x" + value.slice(value.length - 40, value.length);
+ };
+
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 }
+ { type: prefixedType('uint'), format: formatInt },
+ { type: prefixedType('int'), format: formatInt },
+ { type: prefixedType('hash'), format: formatHash },
+ { type: prefixedType('string'), format: formatString },
+ { type: prefixedType('real'), format: formatInt },
+ { type: prefixedType('ureal'), format: formatInt },
+ { type: namedType('address'), format: formatAddress },
+ { type: namedType('bool'), format: formatBool }
];
};
var outputTypes = setupOutputTypes();
+/// Formats output bytes back to param list
+/// @param contract json abi
+/// @param name of the method that we want to use
+/// @param bytes representtion of output
+/// @returns array of output params
var fromAbiOutput = function (json, methodName, output) {
var index = findMethodIndex(json, methodName);
@@ -232,14 +224,16 @@ var fromAbiOutput = function (json, methodName, output) {
var result = [];
var method = json[index];
+ var padding = 32 * 2;
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 typeMatch = false;
+ for (var j = 0; j < outputTypes.length && !typeMatch; j++) {
+ typeMatch = outputTypes[j].type(method.outputs[i].type);
}
- if (padding === -1) {
+ if (!typeMatch) {
// not found output parsing
+ console.error('output parser does not support type: ' + method.outputs[i].type);
continue;
}
var res = output.slice(0, padding);
@@ -251,6 +245,8 @@ var fromAbiOutput = function (json, methodName, output) {
return result;
};
+/// @param json abi for contract
+/// @returns input parser object for given json abi
var inputParser = function (json) {
var parser = {};
json.forEach(function (method) {
@@ -263,6 +259,8 @@ var inputParser = function (json) {
return parser;
};
+/// @param json abi for contract
+/// @returns output parser for given json abi
var outputParser = function (json) {
var parser = {};
json.forEach(function (method) {
@@ -274,6 +272,9 @@ var outputParser = function (json) {
return parser;
};
+/// @param json abi for contract
+/// @param method name for which we want to get method signature
+/// @returns (promise) contract method signature for method with given name
var methodSignature = function (json, name) {
var method = json[findMethodIndex(json, name)];
var result = name + '(';