Merge pull request #29 from d11e9/gh-pages

Contentious Much?
pull/1/head
chriseth 9 years ago
commit e09d93faa0
  1. 228
      index.html
  2. 340
      libs/universal-dapp.js
  3. 9
      libs/web3.min.js
  4. 163
      stylesheets/browser-solidity.css
  5. 282
      stylesheets/universal-dapp.css

@ -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.
<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>
@ -50,26 +52,35 @@ THE SOFTWARE.
<div id="editor"> <div id="editor">
<div id="files"> <div id="files">
<span class="newFile" title="New File">+</span> <span class="newFile" title="New File">+</span>
</div> </div>
<div id="input"></div> <div id="input"></div>
<div id="dragbar"></div>
</div> </div>
<div id="righthand-panel"> <div id="righthand-panel">
<div id="dragbar"></div>
<div id="header"> <div id="header">
<img id="solIcon" src="solidity.svg"> <img id="solIcon" src="solidity.svg">
<h1>Solidity realtime<br/>compiler and runtime</h1> <h1>Solidity realtime<br/>compiler and runtime</h1>
<div class="info"> <div class="info">
<p>Version: <span id="version">(loading)</span><br/> <p>Version: <span id="version">(loading)</span><br/>
Change to: <select id="versionSelector"></select><br/> Change to: <select id="versionSelector"></select><br/>
Execution environment does not connect to any node, everyhing is local and in memory only.<br/>
<code>tx.origin = <span id="txorigin"/></code></p> <code>tx.origin = <span id="txorigin"/></code></p>
</div> </div>
<div id="optimizeBox"> <div id="optimizeBox">
<input id="editorWrap" type="checkbox"><label for="editorWrap">Text Wrap</label> <label for="editorWrap"><input id="editorWrap" type="checkbox">Text Wrap</label>
<input id="optimize" type="checkbox"><label for="optimize">Enable Optimization</label> <label for="optimize"><input id="optimize" type="checkbox">Enable Optimization</label>
<span id="executionContext">
<label for="vm" title="Execution environment does not connect to any node, everything is local and in memory only.">
<input id="vm" type="radio" value="vm" checked name="executionContext">
JavaScript VM
</label>
<label for="web3" title="Execution environment connects to node at localhost, transactions will be sent to the network and can cause loss of money or worse!">
<input id="web3" type="radio" value="web3" name="executionContext">
Web3 Provider
</label>
</span>
</div> </div>
</div> </div>
<div id="output"></div> <div id="output"></div>
@ -109,6 +120,27 @@ THE SOFTWARE.
session.setTabSize(4); session.setTabSize(4);
session.setUseSoftTabs(true); session.setUseSoftTabs(true);
// ----------------- execution context -------------
var $vmToggle = $('#vm');
var $web3Toggle = $('#web3');
var executionContext = 'vm';
$vmToggle.get(0).checked = true;
$vmToggle.on('change', executionContextChange );
$web3Toggle.on('change', executionContextChange );
function executionContextChange (ev) {
if (ev.target.value == 'web3' && !confirm("Are you sure you want to connect to a local ethereum node?") ) {
$vmToggle.get(0).checked = true;
executionContext = 'vm';
} else executionContext = ev.target.value;
compile();
}
// ----------------- file selector------------- // ----------------- file selector-------------
var $filesEl = $('#files'); var $filesEl = $('#files');
@ -307,6 +339,7 @@ THE SOFTWARE.
onResize(); onResize();
document.querySelector('#editor').addEventListener('change', onResize); document.querySelector('#editor').addEventListener('change', onResize);
document.querySelector('#editorWrap').addEventListener('change', onResize);
// ----------------- compiler ---------------------- // ----------------- compiler ----------------------
@ -332,14 +365,21 @@ THE SOFTWARE.
renderError("Uncaught JavaScript Exception:\n" + exception); renderError("Uncaught JavaScript Exception:\n" + exception);
return; return;
} }
if (data['error'] !== undefined)
var noFatalErrors = true; // ie warnings are ok
if (data['error'] !== undefined) {
renderError(data['error']); renderError(data['error']);
if (data['errors'] != undefined) if (errortype(data['error']) !== 'warning') noFatalErrors = false;
}
if (data['errors'] != undefined) {
$.each(data['errors'], function(i, err) { $.each(data['errors'], function(i, err) {
renderError(err); renderError(err);
if (errortype(err) !== 'warning') noFatalErrors = false;
}); });
else }
renderContracts(data, input);
if (noFatalErrors) renderContracts(data, input);
} }
@ -392,9 +432,14 @@ THE SOFTWARE.
// ----------------- compiler output renderer ---------------------- // ----------------- compiler output renderer ----------------------
var detailsOpen = {}; var detailsOpen = {};
function errortype(message) {
return message.match(/^[0-9:]* Warning: /) ? 'warning' : 'error';
}
var renderError = function(message) { var renderError = function(message) {
var type = message.match(/^[0-9:]* Warning: /) ? 'warning' : 'error'; var type = errortype(message);
var $error = $('<pre class="' + type + '"></pre>').text(message); var $pre = $("<pre />").text(message);
var $error = $('<div class="sol ' + type + '"><div class="close">x</div></div>').prepend($pre);
$('#output').append( $error ); $('#output').append( $error );
var err = message.match(/^:([0-9]*):([0-9]*)/); var err = message.match(/^:([0-9]*):([0-9]*)/);
if (err && err.length) { if (err && err.length) {
@ -411,6 +456,11 @@ THE SOFTWARE.
editor.focus(); editor.focus();
editor.gotoLine(errLine + 1, errCol - 1, true); editor.gotoLine(errLine + 1, errCol - 1, true);
}); });
$error.find('.close').click(function(ev){
ev.preventDefault();
$error.remove();
return false;
});
} }
}; };
@ -422,7 +472,7 @@ THE SOFTWARE.
code += "var " + inp.name + " = /* var of type " + inp.type + " here */ ;\n"; code += "var " + inp.name + " = /* var of type " + inp.type + " here */ ;\n";
}); });
code += "\nvar " + contractName + "Contract = web3.eth.contract(" + interface.replace("\n","") + ");" code += "var " + contractName + "Contract = web3.eth.contract(" + interface.replace("\n","") + ");"
+"\nvar " + contractName + " = " + contractName + "Contract.new("; +"\nvar " + contractName + " = " + contractName + "Contract.new(";
$.each(funABI.inputs, function(i, inp) { $.each(funABI.inputs, function(i, inp) {
@ -450,27 +500,34 @@ THE SOFTWARE.
}; };
var renderContracts = function(data, source) { var renderContracts = function(data, source) {
$('#output').empty();
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: executionContext === 'vm',
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('uDApp', combined(contractName,contract['interface'],contract.bytecode), 'deploy')) .append(textRow('Bytecode', contract.bytecode))
.append(getDetails(contract, source, contractName)); .append(textRow('Interface', contract['interface']))
.append(textRow('Web3 deploy', gethDeploy(contractName.toLowerCase(),contract['interface'],contract.bytecode), 'deploy'))
$('#output').append(contractOutput); .append(textRow('uDApp', combined(contractName,contract['interface'],contract.bytecode), 'deploy'))
title.click(function(ev){ $(this).parent().toggleClass('hide') }); .append(getDetails(contract, source, contractName));
}
if (executionContext === 'vm') $('#txorigin').text('0x' + dapp.address.toString('hex'));
else web3.eth.getAccounts( function(err,accounts) {
if (err) renderError(err.message);
$('#txorigin').text(accounts[0]);
});
$contractOutput.find('.title').click(function(ev){ $(this).closest('.udapp').toggleClass('hide') });
$('#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 +548,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 +570,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 +609,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 +622,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>

@ -0,0 +1,340 @@
function UniversalDApp (contracts, options) {
this.options = options || {};
this.$el = $('<div class="udapp" />');
this.contracts = contracts;
if (!options.vm && web3.currentProvider) {
} else if (options.vm) {
this.stateTrie = new EthVm.Trie();
this.vm = new EthVm.VM(this.stateTrie);
//@todo this does not calculate the gas costs correctly but gets the job done.
this.identityCode = 'return { gasUsed: 1, return: opts.data, exception: 1 };';
this.identityAddr = ethUtil.pad(new Buffer('04', 'hex'), 20)
this.vm.loadPrecompiled(this.identityAddr, this.identityCode);
this.secretKey = '3cd7232cd6f3fc66a57a6bedc1a8ed6c228fff0a327e169c2bcc5e869ed49511'
this.publicKey = '0406cc661590d48ee972944b35ad13ff03c7876eae3fd191e8a2f77311b0a3c6613407b5005e63d7d8d76b89d5f900cde691497688bb281e07a5052ff61edebdc0'
this.address = ethUtil.pubToAddress(new Buffer(this.publicKey, 'hex'));
this.account = new EthVm.Account();
this.account.balance = 'f00000000000000001';
this.nonce = 0;
this.stateTrie.put(this.address, this.account.serialize());
} else {
var host = options.host || "localhost";
var port = options.port || "8545";
var rpc_url = 'http://' + host + ':' + port;
web3.setProvider( new web3.providers.HttpProvider( rpc_url ) );
}
}
UniversalDApp.prototype.render = function () {
if (this.contracts.length == 0) {
this.$el.append( this.getABIInputForm() );
} else {
for (var c in this.contracts) {
var $contractEl = $('<div class="contract"/>');
if (this.contracts[c].address) {
this.getInstanceInterface(this.contracts[c], this.contracts[c].address, $contractEl );
} else {
var $title = $('<span class="title"/>').text( this.contracts[c].name );
if (this.contracts[c].bytecode) {
$title.append($('<div class="size"/>').text((this.contracts[c].bytecode.length / 2) + ' bytes'))
}
$contractEl.append( $title ).append( this.getCreateInterface( $contractEl, this.contracts[c]) );
}
this.$el.append( $contractEl );
}
}
$legend = $('<div class="legend" />')
.append( $('<div class="attach"/>').text('Attach') )
.append( $('<div class="transact"/>').text('Transact') )
.append( $('<div class="call"/>').text('Call') )
this.$el.append( $('<div class="poweredBy" />')
.html("<a href='http://github.com/d11e9/universal-dapp'>Universal ÐApp</a> powered by The Blockchain") )
this.$el.append( $legend )
return this.$el;
}
UniversalDApp.prototype.getABIInputForm = function (cb){
var self = this;
var $el = $('<div class="udapp-setup" />');
var $jsonInput = $('<textarea class="json" placeholder=\'[ { "name": name, "bytecode": bytyecode, "interface": abi }, { ... } ]\'/>')
var $createButton = $('<button class="udapp-create"/>').text('Create a Universal ÐApp')
$createButton.click(function(ev){
var contracts = $.parseJSON( $jsonInput.val() );
if (cb) {
var err = null;
var dapp = null;
try {
dapp = new UniversalDApp( contracts, self.options );
} catch(e) {
err = e;
}
cb( err, dapp )
} else {
self.contracts = contracts;
self.$el.empty().append( self.render() )
}
})
$el.append( $jsonInput ).append( $createButton )
return $el;
}
UniversalDApp.prototype.getCreateInterface = function ($container, contract) {
var self = this;
var $createInterface = $('<div class="create"/>');
if (this.options.removable) {
var $close = $('<div class="udapp-close" />')
$close.click( function(){ self.$el.remove(); } )
$createInterface.append( $close );
}
var $newButton = this.getInstanceInterface( contract )
var $atButton = $('<button class="atAddress"/>').text('At Address').click( function(){ self.clickContractAt( self, $container, contract ) } );
$createInterface.append( $atButton ).append( $newButton );
return $createInterface;
}
UniversalDApp.prototype.getInstanceInterface = function (contract, address, $target) {
var self = this;
var abi = JSON.parse(contract.interface).sort(function(a,b){
if (a.name > b.name) return -1;
else return 1;
}).sort(function(a,b){
if (a.constant == true) return -1;
else return 1;
});
var funABI = this.getConstructorInterface(abi);
var $createInterface = $('<div class="createContract"/>');
var appendFunctions = function (address, $el){
var $instance = $('<div class="instance"/>');
if (self.options.removable_instances) {
var $close = $('<div class="udapp-close" />')
$close.click( function(){ $instance.remove(); } )
$instance.append( $close );
}
var context = self.options.vm ? 'memory' : 'blockchain';
var $title = $('<span class="title"/>').text( contract.name + " at " + (self.options.vm ? '0x' : '') + address.toString('hex') + ' (' + context + ')');
$title.click(function(){
$instance.toggleClass('hide');
});
$events = $('<div class="events"/>');
if (!self.options.vm){
var jsInterface = web3.eth.contract(abi).at(address)
var eventFilter = jsInterface.allEvents();
eventFilter.watch(function(err,response){
$event = $('<div class="event" />')
var $close = $('<div class="udapp-close" />')
$close.click( function(){ $event.remove(); } )
$event.append( $('<span class="name"/>').text(response.event) )
.append( $('<span class="args" />').text( JSON.stringify(response.args, null, 2) ) )
.append( $close );
$events.append( $event );
})
}
$instance.append( $title );
$.each(abi, function(i, funABI) {
if (funABI.type != 'function') return;
$instance.append(self.getCallButton({
abi: funABI,
address: address
}));
});
($el || $createInterface ).append( $instance.append( $events ) );
}
if (!address || !$target) {
$createInterface.append( this.getCallButton({
abi: funABI,
bytecode: contract.bytecode,
appendFunctions: appendFunctions
}));
} else {
appendFunctions( address, $target );
}
return $createInterface;
}
UniversalDApp.prototype.getConstructorInterface = function(abi) {
var funABI = {'name':'','inputs':[],'type':'constructor','outputs':[]};
for (var i = 0; i < abi.length; i++)
if (abi[i].type == 'constructor') {
funABI.inputs = abi[i].inputs || [];
break;
}
return funABI;
}
UniversalDApp.prototype.getCallButton = function(args) {
var self = this;
// args.abi, args.bytecode [constr only], args.address [fun only]
// args.appendFunctions [constr only]
var isConstructor = args.bytecode !== undefined;
var lookupOnly = ( args.abi.constant && !isConstructor );
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;
});
if (!args.bytecode && !fun.displayName()) return;
var inputField = $('<input/>').attr('placeholder', inputs).attr('title', inputs);
var $outputOverride = $('<div class="value" />');
var outputSpan = $('<div class="output"/>');
var getReturnOutput = function(result) {
var returnName = lookupOnly ? 'Value' : 'Result';
var returnCls = lookupOnly ? 'value' : 'returned';
return $('<div class="' + returnCls + '">').html('<strong>' + returnName + ':</strong> ' + JSON.stringify( result, null, 2 ) )
}
var getGasUsedOutput = function (result) {
var $gasUsed = $('<div class="gasUsed">')
var caveat = lookupOnly ? '<em>(<span class="caveat" title="Cost only applies when called by a contract">caveat</span>)</em>' : '';
if (result.gasUsed) {
var gas = result.gasUsed.toString(10)
$gasUsed.html('<strong>Cost:</strong> ' + gas + ' gas. ' + caveat )
}
return $gasUsed;
}
var getOutput = function() {
var values = Array.prototype.slice.call(arguments);
var $result = $('<div class="result" />');
var $close = $('<div class="udapp-close" />');
$close.click( function(){ $result.remove(); } );
$result.append( $close );
for( var v in values ) { $result.append( values[v] ); }
return $result;
}
var handleCallButtonClick = function( ev ) {
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);
var $result = getOutput( $('<a class="waiting" href="#" title="Waiting for transaction to be mined.">Polling for tx receipt...</a>') );
if (lookupOnly && !inputs.length) {
$outputOverride.empty().append( $result );
} else {
outputSpan.append( $result );
}
self.runTx(data, args, function(err, result) {
if (err) {
$result.replaceWith( getOutput( $('<span/>').text(err).addClass('error') ) );
} else if (self.options.vm && isConstructor) {
$result.replaceWith( getOutput( getGasUsedOutput( result ) ) );
args.appendFunctions(result.createdAddress);
} else if (self.options.vm){
var outputObj = fun.unpackOutput('0x' + result.vm.return.toString('hex'));
$result.replaceWith( getOutput( getReturnOutput( outputObj ), getGasUsedOutput( result.vm ) ) );
} else if (args.abi.constant && !isConstructor) {
$result.replaceWith( getOutput( getReturnOutput( result ) ) );
} else {
function tryTillResponse (txhash, done) {
web3.eth.getTransactionReceipt(result, testResult );
function testResult (err, address) {
if (!err && !address) {
setTimeout( function(){ tryTillResponse(txhash, done) }, 500);
} else done( err, address );
}
}
tryTillResponse( result, function(err, result) {
if (isConstructor) {
$result.html('');
args.appendFunctions(result.contractAddress);
} else $result.replaceWith( getOutput( getReturnOutput( result ), getGasUsedOutput( result ) ) );
})
}
});
}
var button = $('<button />')
.addClass( 'call' )
.attr('title', fun.displayName())
.text(args.bytecode ? 'Create' : fun.displayName())
.click( handleCallButtonClick );
if (lookupOnly && !inputs.length) {
handleCallButtonClick();
}
var $contractProperty = $('<div class="contractProperty"/>');
$contractProperty
.toggleClass( 'constant', !isConstructor && args.abi.constant )
.toggleClass( 'hasArgs', args.abi.inputs.length > 0)
.toggleClass( 'constructor', isConstructor)
.append(button)
.append( (lookupOnly && !inputs.length) ? $outputOverride : inputField );
return $contractProperty.append(outputSpan);
}
UniversalDApp.prototype.clickNewContract = function ( self, $contract, contract ) {
$contract.append( self.getInstanceInterface(contract) );
}
UniversalDApp.prototype.clickContractAt = function ( self, $contract, contract ) {
var address = prompt( "What Address is this contract at in the Blockchain? ie: '0xdeadbeaf...'" )
self.getInstanceInterface(contract, address, $contract );
}
UniversalDApp.prototype.runTx = function( data, args, cb) {
var to = args.address;
var constant = args.abi.constant;
var isConstructor = args.bytecode !== undefined;
if (!this.vm) {
if (constant && !isConstructor) {
var func = web3.eth.contract( [args.abi] ).at( to );
func[args.abi.name].call( cb );
} else {
var tx = {
from: web3.eth.accounts[0],
to: to,
data: data,
gas: 1000000
};
web3.eth.estimateGas( tx, function(err, resp){
tx.gas = resp;
if (!err) web3.eth.sendTransaction( tx, function(err, resp) {
cb( err, resp );
});
else cb( err, resp);
});
}
} else {
try {
var tx = new EthVm.Transaction({
nonce: new Buffer([this.nonce++]), //@todo count beyond 255
gasPrice: '01',
gasLimit: '3000000000', //plenty
to: to,
data: data
});
tx.sign(new Buffer(this.secretKey, 'hex'));
this.vm.runTx({tx: tx}, cb);
} catch (e) {
cb( e, null );
}
}
}

