').append(second));
- };
- var tableRow = function(description, data) {
- return tableRowItems(
- $('
').text(description),
- $('
').val(data));
- };
- var textRow = function(description, data, cls) {
- return tableRowItems(
- $('
').text(description),
- $('
').val(data),
- cls);
- };
- var getDetails = function(contract, source, contractName) {
- var button = $('
');
- var details = $('
')
- .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($('
Functions'));
- details.append($('
').text(funHashes));
- details.append($('
Gas Estimates'));
- details.append($('
').text(formatGasEstimates(contract.gasEstimates)));
- if (contract.runtimeBytecode && contract.runtimeBytecode.length > 0)
- details.append(tableRow('Runtime Bytecode', contract.runtimeBytecode));
- if (contract.assembly !== null)
- {
- details.append($('
Assembly'));
- var assembly = $('
').text(formatAssemblyText(contract.assembly, '', source));
- details.append(assembly);
- }
- button.click(function() { detailsOpen[contractName] = !detailsOpen[contractName]; details.toggle(); });
- if (detailsOpen[contractName])
- details.show();
- return $('
').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;
- };
$('.asmOutput button').click(function() {$(this).parent().find('pre').toggle(); });
- var 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;
- };
// ----------------- compiler ----------------------
@@ -659,7 +453,7 @@ var run = function() {
return $.getJSON('https://api.github.com/repos/' + root + '/contents/' + path, cb);
}
- var compiler = new Compiler(editor, renderContracts, renderError, handleGithubCall, $('#output'), function() { return hidingRHP; });
+ var compiler = new Compiler(editor, handleGithubCall, $('#output'), getHidingRHP, updateFiles);
function setVersionText(text) {
$('#version').text(text);
diff --git a/src/app/compiler.js b/src/app/compiler.js
index 0435de666b..78075d7420 100644
--- a/src/app/compiler.js
+++ b/src/app/compiler.js
@@ -1,9 +1,11 @@
var queryParams = require('./query-params');
var utils = require('./utils');
+var Renderer = require('./renderer');
var Base64 = require('js-base64').Base64;
-function Compiler(editor, renderContracts, renderError, handleGithubCall, outputField, hidingRHP) {
+function Compiler(editor, handleGithubCall, outputField, hidingRHP, updateFiles) {
+ var renderer = new Renderer(editor, this, updateFiles);
var compileJSON;
var compilerAcceptsMultipleFiles;
@@ -19,7 +21,7 @@ function Compiler(editor, renderContracts, renderError, handleGithubCall, output
function onChange() {
var input = editor.getValue();
if (input === "") {
- window.localStorage.setItem(editor.getCacheFile(), '');
+ window.localStorage.setItem(editor.getRawCacheFile(), '');
return;
}
if (input === previousInput)
@@ -36,14 +38,14 @@ function Compiler(editor, renderContracts, renderError, handleGithubCall, output
sourceAnnotations = [];
outputField.empty();
var input = editor.getValue();
- window.localStorage.setItem(editor.getCacheFile(), input);
+ window.localStorage.setItem(editor.getRawCacheFile(), input);
var files = {};
- files[utils.fileNameFromKey(editor.getCacheFile())] = input;
+ files[editor.getCacheFile()] = input;
gatherImports(files, missingInputs, function(input, error) {
outputField.empty();
if (input === null) {
- renderError(error);
+ render.error(error);
} else {
var optimize = queryParams.get().optimize;
compileJSON(input, optimize ? 1 : 0);
@@ -104,17 +106,17 @@ function Compiler(editor, renderContracts, renderError, handleGithubCall, output
try {
data = JSON.parse(result);
} catch (exception) {
- renderError('Invalid JSON output from the compiler: ' + exception);
+ renderer.error('Invalid JSON output from the compiler: ' + exception);
return;
}
if (data['error'] !== undefined) {
- renderError(data['error']);
+ renderer.error(data['error']);
if (utils.errortype(data['error']) !== 'warning') noFatalErrors = false;
}
if (data['errors'] != undefined) {
data['errors'].forEach(function(err) {
- renderError(err);
+ renderer.error(err);
if (utils.errortype(err) !== 'warning') noFatalErrors = false;
});
}
@@ -122,7 +124,7 @@ function Compiler(editor, renderContracts, renderError, handleGithubCall, output
if (missingInputs !== undefined && missingInputs.length > 0)
this.compile(missingInputs);
else if (noFatalErrors && !hidingRHP())
- renderContracts(data, editor.getValue());
+ renderer.contracts(data, editor.getValue());
}
this.initializeWorker = function(version, setVersionText) {
@@ -154,7 +156,7 @@ function Compiler(editor, renderContracts, renderError, handleGithubCall, output
importHints = importHints || [];
if (!compilerAcceptsMultipleFiles)
{
- cb(files[utils.fileNameFromKey(editor.getCacheFile())]);
+ cb(files[editor.getCacheFile()]);
return;
}
var importRegex = /^\s*import\s*[\'\"]([^\'\"]+)[\'\"];/g;
diff --git a/src/app/editor.js b/src/app/editor.js
index d19a102c6e..9360f09339 100644
--- a/src/app/editor.js
+++ b/src/app/editor.js
@@ -18,6 +18,10 @@ function Editor(loadingFromGist) {
SOL_CACHE_FILE = utils.fileKey(cacheFile);
};
+ this.getRawCacheFile = function() {
+ return SOL_CACHE_FILE;
+ };
+
this.getCacheFile = function() {
return utils.fileNameFromKey(SOL_CACHE_FILE);
};
diff --git a/src/app/renderer.js b/src/app/renderer.js
new file mode 100644
index 0000000000..9b2585507a
--- /dev/null
+++ b/src/app/renderer.js
@@ -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 = $("
").text(message);
+ var $error = $('
').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($('
').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 $('
')
+ .addClass(cls)
+ .append($('
').append(first))
+ .append($('
').append(second));
+ };
+ var tableRow = function(description, data) {
+ return tableRowItems(
+ $('
').text(description),
+ $('
').val(data));
+ };
+ var textRow = function(description, data, cls) {
+ return tableRowItems(
+ $('
').text(description),
+ $('
').val(data),
+ cls);
+ };
+
+ var getDetails = function(contract, source, contractName) {
+ var button = $('
');
+ var details = $('
')
+ .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($('
Functions'));
+ details.append($('
').text(funHashes));
+ details.append($('
Gas Estimates'));
+ details.append($('
').text(formatGasEstimates(contract.gasEstimates)));
+ if (contract.runtimeBytecode && contract.runtimeBytecode.length > 0)
+ details.append(tableRow('Runtime Bytecode', contract.runtimeBytecode));
+ if (contract.assembly !== null)
+ {
+ details.append($('
Assembly'));
+ var assembly = $('
').text(formatAssemblyText(contract.assembly, '', source));
+ details.append(assembly);
+ }
+ button.click(function() { detailsOpen[contractName] = !detailsOpen[contractName]; details.toggle(); });
+ if (detailsOpen[contractName])
+ details.show();
+ return $('
').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;