web3.js/lib/abi.js

201 lines
6.1 KiB
JavaScript
Raw Normal View History

2014-11-14 12:11:47 +00:00
/*
This file is part of ethereum.js.
ethereum.js is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethereum.js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ethereum.js. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file abi.js
* @authors:
* Marek Kotewicz <marek@ethdev.com>
2014-12-22 00:13:49 +00:00
* Gav Wood <g@ethdev.com>
2014-11-14 12:11:47 +00:00
* @date 2014
*/
2014-11-12 17:59:29 +00:00
var utils = require('./utils');
var types = require('./types');
2015-01-31 13:05:48 +00:00
var c = require('./const');
2015-01-31 00:52:36 +00:00
var f = require('./formatters');
2015-01-16 09:47:43 +00:00
2015-01-31 14:48:49 +00:00
var displayTypeError = function (type) {
console.error('parser does not support type: ' + type);
};
2015-01-31 00:52:36 +00:00
/// This method should be called if we want to check if givent type is an array type
/// @returns true if it is, otherwise false
2015-01-17 01:14:40 +00:00
var arrayType = function (type) {
return type.slice(-2) === '[]';
};
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);
2015-01-17 01:14:40 +00:00
return "";
};
var inputTypes = types.inputTypes();
2014-11-12 17:59:29 +00:00
2015-01-14 13:19:54 +00:00
/// Formats input params to bytes
2015-01-31 14:48:49 +00:00
/// @param abi contract method inputs
2015-01-14 13:19:54 +00:00
/// @param array of params that will be formatted to bytes
/// @returns bytes representation of input params
2015-01-31 14:48:49 +00:00
var formatInput = function (inputs, params) {
2014-11-12 17:59:29 +00:00
var bytes = "";
var toAppendConstant = "";
var toAppendArrayContent = "";
2014-12-22 00:13:49 +00:00
/// first we iterate in search for dynamic
2015-01-31 14:48:49 +00:00
inputs.forEach(function (input, index) {
2015-01-17 01:14:40 +00:00
bytes += dynamicTypeBytes(input.type, params[index]);
});
2015-01-31 14:48:49 +00:00
inputs.forEach(function (input, i) {
2015-01-14 12:53:40 +00:00
var typeMatch = false;
for (var j = 0; j < inputTypes.length && !typeMatch; j++) {
2015-01-31 14:48:49 +00:00
typeMatch = inputTypes[j].type(inputs[i].type, params[i]);
2014-11-12 17:59:29 +00:00
}
2015-01-14 12:53:40 +00:00
if (!typeMatch) {
2015-01-31 14:48:49 +00:00
displayTypeError(inputs[i].type);
2014-11-12 17:59:29 +00:00
}
2015-01-14 12:53:40 +00:00
var formatter = inputTypes[j - 1].format;
2015-01-17 01:14:40 +00:00
2015-01-31 14:48:49 +00:00
if (arrayType(inputs[i].type))
2015-02-27 04:24:19 +00:00
toAppendArrayContent += params[i].reduce(function (acc, curr) {
2015-01-17 01:14:40 +00:00
return acc + formatter(curr);
}, "");
else if (inputs[i].type === 'string')
toAppendArrayContent += formatter(params[i]);
2015-01-17 01:14:40 +00:00
else
2015-02-27 04:24:19 +00:00
toAppendConstant += formatter(params[i]);
2015-01-17 01:14:40 +00:00
});
bytes += toAppendConstant + toAppendArrayContent;
2014-11-12 17:59:29 +00:00
return bytes;
};
2015-01-17 12:39:19 +00:00
var dynamicBytesLength = function (type) {
if (arrayType(type) || type === 'string') // only string itself that is dynamic; stringX is static length.
2015-01-31 13:05:48 +00:00
return c.ETH_PADDING * 2;
2015-01-17 12:39:19 +00:00
return 0;
};
var outputTypes = types.outputTypes();
2014-11-13 03:21:51 +00:00
2015-01-14 13:19:54 +00:00
/// Formats output bytes back to param list
2015-01-31 14:48:49 +00:00
/// @param contract abi method outputs
/// @param bytes representtion of output
/// @returns array of output params
2015-01-31 14:48:49 +00:00
var formatOutput = function (outs, output) {
2014-11-13 03:21:51 +00:00
output = output.slice(2);
var result = [];
2015-01-31 13:05:48 +00:00
var padding = c.ETH_PADDING * 2;
2015-01-17 12:39:19 +00:00
2015-01-31 14:48:49 +00:00
var dynamicPartLength = outs.reduce(function (acc, curr) {
2015-01-17 12:39:19 +00:00
return acc + dynamicBytesLength(curr.type);
}, 0);
2015-01-17 12:39:19 +00:00
var dynamicPart = output.slice(0, dynamicPartLength);
output = output.slice(dynamicPartLength);
2015-01-31 14:48:49 +00:00
outs.forEach(function (out, i) {
2015-02-25 14:53:28 +00:00
/*jshint maxcomplexity:6 */
2015-01-14 12:53:40 +00:00
var typeMatch = false;
for (var j = 0; j < outputTypes.length && !typeMatch; j++) {
2015-01-31 14:48:49 +00:00
typeMatch = outputTypes[j].type(outs[i].type);
2014-11-13 03:21:51 +00:00
}
2015-01-14 12:53:40 +00:00
if (!typeMatch) {
2015-01-31 14:48:49 +00:00
displayTypeError(outs[i].type);
2014-11-13 03:21:51 +00:00
}
2015-01-17 12:39:19 +00:00
2014-11-13 03:21:51 +00:00
var formatter = outputTypes[j - 1].format;
2015-01-31 14:48:49 +00:00
if (arrayType(outs[i].type)) {
2015-01-31 00:52:36 +00:00
var size = f.formatOutputUInt(dynamicPart.slice(0, padding));
2015-01-17 12:39:19 +00:00
dynamicPart = dynamicPart.slice(padding);
var array = [];
for (var k = 0; k < size; k++) {
array.push(formatter(output.slice(0, padding)));
2015-01-17 12:39:19 +00:00
output = output.slice(padding);
}
result.push(array);
}
2015-01-31 14:48:49 +00:00
else if (types.prefixedType('string')(outs[i].type)) {
dynamicPart = dynamicPart.slice(padding);
2015-01-17 12:39:19 +00:00
result.push(formatter(output.slice(0, padding)));
output = output.slice(padding);
} else {
result.push(formatter(output.slice(0, padding)));
output = output.slice(padding);
}
});
2014-11-13 03:21:51 +00:00
return result;
};
2015-01-14 12:53:40 +00:00
/// @param json abi for contract
/// @returns input parser object for given json abi
/// TODO: refactor creating the parser, do not double logic from contract
2014-11-14 12:11:47 +00:00
var inputParser = function (json) {
var parser = {};
json.forEach(function (method) {
var displayName = utils.extractDisplayName(method.name);
2015-01-31 14:22:05 +00:00
var typeName = utils.extractTypeName(method.name);
2015-01-20 14:06:05 +00:00
var impl = function () {
2014-11-13 11:24:34 +00:00
var params = Array.prototype.slice.call(arguments);
2015-01-31 14:48:49 +00:00
return formatInput(method.inputs, params);
2014-11-13 11:24:34 +00:00
};
2015-01-20 14:06:05 +00:00
if (parser[displayName] === undefined) {
parser[displayName] = impl;
}
parser[displayName][typeName] = impl;
2014-11-13 11:24:34 +00:00
});
2014-11-14 12:11:47 +00:00
return parser;
2014-11-12 17:59:29 +00:00
};
2015-01-14 12:53:40 +00:00
/// @param json abi for contract
/// @returns output parser for given json abi
2014-11-14 12:11:47 +00:00
var outputParser = function (json) {
var parser = {};
json.forEach(function (method) {
2015-01-20 14:06:05 +00:00
var displayName = utils.extractDisplayName(method.name);
2015-01-31 14:22:05 +00:00
var typeName = utils.extractTypeName(method.name);
2015-01-20 14:06:05 +00:00
var impl = function (output) {
2015-01-31 14:48:49 +00:00
return formatOutput(method.outputs, output);
2014-11-14 12:11:47 +00:00
};
2015-01-20 14:06:05 +00:00
if (parser[displayName] === undefined) {
parser[displayName] = impl;
}
parser[displayName][typeName] = impl;
2014-11-14 12:11:47 +00:00
});
return parser;
};
module.exports = {
inputParser: inputParser,
2015-01-09 11:55:04 +00:00
outputParser: outputParser,
2015-01-31 14:48:49 +00:00
formatInput: formatInput,
2015-03-03 17:38:23 +00:00
formatOutput: formatOutput
2014-11-14 12:11:47 +00:00
};