aboutsummaryrefslogtreecommitdiffstats
path: root/lib/abi.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/abi.js')
-rw-r--r--lib/abi.js256
1 files changed, 150 insertions, 106 deletions
diff --git a/lib/abi.js b/lib/abi.js
index 5a01f43fd..319b06066 100644
--- a/lib/abi.js
+++ b/lib/abi.js
@@ -32,15 +32,6 @@ BigNumber.config({ ROUNDING_MODE: BigNumber.ROUND_DOWN });
var ETH_PADDING = 32;
-// TODO: make these be actually accurate instead of falling back onto JS's doubles.
-var hexToDec = function (hex) {
- return parseInt(hex, 16).toString();
-};
-
-var decToHex = function (dec) {
- return parseInt(dec).toString(16);
-};
-
/// Finds first index of array element matching pattern
/// @param array
/// @param callback pattern
@@ -85,55 +76,66 @@ var namedType = function (name) {
};
};
+var arrayType = function (type) {
+ return type.slice(-2) === '[]';
+};
+
+/// Formats input value to byte representation of int
+/// If value is negative, return it's two's complement
+/// If the value is floating point, round it down
+/// @returns right-aligned byte representation of int
+var formatInputInt = function (value) {
+ var padding = ETH_PADDING * 2;
+ if (value instanceof BigNumber || typeof value === 'number') {
+ if (typeof value === 'number')
+ value = new BigNumber(value);
+ value = value.round();
+
+ if (value.lessThan(0))
+ value = new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).plus(value).plus(1);
+ value = value.toString(16);
+ }
+ else if (value.indexOf('0x') === 0)
+ value = value.substr(2);
+ else if (typeof value === 'string')
+ value = formatInputInt(new BigNumber(value));
+ else
+ value = (+value).toString(16);
+ return padLeft(value, padding);
+};
+
+/// Formats input value to byte representation of string
+/// @returns left-algined byte representation of string
+var formatInputString = function (value) {
+ return web3.fromAscii(value, ETH_PADDING).substr(2);
+};
+
+/// Formats input value to byte representation of bool
+/// @returns right-aligned byte representation bool
+var formatInputBool = function (value) {
+ return '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0');
+};
+
+var dynamicTypeBytes = function (type, value) {
+ // TODO: decide what to do with array of strings
+ if (arrayType(type) || prefixedType('string')(type))
+ return formatInputInt(value.length);
+ return "";
+};
+
/// Setups input formatters for solidity types
/// @returns an array of input formatters
var setupInputTypes = function () {
- /// Formats input value to byte representation of int
- /// If value is negative, return it's two's complement
- /// If the value is floating point, round it down
- /// @returns right-aligned byte representation of int
- var formatInt = function (value) {
- var padding = ETH_PADDING * 2;
- if (value instanceof BigNumber || typeof value === 'number') {
- if (typeof value === 'number')
- value = new BigNumber(value);
- value = value.round();
-
- if (value.lessThan(0))
- value = new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).plus(value).plus(1);
- value = value.toString(16);
- }
- else if (value.indexOf('0x') === 0)
- value = value.substr(2);
- else if (typeof value === 'string')
- value = formatInt(new BigNumber(value));
- else
- value = (+value).toString(16);
- return padLeft(value, padding);
- };
-
- /// Formats input value to byte representation of string
- /// @returns left-algined byte representation of string
- var formatString = function (value) {
- return web3.fromAscii(value, ETH_PADDING).substr(2);
- };
-
- /// Formats input value to byte representation of bool
- /// @returns right-aligned byte representation bool
- var formatBool = function (value) {
- return '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0');
- };
-
return [
- { 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 }
+ { type: prefixedType('uint'), format: formatInputInt },
+ { type: prefixedType('int'), format: formatInputInt },
+ { type: prefixedType('hash'), format: formatInputInt },
+ { type: prefixedType('string'), format: formatInputString },
+ { type: prefixedType('real'), format: formatInputInt },
+ { type: prefixedType('ureal'), format: formatInputInt },
+ { type: namedType('address'), format: formatInputInt },
+ { type: namedType('bool'), format: formatInputBool }
];
};
@@ -155,7 +157,12 @@ var toAbiInput = function (json, methodName, params) {
var method = json[index];
var padding = ETH_PADDING * 2;
- for (var i = 0; i < method.inputs.length; i++) {
+ /// first we iterate in search for dynamic
+ method.inputs.forEach(function (input, index) {
+ bytes += dynamicTypeBytes(input.type, params[index]);
+ });
+
+ method.inputs.forEach(function (input, i) {
var typeMatch = false;
for (var j = 0; j < inputTypes.length && !typeMatch; j++) {
typeMatch = inputTypes[j].type(method.inputs[i].type, params[i]);
@@ -165,62 +172,77 @@ var toAbiInput = function (json, methodName, params) {
}
var formatter = inputTypes[j - 1].format;
- bytes += (formatter ? formatter(params[i]) : params[i]);
- }
+ var toAppend = "";
+
+ if (arrayType(method.inputs[i].type))
+ toAppend = params[i].reduce(function (acc, curr) {
+ return acc + formatter(curr);
+ }, "");
+ else
+ toAppend = formatter(params[i]);
+
+ bytes += toAppend;
+ });
return bytes;
};
-/// Setups output formaters for solidity types
-/// @returns an array of output formatters
-var setupOutputTypes = function () {
+/// Formats input right-aligned input bytes to int
+/// @returns right-aligned input bytes formatted to int
+var formatOutputInt = function (value) {
+ // check if it's negative number
+ // it it is, return two's complement
+ var firstBit = new BigNumber(value.substr(0, 1), 16).toString(2).substr(0, 1);
+ if (firstBit === '1') {
+ return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1);
+ }
+ return new BigNumber(value, 16);
+};
- /// Formats input right-aligned input bytes to int
- /// @returns right-aligned input bytes formatted to int
- var formatInt = function (value) {
- // check if it's negative number
- // it it is, return two's complement
- var firstBit = new BigNumber(value.substr(0, 1), 16).toString(2).substr(0, 1);
- if (firstBit === '1') {
- return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1);
- }
- return new BigNumber(value, 16);
- };
+/// Formats big right-aligned input bytes to uint
+/// @returns right-aligned input bytes formatted to uint
+var formatOutputUInt = function (value) {
+ return new BigNumber(value, 16);
+};
- /// Formats big right-aligned input bytes to uint
- /// @returns right-aligned input bytes formatted to uint
- var formatUInt = function (value) {
- return new BigNumber(value, 16);
- };
+/// @returns right-aligned input bytes formatted to hex
+var formatOutputHash = function (value) {
+ return "0x" + 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 formatOutputBool = function (value) {
+ return value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false;
+};
- /// @returns right-aligned input bytes formatted to bool
- var formatBool = function (value) {
- return value === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false;
- };
+/// @returns left-aligned input bytes formatted to ascii string
+var formatOutputString = function (value) {
+ return web3.toAscii(value);
+};
- /// @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 formatOutputAddress = function (value) {
+ return "0x" + value.slice(value.length - 40, value.length);
+};
- /// @returns right-aligned input bytes formatted to address
- var formatAddress = function (value) {
- return "0x" + value.slice(value.length - 40, value.length);
- };
+var dynamicBytesLength = function (type) {
+ if (arrayType(type) || prefixedType('string')(type))
+ return ETH_PADDING * 2;
+ return 0;
+};
+
+/// Setups output formaters for solidity types
+/// @returns an array of output formatters
+var setupOutputTypes = function () {
return [
- { type: prefixedType('uint'), format: formatUInt },
- { 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 }
+ { type: prefixedType('uint'), format: formatOutputUInt },
+ { type: prefixedType('int'), format: formatOutputInt },
+ { type: prefixedType('hash'), format: formatOutputHash },
+ { type: prefixedType('string'), format: formatOutputString },
+ { type: prefixedType('real'), format: formatOutputInt },
+ { type: prefixedType('ureal'), format: formatOutputInt },
+ { type: namedType('address'), format: formatOutputAddress },
+ { type: namedType('bool'), format: formatOutputBool }
];
};
@@ -243,22 +265,44 @@ var fromAbiOutput = function (json, methodName, output) {
var result = [];
var method = json[index];
var padding = ETH_PADDING * 2;
- for (var i = 0; i < method.outputs.length; i++) {
+
+ var dynamicPartLength = method.outputs.reduce(function (acc, curr) {
+ return acc + dynamicBytesLength(curr.type);
+ }, 0);
+
+ var dynamicPart = output.slice(0, dynamicPartLength);
+ output = output.slice(dynamicPartLength);
+
+ method.outputs.forEach(function (out, i) {
var typeMatch = false;
for (var j = 0; j < outputTypes.length && !typeMatch; j++) {
typeMatch = outputTypes[j].type(method.outputs[i].type);
}
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);
+
var formatter = outputTypes[j - 1].format;
- result.push(formatter ? formatter(res) : ("0x" + res));
- output = output.slice(padding);
- }
+ if (arrayType(method.outputs[i].type)) {
+ var size = 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 (prefixedType('string')(method.outputs[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;
};