aboutsummaryrefslogtreecommitdiffstats
path: root/lib/abi.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/abi.js')
-rw-r--r--lib/abi.js164
1 files changed, 164 insertions, 0 deletions
diff --git a/lib/abi.js b/lib/abi.js
new file mode 100644
index 000000000..1e3759918
--- /dev/null
+++ b/lib/abi.js
@@ -0,0 +1,164 @@
+
+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;
+