From 05290d554749c7b3507da4af11796112c67be718 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 12 Nov 2014 18:59:29 +0100 Subject: abi, the beginning --- lib/abi.js | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 lib/abi.js (limited to 'lib') diff --git a/lib/abi.js b/lib/abi.js new file mode 100644 index 000000000..3082b8232 --- /dev/null +++ b/lib/abi.js @@ -0,0 +1,77 @@ + +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 padLeft = function (number, n) { + return (new Array(n - number.toString.length + 1)).join("0") + number; +}; + +var setupTypes = 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) { + return function (type, value) { + if (type !== name) { + return false; + } + + return padLeft(value, padding); + }; + }; + + return [ + prefixedType('uint'), + prefixedType('int'), + namedType('address', 20), + namedType('bool', 1), + ]; +}; + +var types = setupTypes(); + +var toBytes = function (json, methodName, params) { + var bytes = ""; + var index = findIndex(json, function (method) { + return method.name === methodName; + }); + + if (index === -1) { + return; + } + + bytes = bytes + index + 'x'; + var method = json[index]; + + for (var i = 0; i < method.inputs.length; i++) { + var found = false; + for (var j = 0; j < types.length && !found; j++) { + found = types[j](method.inputs[i].type, params[i]); + } + if (!found) { + console.error('unsupported json type: ' + method.inputs[i].type); + } + bytes += found; + } + return bytes; +}; + +module.exports = { + toBytes: toBytes +}; + -- cgit v1.2.3 From 3451f2608682bd044d7b7165b0d3aa640e8fd81f Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Wed, 12 Nov 2014 20:39:13 +0100 Subject: changes to make everything work --- lib/abi.js | 6 ++++-- lib/main.js | 7 +++++-- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/abi.js b/lib/abi.js index 3082b8232..9102454b0 100644 --- a/lib/abi.js +++ b/lib/abi.js @@ -9,7 +9,7 @@ var findIndex = function (array, callback) { }; var padLeft = function (number, n) { - return (new Array(n - number.toString.length + 1)).join("0") + number; + return (new Array(n * 2 - number.toString().length + 1)).join("0") + number; }; var setupTypes = function () { @@ -55,7 +55,9 @@ var toBytes = function (json, methodName, params) { return; } - bytes = bytes + index + 'x'; + // 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++) { diff --git a/lib/main.js b/lib/main.js index c3ed22f8b..d7f8531d2 100644 --- a/lib/main.js +++ b/lib/main.js @@ -84,8 +84,11 @@ var ethMethods = function () { { name: 'block', call: blockCall }, { name: 'transaction', call: transactionCall }, { name: 'uncle', call: uncleCall }, - { name: 'compile', call: 'eth_compile' }, - { name: 'lll', call: 'eth_lll' } + { name: 'compilers', call: 'eth_compilers' }, + { name: 'lll', call: 'eth_lll' }, + { name: 'solidity', call: 'eth_solidity' }, + { name: 'contractCreate', call: 'eth_contractCreate' }, + { name: 'contractCall', call: 'eth_contractCall' } ]; return methods; }; -- cgit v1.2.3 From d99fea2db682c454581e1f9f60b2cea27d02c36e Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 13 Nov 2014 04:21:51 +0100 Subject: abi output formatting --- lib/abi.js | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 89 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/abi.js b/lib/abi.js index 9102454b0..0ac27e6b8 100644 --- a/lib/abi.js +++ b/lib/abi.js @@ -8,11 +8,17 @@ var findIndex = function (array, callback) { 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 setupTypes = function () { +var setupInputTypes = function () { var prefixedType = function (prefix) { return function (type, value) { var expected = prefix; @@ -25,32 +31,34 @@ var setupTypes = function () { }; }; - var namedType = function (name, padding) { + var namedType = function (name, padding, formatter) { return function (type, value) { if (type !== name) { return false; } - return padLeft(value, padding); + 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), + namedType('bool', 1, formatBool), ]; }; -var types = setupTypes(); +var inputTypes = setupInputTypes(); -var toBytes = function (json, methodName, params) { +var toAbiInput = function (json, methodName, params) { var bytes = ""; - var index = findIndex(json, function (method) { - return method.name === methodName; - }); - + var index = findMethodIndex(json, methodName); + if (index === -1) { return; } @@ -62,8 +70,8 @@ var toBytes = function (json, methodName, params) { for (var i = 0; i < method.inputs.length; i++) { var found = false; - for (var j = 0; j < types.length && !found; j++) { - found = types[j](method.inputs[i].type, params[i]); + 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); @@ -73,7 +81,75 @@ var toBytes = function (json, methodName, params) { 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; +}; + module.exports = { - toBytes: toBytes + toAbiInput: toAbiInput, + fromAbiOutput: fromAbiOutput }; -- cgit v1.2.3 From 0e67fcd361ea1681f989077969417e166ea8453e Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 13 Nov 2014 12:24:34 +0100 Subject: contract object --- lib/abi.js | 15 ++++++++++++--- lib/main.js | 4 +--- 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/abi.js b/lib/abi.js index 0ac27e6b8..1e3759918 100644 --- a/lib/abi.js +++ b/lib/abi.js @@ -148,8 +148,17 @@ var fromAbiOutput = function (json, methodName, output) { return result; }; -module.exports = { - toAbiInput: toAbiInput, - fromAbiOutput: fromAbiOutput +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; + diff --git a/lib/main.js b/lib/main.js index d7f8531d2..fc0170287 100644 --- a/lib/main.js +++ b/lib/main.js @@ -86,9 +86,7 @@ var ethMethods = function () { { name: 'uncle', call: uncleCall }, { name: 'compilers', call: 'eth_compilers' }, { name: 'lll', call: 'eth_lll' }, - { name: 'solidity', call: 'eth_solidity' }, - { name: 'contractCreate', call: 'eth_contractCreate' }, - { name: 'contractCall', call: 'eth_contractCall' } + { name: 'solidity', call: 'eth_solidity' } ]; return methods; }; -- cgit v1.2.3 From b1428555d10c5449e0f91f53f1dd0e8d1a1f9732 Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Thu, 13 Nov 2014 18:29:31 +0100 Subject: added storageAt --- lib/main.js | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/main.js b/lib/main.js index fc0170287..e2caf6bc3 100644 --- a/lib/main.js +++ b/lib/main.js @@ -77,6 +77,7 @@ var ethMethods = function () { var methods = [ { name: 'balanceAt', call: 'eth_balanceAt' }, { name: 'stateAt', call: 'eth_stateAt' }, + { name: 'storageAt', call: 'eth_storageAt' }, { name: 'countAt', call: 'eth_countAt'}, { name: 'codeAt', call: 'eth_codeAt' }, { name: 'transact', call: 'eth_transact' }, -- cgit v1.2.3 From ea8db7a4aecb034c6a967ccd3b17c50f423cb77c Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Fri, 14 Nov 2014 13:11:47 +0100 Subject: improved contracts interface --- lib/abi.js | 48 ++++++++++++++++++++++++++++++++++++++++++------ lib/main.js | 42 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 81 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/abi.js b/lib/abi.js index 1e3759918..3df0fe684 100644 --- a/lib/abi.js +++ b/lib/abi.js @@ -1,3 +1,24 @@ +/* + 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 . +*/ +/** @file abi.js + * @authors: + * Marek Kotewicz + * @date 2014 + */ var findIndex = function (array, callback) { var end = false; @@ -71,7 +92,8 @@ var toAbiInput = function (json, methodName, params) { 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 val = parseInt(params[i]).toString(16); + found = inputTypes[j](method.inputs[i].type, val); } if (!found) { console.error('unsupported json type: ' + method.inputs[i].type); @@ -148,17 +170,31 @@ var fromAbiOutput = function (json, methodName, output) { return result; }; -var load = function (json) { - var contract = {}; +var inputParser = function (json) { + var parser = {}; json.forEach(function (method) { - contract[method.name] = function () { + parser[method.name] = function () { var params = Array.prototype.slice.call(arguments); return toAbiInput(json, method.name, params); }; }); - return contract; + return parser; }; -module.exports = load; +var outputParser = function (json) { + var parser = {}; + json.forEach(function (method) { + parser[method.name] = function (output) { + return fromAbiOutput(json, method.name, output); + }; + }); + + return parser; +}; + +module.exports = { + inputParser: inputParser, + outputParser: outputParser +}; diff --git a/lib/main.js b/lib/main.js index e2caf6bc3..7990691de 100644 --- a/lib/main.js +++ b/lib/main.js @@ -22,6 +22,8 @@ * @date 2014 */ +var abi = require('./abi'); + function flattenPromise (obj) { if (obj instanceof Promise) { return Promise.resolve(obj); @@ -292,9 +294,8 @@ var web3 = { } }; -var eth = web3.eth; -setupMethods(eth, ethMethods()); -setupProperties(eth, ethProperties()); +setupMethods(web3.eth, ethMethods()); +setupProperties(web3.eth, ethProperties()); setupMethods(web3.db, dbMethods()); setupMethods(web3.shh, shhMethods()); @@ -454,5 +455,40 @@ function messageHandler(data) { } } +web3.contract = function (address, desc) { + var inputParser = abi.inputParser(desc); + var outputParser = abi.outputParser(desc); + + var contract = {}; + + desc.forEach(function (method) { + contract[method.name] = function () { + var params = Array.prototype.slice.call(arguments); + var parsed = inputParser[method.name].apply(null, params); + + var onSuccess = function (result) { + return outputParser[method.name](result); + }; + + return { + call: function (extra) { + extra = extra || {}; + extra.to = address; + extra.data = parsed; + return web3.eth.call(extra).then(onSuccess); + }, + transact: function (extra) { + extra = extra || {}; + extra.to = address; + extra.data = parsed; + return web3.eth.transact(extra).then(onSuccess); + } + }; + }; + }); + + return contract; +}; + module.exports = web3; -- cgit v1.2.3