9
libs/web3.min.js vendored

File diff suppressed because one or more lines are too long

@ -110,6 +110,13 @@ body {
height: 5em; height: 5em;
} }
#header #executionContext {
padding: 0.4em 1em;
background-color: #efefef;
display: inline-block;
margin-left: 1em;
}
.col1 { .col1 {
width: 30%; width: 30%;
float: left; float: left;
@ -119,114 +126,122 @@ body {
float: left; float: left;
} }
.row { .udapp.hide {
overflow: auto; padding-bottom: 0;
}
.gethDeployText {
border-color: #bebebe;
height: 2.5em;
width: 100%;
display: block;
} }
.contractInstance { .udapp.hide > *:not(.contract) {
background-color: #ccc;
margin-bottom: 1em;
padding: 0.6em;
}
.contractInstance.hide > *:not(.title) {
display: none; display: none;
} }
.udapp.hide .contract {
.contractInstance .contractProperty input,
.contractInstance .contractProperty button {
text-align: left;
padding: 0.3em;
width: 50%;
margin: 0; margin: 0;
} }
.contractOutput .contractInstance .contractProperty {
margin-bottom: 0; .udapp.hide .contract > *:not(.title) {
} display: none;
.contractOutput .contractInstance .contractProperty .output {
padding: 0.4em;
background-color: #333;
color: white;
margin-bottom: 1em;
display: block;
} }
.contractInstance .contractProperty .output:empty { display: none; }
.contractOutput { .udapp .contract > .title {
border-bottom: 1px dotted black; cursor:pointer;
padding: 0.6em;
box-sizing: border-box;
} }
.contractOutput .contractProperty {
margin-bottom: 0.6em; .udapp .contract > .title:before {
content: "\25BC";
opacity: 0.5;
margin-right: 0.4em;
font-size: 10px;
} }
.contractOutput .contractProperty .output {
display: inline; .udapp.hide > .contract > .title:before {
content: "\25B6";
} }
#output .poweredBy,
#output .legend { display: none; }
.contractOutput .body { #output .udapp {
margin-top: 10px; border: 0 none;
box-shadow: none;
border-bottom: 1px dotted;
} }
.contractOutput.hide { #output .udapp button,
background-color: #4C4C67; #output .udapp input {
color: white; padding: 0.25em;
color: black;
} }
.contractOutput.hide > *:not(.title) { #output .udapp button {
display: none; border-color: #9E9D9D;
} }
.title { #output .udapp .atAddress { background-color: #B1EAC5; }
margin: 0; #output .udapp .contractProperty .call { background-color: #FF8B8B; }
cursor: pointer; #output .udapp .contractProperty.constant .call { background-color: #9DC1F5; }
font-family: monospace;
font-weight: bold; .row {
overflow: auto;
display: block;
clear: both;
margin: 0.5em;
} }
.title:before { .gethDeployText {
content: "\25BC"; border-color: #bebebe;
opacity: 0.5; height: 2.5em;
margin-right: 0.4em; width: 100%;
font-size: 10px; display: block;
} }
.hide > .title:before { .contractDetails button {
content: "\25B6"; background-color: transparent;
border: 0 none;
padding: 0;
display: inline-block;
text-decoration: underline;
color: blue;
cursor: pointer;
width: auto;
min-width: 4em;
margin-bottom: 1em;
} }
.contractOutput > .title {
border-bottom: #4C4C67; .sol.error,
.sol.warning {
border-radius: 0;
word-wrap: break-word;
cursor: pointer;
position: relative;
margin: 0.25em;
} }
.sol.error pre,
.sol.warning pre {
background-color: transparent;
margin: 0;
font-size: 10px;
border: 0 none;
}
.title .size { .sol.error .close,
font-weight: normal; .sol.warning .close {
float: right; font-weight: bold;
position: absolute;
top: 0;
right: 0;
padding: 0.5em;
} }
.error { .sol.error {
background-color: rgba(255, 0, 0, 0.5); background-color: rgba(255, 0, 0, 0.5);
border-radius: 0;
word-wrap: break-word;
border: 1px solid #D00909; border: 1px solid #D00909;
cursor: pointer;
} }
.warning { .sol.warning {
background-color: rgba(210, 202, 36, 0.5); background-color: rgba(210, 202, 36, 0.5);
border-radius: 0; border: 1px solid #BBB427;
word-wrap: break-word;
border: 1px solid #BBB427;
cursor: pointer;
} }
#ghostbar { #ghostbar {
@ -243,8 +258,8 @@ body {
#dragbar{ #dragbar{
background-color: transparent; background-color: transparent;
position: absolute; position: absolute;
width: 5px; width: 10px;
left: 0; right: -10px;
top: 0; top: 0;
bottom: 0; bottom: 0;
cursor: col-resize; cursor: col-resize;

@ -0,0 +1,282 @@
.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,
.udapp .caveat {
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-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;
position: relative;
}
.udapp .title .size {
position: absolute;
right: 2.2em;
top: 0.2em;
font-weight: normal;
}
.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;
z-index: 9999;
}
.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;
overflow: hidden;
text-overflow: ellipsis;
}
.udapp .instance input,
.udapp .instance button {
width: 50%;
float: left;
box-sizing: border-box;
}
.udapp .contractProperty.hasArgs input {
width: 75%;
}
.udapp .contractProperty button {
width: 25%;
}
.udapp .contractProperty .call {
background-color: #D42828;
}
.udapp .contractProperty.constant .call {
background-color: #556DF3;
width: 25%;
}
.udapp .contractProperty input {
display: none;
}
.udapp .contractProperty > .value {
padding: 0 0.4em;
box-sizing: border-box;
width: 75%;
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;
}
Loading…
Cancel
Save