Commit bf0acf27 authored by d11e9's avatar d11e9

use universal-dapp interface

Universal-dapp was originaly factored out of browser-solidity to modularise the contract interface component. And so is a direct decended of the code it removes/replaces. Adding a number of features: - constants are shown by default when appropriate - all methods show gas execution costs when run - smoothes the path to interacting with a local node aswell as vm - allows instanciating contracts from an address - shows events where supported
parent 4cffd49b
...@@ -30,6 +30,7 @@ THE SOFTWARE. ...@@ -30,6 +30,7 @@ THE SOFTWARE.
<title>Solidity realtime compiler and runtime</title> <title>Solidity realtime compiler and runtime</title>
<link rel="stylesheet" href="stylesheets/styles.css"> <link rel="stylesheet" href="stylesheets/styles.css">
<link rel="stylesheet" href="stylesheets/pygment_trac.css"> <link rel="stylesheet" href="stylesheets/pygment_trac.css">
<link rel="stylesheet" href="stylesheets/universal-dapp.css">
<link rel="stylesheet" href="stylesheets/browser-solidity.css"> <link rel="stylesheet" href="stylesheets/browser-solidity.css">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<style type="text/css"> <style type="text/css">
...@@ -41,6 +42,7 @@ THE SOFTWARE. ...@@ -41,6 +42,7 @@ THE SOFTWARE.
<script src="libs/mode-solidity.js"></script> <script src="libs/mode-solidity.js"></script>
<script src="bin/soljson-latest.js"></script> <script src="bin/soljson-latest.js"></script>
<script src="libs/ethereumjs-vm.js"></script> <script src="libs/ethereumjs-vm.js"></script>
<script src="libs/universal-dapp.js"></script>
<script src="libs/web3.min.js"></script> <script src="libs/web3.min.js"></script>
<script src="ballot.sol.js"></script> <script src="ballot.sol.js"></script>
...@@ -450,27 +452,27 @@ THE SOFTWARE. ...@@ -450,27 +452,27 @@ THE SOFTWARE.
}; };
var renderContracts = function(data, source) { var renderContracts = function(data, source) {
$('#output').empty(); console.log( "rendering ", data)
for (var contractName in data.contracts) { for (var contractName in data.contracts) {
var contract = data.contracts[contractName]; var contract = data.contracts[contractName];
var title = $('<h3 class="title"/>').text(contractName); var dapp = new UniversalDApp([{
var contractOutput = $('<div class="contractOutput"/>') name: contractName,
.append(title); interface: contract['interface'],
var body = $('<div class="body" />') bytecode: contract.bytecode
contractOutput.append(body); }], {
if (contract.bytecode.length > 0) vm: true,
title.append($('<div class="size"/>').text((contract.bytecode.length / 2) + ' bytes')) removable: false,
body.append(getExecuteInterface(contract, contractName)) removable_instances: true
.append(tableRow('Bytecode', contract.bytecode)); });
body.append(tableRow('Interface', contract['interface'])) var $contractOutput = dapp.render();
.append(textRow('Web3 deploy', gethDeploy(contractName.toLowerCase(),contract['interface'],contract.bytecode), 'deploy')) $contractOutput.append(textRow('Interface', contract['interface']))
.append(textRow('uDApp', combined(contractName,contract['interface'],contract.bytecode), 'deploy')) .append(textRow('Web3 deploy', gethDeploy(contractName.toLowerCase(),contract['interface'],contract.bytecode), 'deploy'))
.append(getDetails(contract, source, contractName)); .append(textRow('uDApp', combined(contractName,contract['interface'],contract.bytecode), 'deploy'))
.append(getDetails(contract, source, contractName));
$('#output').append(contractOutput);
title.click(function(ev){ $(this).parent().toggleClass('hide') }); console.log("contract output", $contractOutput )
$('#output').append( $contractOutput );
} }
$('.col2 input,textarea').click(function() { this.select(); }); $('.col2 input,textarea').click(function() { this.select(); });
}; };
var tableRowItems = function(first, second, cls) { var tableRowItems = function(first, second, cls) {
...@@ -491,7 +493,7 @@ THE SOFTWARE. ...@@ -491,7 +493,7 @@ THE SOFTWARE.
cls); cls);
}; };
var getDetails = function(contract, source, contractName) { var getDetails = function(contract, source, contractName) {
var button = $('<button>Details</button>'); var button = $('<button>Toggle Details</button>');
var details = $('<div style="display: none;"/>') var details = $('<div style="display: none;"/>')
.append(tableRow('Solidity Interface', contract.solidity_interface)) .append(tableRow('Solidity Interface', contract.solidity_interface))
.append(tableRow('Opcodes', contract.opcodes)); .append(tableRow('Opcodes', contract.opcodes));
...@@ -513,7 +515,7 @@ THE SOFTWARE. ...@@ -513,7 +515,7 @@ THE SOFTWARE.
button.click(function() { detailsOpen[contractName] = !detailsOpen[contractName]; details.toggle(); }); button.click(function() { detailsOpen[contractName] = !detailsOpen[contractName]; details.toggle(); });
if (detailsOpen[contractName]) if (detailsOpen[contractName])
details.show(); details.show();
return $('<div/>').append(button).append(details); return $('<div class="contractDetails"/>').append(button).append(details);
}; };
var formatGasEstimates = function(data) { var formatGasEstimates = function(data) {
var gasToText = function(g) { return g === null ? 'unknown' : g; } var gasToText = function(g) { return g === null ? 'unknown' : g; }
...@@ -552,35 +554,8 @@ THE SOFTWARE. ...@@ -552,35 +554,8 @@ THE SOFTWARE.
return text; return text;
}; };
$('.asmOutput button').click(function() {$(this).parent().find('pre').toggle(); })
$('.asmOutput button').click(function() {$(this).parent().find('pre').toggle(); });
// ----------------- VM ----------------------
var stateTrie = new EthVm.Trie();
var vm = new EthVm.VM(stateTrie);
//@todo this does not calculate the gas costs correctly but gets the job done.
var identityCode = 'return { gasUsed: 1, return: opts.data, exception: 1 };';
var identityAddr = ethUtil.pad(new Buffer('04', 'hex'), 20)
vm.loadPrecompiled(identityAddr, identityCode);
var secretKey = '3cd7232cd6f3fc66a57a6bedc1a8ed6c228fff0a327e169c2bcc5e869ed49511'
var publicKey = '0406cc661590d48ee972944b35ad13ff03c7876eae3fd191e8a2f77311b0a3c6613407b5005e63d7d8d76b89d5f900cde691497688bb281e07a5052ff61edebdc0'
var address = ethUtil.pubToAddress(new Buffer(publicKey, 'hex'));
$('#txorigin').text('0x' + address.toString('hex'));
var account = new EthVm.Account();
account.balance = 'f00000000000000001';
var nonce = 0;
stateTrie.put(address, account.serialize());
var runTx = function(data, to, cb) {
var tx = new EthVm.Transaction({
nonce: new Buffer([nonce++]), //@todo count beyond 255
gasPrice: '01',
gasLimit: '3000000000', // plenty
to: to,
data: data
});
tx.sign(new Buffer(secretKey, 'hex'));
vm.runTx({tx: tx}, cb);
};
var getConstructorInterface = function(abi) { var getConstructorInterface = function(abi) {
var funABI = {'name':'','inputs':[],'type':'constructor','outputs':[]}; var funABI = {'name':'','inputs':[],'type':'constructor','outputs':[]};
...@@ -592,78 +567,6 @@ THE SOFTWARE. ...@@ -592,78 +567,6 @@ THE SOFTWARE.
return funABI; return funABI;
}; };
var getCallButton = function(args) {
// args.abi, args.bytecode [constr only], args.address [fun only]
// args.appendFunctions [constr only]
var isConstructor = args.bytecode !== undefined;
var fun = new web3.eth.function(args.abi);
var inputs = '';
$.each(args.abi.inputs, function(i, inp) {
if (inputs != '') inputs += ', ';
inputs += inp.type + ' ' + inp.name;
});
var inputField = $('<input/>').attr('placeholder', inputs);
var outputSpan = $('<div class="output"/>');
var button = $('<button/>')
.text(args.bytecode ? 'Create' : fun.displayName())
.click(function() {
var funArgs = $.parseJSON('[' + inputField.val() + ']');
var data = fun.toPayload(funArgs).data;
if (data.slice(0, 2) == '0x') data = data.slice(2);
if (isConstructor)
data = args.bytecode + data.slice(8);
outputSpan.text('...');
runTx(data, args.address, function(err, result) {
if (err)
outputSpan.text(err);
else if (isConstructor) {
outputSpan.text(' Creation used ' + result.vm.gasUsed.toString(10) + ' gas.');
args.appendFunctions(result.createdAddress);
} else {
var outputObj = fun.unpackOutput('0x' + result.vm.return.toString('hex'));
outputSpan.text(' Returned: ' + JSON.stringify(outputObj));
}
});
});
if (!isConstructor)
button.addClass('runButton');
var c = $('<div class="contractProperty"/>')
.append(button);
if (args.abi.inputs.length > 0)
c.append(inputField);
return c.append(outputSpan);
};
var getExecuteInterface = function(contract, name) {
var abi = $.parseJSON(contract.interface);
var execInter = $('<div/>');
var funABI = getConstructorInterface(abi);
var appendFunctions = function(address) {
var instance = $('<div class="contractInstance"/>');
var title = $('<span class="title"/>').text('Contract at ' + address.toString('hex'));
instance.append(title);
$.each(abi, function(i, funABI) {
if (funABI.type != 'function') return;
instance.append(getCallButton({
abi: funABI,
address: address
}));
});
execInter.append(instance);
title.click(function(ev){ $(this).parent().toggleClass('hide') });
};
if (contract.bytecode.length > 0)
execInter
.append(getCallButton({
abi: funABI,
bytecode: contract.bytecode,
appendFunctions: appendFunctions
}));
return execInter;
};
</script> </script>
</body> </body>
</html> </html>
This diff is collapsed.
...@@ -119,9 +119,21 @@ body { ...@@ -119,9 +119,21 @@ body {
float: left; float: left;
} }
#output .poweredBy,
#output .legend { display: none; }
#output .udapp {
border: 0 none;
box-shadow: none;
}
.row { .row {
overflow: auto; overflow: auto;
display: block;
clear: both;
margin: 0.5em;
} }
.gethDeployText { .gethDeployText {
border-color: #bebebe; border-color: #bebebe;
height: 2.5em; height: 2.5em;
...@@ -129,88 +141,17 @@ body { ...@@ -129,88 +141,17 @@ body {
display: block; display: block;
} }
.contractInstance { .contractDetails button {
background-color: #ccc; background-color: transparent;
margin-bottom: 1em; border: 0 none;
padding: 0.6em; padding: 0;
} display: inline-block;
text-decoration: underline;
.contractInstance.hide > *:not(.title) { color: blue;
display: none;
}
.contractInstance .contractProperty input,
.contractInstance .contractProperty button {
text-align: left;
padding: 0.3em;
width: 50%;
margin: 0;
}
.contractOutput .contractInstance .contractProperty {
margin-bottom: 0;
}
.contractOutput .contractInstance .contractProperty .output {
padding: 0.4em;
background-color: #333;
color: white;
margin-bottom: 1em;
display: block;
}
.contractInstance .contractProperty .output:empty { display: none; }
.contractOutput {
border-bottom: 1px dotted black;
padding: 0.6em;
box-sizing: border-box;
}
.contractOutput .contractProperty {
margin-bottom: 0.6em;
}
.contractOutput .contractProperty .output {
display: inline;
}
.contractOutput .body {
margin-top: 10px;
}
.contractOutput.hide {
background-color: #4C4C67;
color: white;
}
.contractOutput.hide > *:not(.title) {
display: none;
}
.title {
margin: 0;
cursor: pointer; cursor: pointer;
font-family: monospace; width: auto;
font-weight: bold; min-width: 4em;
} margin-bottom: 1em;
.title:before {
content: "\25BC";
opacity: 0.5;
margin-right: 0.4em;
font-size: 10px;
}
.hide > .title:before {
content: "\25B6";
}
.contractOutput > .title {
border-bottom: #4C4C67;
}
.title .size {
font-weight: normal;
float: right;
} }
.error { .error {
......
.udapp {
padding: 1em;
border: 1px dotted #4D5686;
position: relative;
box-shadow: 0 0 5px rgba(0,0,0,0.3);
box-sizing: border-box;
overflow: auto;
}
.udapp a {
color: #7A7AE2;
}
.udapp a:visited {
color: #7A7AE2;
}
.udapp input,
.udapp button,
.udapp-setup textarea,
.udapp-setup button {
display: block;
width: 100%;
padding: 0.6em;
box-sizing: border-box;
border: 1px solid rgba( 0,0,0,0.3 );
border-radius: 0.5em;
}
.udapp-setup textarea {
border-radius: 0;
margin-bottom: 1em;
height: 7em;
}
.udapp button {
min-width: 8em;
}
.udapp-setup button {
background-color: #556DF3;
color: white;
cursor: pointer;
}
.udapp .contract {
margin-bottom: 1em;
}
.udapp .create {
overflow: auto;
margin-bottom: 1em;
}
.udapp .title {
margin-bottom: 0.4em;
display: inline-block;
padding: 0.2em;
background-color: rgba( 255,255,255,0.5 );
display: block;
font-weight: bold;
padding-right: 2em;
word-wrap: break-word;
}
.udapp .output {
padding: 1em;
clear: both;
word-wrap: break-word;
}
.udapp .constructor > .output {
padding-right: 1em;
}
.udapp .output .error {
color: red;
}
.udapp .output .result {
position: relative;
margin-bottom: 0.5em;
white-space: pre;
}
.udapp .result { position: relative; }
.udapp .output .result .returned,
.udapp .output .result .value,
.udapp .output .result .waiting,
.udapp .output .result .gasUsed {
padding-right: 2em;
word-wrap: break-word;
}
.udapp .output .result:last-child { margin: 0; }
.udapp .output:empty {
display: none;
}
.udapp-close:before {
position: absolute;
top: .4em;
right: .4em;
width: 1.5em;
height: 1.5em;
text-align: center;
content: "x";
cursor: pointer;
}
.udapp .instance {
padding: 0.4em;
background-color: #ECD7D7;
margin-bottom: 1em;
position: relative;
border: 1px solid #999;
}
.udapp .instance:last-child {
margin-bottom: 0;
}
.udapp .instance .title {
cursor: pointer;
}
.udapp .instance.hide .title {
margin-bottom: 0;
padding-right: 1.5em;
word-wrap: break-word;
}
.udapp .instance .title:before {
content: "\25BC";
opacity: 0.5;
margin-right: 0.4em;
font-size: 10px;
}
.udapp .instance.hide > *:not(.title) {
display: none;
}
.udapp .instance.hide > .title:before {
content: "\25B6";
}
.udapp .contractProperty {
overflow: auto;
margin-bottom: 0.4em;
}
.udapp input,
.udapp button {
width: 33%;
display: block;
float: left;
}
.udapp .atAddress {
background-color: #62B762;
margin-right: 1em;
border-radius: 0.5em;
}
.udapp input { border-left: 0 none;}
.udapp button {
background-color: #666;
color: white;
cursor: pointer;
}
.udapp .instance input,
.udapp .instance button {
width: 50%;
float: left;
}
.udapp .contractProperty.hasArgs input,
.udapp .contractProperty.hasArgs button {
width: 50%;
}
.udapp .contractProperty .call {
background-color: #D42828;
}
.udapp .contractProperty.constant .call {
background-color: #556DF3;
}
.udapp .contractProperty input {
display: none;
}
.udapp .contractProperty > .value {
padding: 0 0.4em;
box-sizing: border-box;
width: 50%;
float: left;
word-wrap: break-word;
}
.udapp .contractProperty.hasArgs input {
display: block;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.udapp .contractProperty.hasArgs button {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-right: 0;
}
.udapp .events:not(:empty):before {
content: "Events";
font-weight: bold;
display: block;
margin-bottom: 0.4em;
}
.udapp .events .event {
padding: 0.4em;
position: relative;
word-wrap: break-word;
padding-right: 3em;
background-color: white;
margin-bottom: 0.5em;
white-space: pre;
}
.udapp .events .event .name { margin-right: 0.5em; }
.udapp .legend {
font-size: 12px;
float: left;
color: #666;
}
.udapp .legend div {
display: inline-block;
margin-right: 0.5em;
}
.udapp .legend div:before {
content: ".";
color: transparent;
display: inline-block;
background-color: #ccc;
height: 1em;
margin-right: 0.5em;
width: 1em;
}
.udapp .legend .attach:before { background-color: #62B762; }
.udapp .legend .transact:before { background-color: #D42828; }
.udapp .legend .call:before { background-color: #556DF3; }
.udapp .poweredBy {
float: right;
color: #666;
font-size: 12px;
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment