parent
0a37e6a3fb
commit
fe1bc22117
@ -0,0 +1,230 @@ |
|||||||
|
var $ = require('jquery'); |
||||||
|
|
||||||
|
var UniversalDApp = require('../universal-dapp.js'); |
||||||
|
|
||||||
|
var utils = require('./utils'); |
||||||
|
|
||||||
|
function Renderer(editor, compiler, updateFiles) { |
||||||
|
|
||||||
|
var detailsOpen = {}; |
||||||
|
|
||||||
|
function renderError(message) { |
||||||
|
var type = utils.errortype(message); |
||||||
|
var $pre = $("<pre />").text(message); |
||||||
|
var $error = $('<div class="sol ' + type + '"><div class="close"><i class="fa fa-close"></i></div></div>').prepend($pre); |
||||||
|
$('#output').append( $error ); |
||||||
|
var err = message.match(/^([^:]*):([0-9]*):(([0-9]*):)? /); |
||||||
|
if (err) { |
||||||
|
var errFile = err[1]; |
||||||
|
var errLine = parseInt(err[2], 10) - 1; |
||||||
|
var errCol = err[4] ? parseInt(err[4], 10) : 0; |
||||||
|
if (errFile == '' || errFile == editor.getCacheFile()) { |
||||||
|
compiler.addAnnotation({ |
||||||
|
row: errLine, |
||||||
|
column: errCol, |
||||||
|
text: message, |
||||||
|
type: type |
||||||
|
}); |
||||||
|
} |
||||||
|
$error.click(function(ev){ |
||||||
|
if (errFile != '' && errFile != editor.getCacheFile() && editor.getFiles().indexOf(utils.fileKey(errFile)) !== -1) { |
||||||
|
// Switch to file
|
||||||
|
editor.setCacheFile(errFile); |
||||||
|
updateFiles(); |
||||||
|
//@TODO could show some error icon in files with errors
|
||||||
|
} |
||||||
|
editor.handleErrorClick(errLine, errCol); |
||||||
|
}); |
||||||
|
$error.find('.close').click(function(ev){ |
||||||
|
ev.preventDefault(); |
||||||
|
$error.remove(); |
||||||
|
return false; |
||||||
|
}); |
||||||
|
} |
||||||
|
}; |
||||||
|
this.error = renderError; |
||||||
|
|
||||||
|
var combined = function(contractName, interface, bytecode){ |
||||||
|
return JSON.stringify([{name: contractName, interface: interface, bytecode: bytecode}]); |
||||||
|
}; |
||||||
|
|
||||||
|
function renderContracts(data, source) { |
||||||
|
|
||||||
|
var udappContracts = []; |
||||||
|
for (var contractName in data.contracts) { |
||||||
|
var contract = data.contracts[contractName]; |
||||||
|
udappContracts.push({ |
||||||
|
name: contractName, |
||||||
|
interface: contract['interface'], |
||||||
|
bytecode: contract.bytecode |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
var dapp = new UniversalDApp(udappContracts, { |
||||||
|
vm: executionContext === 'vm', |
||||||
|
removable: false, |
||||||
|
getAddress: function(){ return $('#txorigin').val(); }, |
||||||
|
getValue: function(){ |
||||||
|
var comp = $('#value').val().split(' '); |
||||||
|
return web3.toWei(comp[0], comp.slice(1).join(' ')); |
||||||
|
}, |
||||||
|
removable_instances: true, |
||||||
|
renderOutputModifier: function(contractName, $contractOutput) { |
||||||
|
var contract = data.contracts[contractName]; |
||||||
|
return $contractOutput |
||||||
|
.append(textRow('Bytecode', contract.bytecode)) |
||||||
|
.append(textRow('Interface', contract['interface'])) |
||||||
|
.append(textRow('Web3 deploy', gethDeploy(contractName.toLowerCase(),contract['interface'],contract.bytecode), 'deploy')) |
||||||
|
.append(textRow('uDApp', combined(contractName,contract['interface'],contract.bytecode), 'deploy')) |
||||||
|
.append(getDetails(contract, source, contractName)); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
var $contractOutput = dapp.render(); |
||||||
|
|
||||||
|
$txOrigin = $('#txorigin'); |
||||||
|
|
||||||
|
function renderAccounts(err, accounts) { |
||||||
|
if (err) |
||||||
|
renderError(err.message); |
||||||
|
if (accounts && accounts[0]){ |
||||||
|
$txOrigin.empty(); |
||||||
|
for( var a in accounts) { $txOrigin.append($('<option />').val(accounts[a]).text(accounts[a])); } |
||||||
|
$txOrigin.val(accounts[0]); |
||||||
|
} else $txOrigin.val('unknown'); |
||||||
|
} |
||||||
|
|
||||||
|
dapp.getAccounts(renderAccounts); |
||||||
|
|
||||||
|
$contractOutput.find('.title').click(function(ev){ $(this).closest('.contract').toggleClass('hide'); }); |
||||||
|
$('#output').append( $contractOutput ); |
||||||
|
$('.col2 input,textarea').click(function() { this.select(); }); |
||||||
|
}; |
||||||
|
this.contracts = renderContracts; |
||||||
|
|
||||||
|
var tableRowItems = function(first, second, cls) { |
||||||
|
return $('<div class="crow"/>') |
||||||
|
.addClass(cls) |
||||||
|
.append($('<div class="col1">').append(first)) |
||||||
|
.append($('<div class="col2">').append(second)); |
||||||
|
}; |
||||||
|
var tableRow = function(description, data) { |
||||||
|
return tableRowItems( |
||||||
|
$('<span/>').text(description), |
||||||
|
$('<input readonly="readonly"/>').val(data)); |
||||||
|
}; |
||||||
|
var textRow = function(description, data, cls) { |
||||||
|
return tableRowItems( |
||||||
|
$('<strong/>').text(description), |
||||||
|
$('<textarea readonly="readonly" class="gethDeployText"/>').val(data), |
||||||
|
cls); |
||||||
|
}; |
||||||
|
|
||||||
|
var getDetails = function(contract, source, contractName) { |
||||||
|
var button = $('<button>Toggle Details</button>'); |
||||||
|
var details = $('<div style="display: none;"/>') |
||||||
|
.append(tableRow('Solidity Interface', contract.solidity_interface)) |
||||||
|
.append(tableRow('Opcodes', contract.opcodes)); |
||||||
|
var funHashes = ''; |
||||||
|
for (var fun in contract.functionHashes) |
||||||
|
funHashes += contract.functionHashes[fun] + ' ' + fun + '\n'; |
||||||
|
details.append($('<span class="col1">Functions</span>')); |
||||||
|
details.append($('<pre/>').text(funHashes)); |
||||||
|
details.append($('<span class="col1">Gas Estimates</span>')); |
||||||
|
details.append($('<pre/>').text(formatGasEstimates(contract.gasEstimates))); |
||||||
|
if (contract.runtimeBytecode && contract.runtimeBytecode.length > 0) |
||||||
|
details.append(tableRow('Runtime Bytecode', contract.runtimeBytecode)); |
||||||
|
if (contract.assembly !== null) |
||||||
|
{ |
||||||
|
details.append($('<span class="col1">Assembly</span>')); |
||||||
|
var assembly = $('<pre/>').text(formatAssemblyText(contract.assembly, '', source)); |
||||||
|
details.append(assembly); |
||||||
|
} |
||||||
|
button.click(function() { detailsOpen[contractName] = !detailsOpen[contractName]; details.toggle(); }); |
||||||
|
if (detailsOpen[contractName]) |
||||||
|
details.show(); |
||||||
|
return $('<div class="contractDetails"/>').append(button).append(details); |
||||||
|
}; |
||||||
|
|
||||||
|
var formatGasEstimates = function(data) { |
||||||
|
var gasToText = function(g) { return g === null ? 'unknown' : g; } |
||||||
|
var text = ''; |
||||||
|
if ('creation' in data) |
||||||
|
text += 'Creation: ' + gasToText(data.creation[0]) + ' + ' + gasToText(data.creation[1]) + '\n'; |
||||||
|
text += 'External:\n'; |
||||||
|
for (var fun in data.external) |
||||||
|
text += ' ' + fun + ': ' + gasToText(data.external[fun]) + '\n'; |
||||||
|
text += 'Internal:\n'; |
||||||
|
for (var fun in data.internal) |
||||||
|
text += ' ' + fun + ': ' + gasToText(data.internal[fun]) + '\n'; |
||||||
|
return text; |
||||||
|
}; |
||||||
|
|
||||||
|
var formatAssemblyText = function(asm, prefix, source) { |
||||||
|
if (typeof(asm) == typeof('') || asm === null || asm === undefined) |
||||||
|
return prefix + asm + '\n'; |
||||||
|
var text = prefix + '.code\n'; |
||||||
|
$.each(asm['.code'], function(i, item) { |
||||||
|
var v = item.value === undefined ? '' : item.value; |
||||||
|
var src = ''; |
||||||
|
if (item.begin !== undefined && item.end != undefined) |
||||||
|
src = source.slice(item.begin, item.end).replace('\n', '\\n', 'g'); |
||||||
|
if (src.length > 30) |
||||||
|
src = src.slice(0, 30) + '...'; |
||||||
|
if (item.name != 'tag') |
||||||
|
text += ' '; |
||||||
|
text += prefix + item.name + ' ' + v + '\t\t\t' + src + '\n'; |
||||||
|
}); |
||||||
|
text += prefix + '.data\n'; |
||||||
|
if (asm['.data']) |
||||||
|
$.each(asm['.data'], function(i, item) { |
||||||
|
text += ' ' + prefix + '' + i + ':\n'; |
||||||
|
text += formatAssemblyText(item, prefix + ' ', source); |
||||||
|
}); |
||||||
|
|
||||||
|
return text; |
||||||
|
}; |
||||||
|
|
||||||
|
function gethDeploy(contractName, interface, bytecode){ |
||||||
|
var code = ""; |
||||||
|
var funABI = getConstructorInterface(JSON.parse(interface)); |
||||||
|
|
||||||
|
funABI.inputs.forEach(function(inp) { |
||||||
|
code += "var " + inp.name + " = /* var of type " + inp.type + " here */ ;\n"; |
||||||
|
}); |
||||||
|
|
||||||
|
code += "var " + contractName + "Contract = web3.eth.contract(" + interface.replace("\n","") + ");" |
||||||
|
+"\nvar " + contractName + " = " + contractName + "Contract.new("; |
||||||
|
|
||||||
|
funABI.inputs.forEach(function(inp) { |
||||||
|
code += "\n " + inp.name + ","; |
||||||
|
}); |
||||||
|
|
||||||
|
code += "\n {"+ |
||||||
|
"\n from: web3.eth.accounts[0], "+ |
||||||
|
"\n data: '"+bytecode+"', "+ |
||||||
|
"\n gas: 3000000"+ |
||||||
|
"\n }, function(e, contract){"+ |
||||||
|
"\n console.log(e, contract);"+ |
||||||
|
"\n if (typeof contract.address != 'undefined') {"+ |
||||||
|
"\n console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);" + |
||||||
|
"\n }" + |
||||||
|
"\n })"; |
||||||
|
|
||||||
|
|
||||||
|
return code; |
||||||
|
} |
||||||
|
|
||||||
|
function getConstructorInterface(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; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
module.exports = Renderer; |
Loading…
Reference in new issue