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 findMethodIndex = function (json, methodName) { return findIndex(json, function (method) { return method.name === methodName; }); }; var padLeft = function (number, n) { return (new Array(n * 2 - number.toString().length + 1)).join("0") + number; }; var setupInputTypes = function () { var prefixedType = function (prefix) { return function (type, value) { var expected = prefix; if (type.indexOf(expected) !== 0) { return false; } var padding = parseInt(type.slice(expected.length)) / 8; return padLeft(value, padding); }; }; var namedType = function (name, padding, formatter) { return function (type, value) { if (type !== name) { return false; } return padLeft(formatter ? value : formatter(value), padding); }; }; var formatBool = function (value) { return value ? '1' : '0'; }; return [ prefixedType('uint'), prefixedType('int'), namedType('address', 20), namedType('bool', 1, formatBool), ]; }; var inputTypes = setupInputTypes(); var toAbiInput = function (json, methodName, params) { var bytes = ""; var index = findMethodIndex(json, methodName); if (index === -1) { return; } // it needs to be checked in WebThreeStubServer // something wrong might be with this additional zero bytes = bytes + index + 'x' + '0'; var method = json[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]); } if (!found) { console.error('unsupported json type: ' + method.inputs[i].type); } bytes += found; } return bytes; }; var setupOutputTypes = function () { var prefixedType = function (prefix) { return function (type) { var expected = prefix; if (type.indexOf(expected) !== 0) { return -1; } var padding = parseInt(type.slice(expected.length)) / 8; return padding * 2; }; }; var namedType = function (name, padding) { return function (type) { return name === type ? padding * 2: -1; }; }; var formatInt = function (value) { return parseInt(value, 16); }; var formatBool = function (value) { return value === '1' ? true : false; }; return [ { padding: prefixedType('uint'), format: formatInt }, { padding: prefixedType('int'), format: formatInt }, { padding: namedType('address', 20) }, { padding: namedType('bool', 1), format: formatBool } ]; }; var outputTypes = setupOutputTypes(); var fromAbiOutput = function (json, methodName, output) { var index = findMethodIndex(json, methodName); if (index === -1) { return; } 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); } if (padding === -1) { // not found output parsing continue; } var res = output.slice(0, padding); var formatter = outputTypes[j - 1].format; result.push(formatter ? formatter(res): res); output = output.slice(padding); } return result; }; var load = function (json) { var contract = {}; json.forEach(function (method) { contract[method.name] = function () { var params = Array.prototype.slice.call(arguments); return toAbiInput(json, method.name, params); }; }); return contract; }; module.exports = load;