Merge pull request #12 from debris/master
simplifie contract creation && calls, improved added examples
This commit is contained in:
commit
42713c6e99
12
dist/ethereum.js
vendored
12
dist/ethereum.js
vendored
File diff suppressed because one or more lines are too long
6
dist/ethereum.js.map
vendored
6
dist/ethereum.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/ethereum.min.js
vendored
2
dist/ethereum.min.js
vendored
File diff suppressed because one or more lines are too long
75
example/contract.html
Normal file
75
example/contract.html
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<!doctype>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<script type="text/javascript" src="js/es6-promise/promise.min.js"></script>
|
||||||
|
<script type="text/javascript" src="../dist/ethereum.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
var web3 = require('web3');
|
||||||
|
web3.setProvider(new web3.providers.AutoProvider());
|
||||||
|
|
||||||
|
// solidity source code
|
||||||
|
var source = "" +
|
||||||
|
"contract test {\n" +
|
||||||
|
" function multiply(uint a) returns(uint d) {\n" +
|
||||||
|
" return a * 7;\n" +
|
||||||
|
" }\n" +
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
// contract description, this will be autogenerated somehow
|
||||||
|
var desc = [{
|
||||||
|
"name": "multiply",
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "a",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "d",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}];
|
||||||
|
|
||||||
|
var contract;
|
||||||
|
|
||||||
|
function createExampleContract() {
|
||||||
|
// hide create button
|
||||||
|
document.getElementById('create').style.visibility = 'hidden';
|
||||||
|
document.getElementById('source').innerText = source;
|
||||||
|
|
||||||
|
// create contract
|
||||||
|
web3.eth.transact({code: web3.eth.solidity(source)}).then(function (address) {
|
||||||
|
contract = web3.contract(address, desc);
|
||||||
|
document.getElementById('call').style.visibility = 'visible';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function callExampleContract() {
|
||||||
|
// this should be generated by ethereum
|
||||||
|
var param = document.getElementById('value').value;
|
||||||
|
|
||||||
|
// call the contract
|
||||||
|
contract.multiply(param).call().then(function(res) {
|
||||||
|
document.getElementById('result').innerText = res[0];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>contract</h1>
|
||||||
|
<div id="source"></div>
|
||||||
|
<div id='create'>
|
||||||
|
<button type="button" onClick="createExampleContract();">create example contract</button>
|
||||||
|
</div>
|
||||||
|
<div id='call' style='visibility: hidden;'>
|
||||||
|
<input type="number" id="value" onkeyup='callExampleContract()'></input>
|
||||||
|
</div>
|
||||||
|
<div id="result"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -4,41 +4,38 @@
|
|||||||
<head>
|
<head>
|
||||||
<script type="text/javascript" src="js/es6-promise/promise.min.js"></script>
|
<script type="text/javascript" src="js/es6-promise/promise.min.js"></script>
|
||||||
<script type="text/javascript" src="../dist/ethereum.js"></script>
|
<script type="text/javascript" src="../dist/ethereum.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
if (window.Promise === undefined) {
|
|
||||||
window.Promise = ES6Promise.Promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
var web3 = require('web3');
|
var web3 = require('web3');
|
||||||
|
web3.setProvider(new web3.providers.AutoProvider());
|
||||||
|
|
||||||
//web3.setProvider(new web3.providers.QtProvider());
|
function watchBalance() {
|
||||||
//web3.setProvider(new web3.providers.HttpRpcProvider("http://localhost:8080"));
|
var coinbase = web3.eth.coinbase;
|
||||||
// web3.setProvider(new web3.providers.WebSocketProvider("ws://localhost:40404/eth"));
|
var originalBalance = 0;
|
||||||
web3.setProvider(new web3.providers.AutoProvider());
|
|
||||||
|
|
||||||
function testSnippet() {
|
web3.eth.balanceAt(coinbase).then(function (balance) {
|
||||||
web3.eth.watch({altered: web3.eth.coinbase}).changed(function() {
|
originalBalance = web3.toDecimal(balance);
|
||||||
web3.eth.balanceAt(web3.eth.coinbase).then(function (balance) {
|
document.getElementById('original').innerText = 'original balance: ' + originalBalance + ' watching...';
|
||||||
console.log(parseInt(balance,16));
|
});
|
||||||
console.log(typeof balance);
|
|
||||||
document.getElementById("result").innerText = +balance;
|
web3.eth.watch({altered: coinbase}).changed(function() {
|
||||||
|
web3.eth.balanceAt(coinbase).then(function (balance) {
|
||||||
|
var currentBalance = web3.toDecimal(balance);
|
||||||
|
document.getElementById("current").innerText = 'current: ' + currentBalance;
|
||||||
|
document.getElementById("diff").innerText = 'diff: ' + (currentBalance - originalBalance);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
<h1>coinbase balance</h1>
|
||||||
<h1>std::name_reg</h1>
|
<button type="button" onClick="watchBalance();">watch balance</button>
|
||||||
<input type="text" id="name"></input>
|
<div></div>
|
||||||
<button type="button" onClick="testSnippet();">test snippet</button>
|
<div id="original"></div>
|
||||||
|
<div id="current"></div>
|
||||||
<div></div>
|
<div id="diff"></div>
|
||||||
result: <div id="result"></div>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
200
lib/abi.js
Normal file
200
lib/abi.js
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
/*
|
||||||
|
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>
|
||||||
|
* @date 2014
|
||||||
|
*/
|
||||||
|
|
||||||
|
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++) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
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 inputParser = function (json) {
|
||||||
|
var parser = {};
|
||||||
|
json.forEach(function (method) {
|
||||||
|
parser[method.name] = function () {
|
||||||
|
var params = Array.prototype.slice.call(arguments);
|
||||||
|
return toAbiInput(json, method.name, params);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return parser;
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
48
lib/main.js
48
lib/main.js
@ -22,6 +22,8 @@
|
|||||||
* @date 2014
|
* @date 2014
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var abi = require('./abi');
|
||||||
|
|
||||||
function flattenPromise (obj) {
|
function flattenPromise (obj) {
|
||||||
if (obj instanceof Promise) {
|
if (obj instanceof Promise) {
|
||||||
return Promise.resolve(obj);
|
return Promise.resolve(obj);
|
||||||
@ -77,6 +79,7 @@ var ethMethods = function () {
|
|||||||
var methods = [
|
var methods = [
|
||||||
{ name: 'balanceAt', call: 'eth_balanceAt' },
|
{ name: 'balanceAt', call: 'eth_balanceAt' },
|
||||||
{ name: 'stateAt', call: 'eth_stateAt' },
|
{ name: 'stateAt', call: 'eth_stateAt' },
|
||||||
|
{ name: 'storageAt', call: 'eth_storageAt' },
|
||||||
{ name: 'countAt', call: 'eth_countAt'},
|
{ name: 'countAt', call: 'eth_countAt'},
|
||||||
{ name: 'codeAt', call: 'eth_codeAt' },
|
{ name: 'codeAt', call: 'eth_codeAt' },
|
||||||
{ name: 'transact', call: 'eth_transact' },
|
{ name: 'transact', call: 'eth_transact' },
|
||||||
@ -84,8 +87,9 @@ var ethMethods = function () {
|
|||||||
{ name: 'block', call: blockCall },
|
{ name: 'block', call: blockCall },
|
||||||
{ name: 'transaction', call: transactionCall },
|
{ name: 'transaction', call: transactionCall },
|
||||||
{ name: 'uncle', call: uncleCall },
|
{ name: 'uncle', call: uncleCall },
|
||||||
{ name: 'compile', call: 'eth_compile' },
|
{ name: 'compilers', call: 'eth_compilers' },
|
||||||
{ name: 'lll', call: 'eth_lll' }
|
{ name: 'lll', call: 'eth_lll' },
|
||||||
|
{ name: 'solidity', call: 'eth_solidity' }
|
||||||
];
|
];
|
||||||
return methods;
|
return methods;
|
||||||
};
|
};
|
||||||
@ -290,9 +294,8 @@ var web3 = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var eth = web3.eth;
|
setupMethods(web3.eth, ethMethods());
|
||||||
setupMethods(eth, ethMethods());
|
setupProperties(web3.eth, ethProperties());
|
||||||
setupProperties(eth, ethProperties());
|
|
||||||
setupMethods(web3.db, dbMethods());
|
setupMethods(web3.db, dbMethods());
|
||||||
setupMethods(web3.shh, shhMethods());
|
setupMethods(web3.shh, shhMethods());
|
||||||
|
|
||||||
@ -452,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;
|
module.exports = web3;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user