From 9e469cc83ed0c7ef778c57e6ce20b83697522b6c Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Thu, 22 Mar 2018 10:43:29 -0400 Subject: [PATCH 01/22] Initial commit for graphviz functionality - Added required packages - Added command to cmd.js - Created graph.js to contain graph logic --- lib/cmd.js | 15 +++++++++++++++ lib/cmds/graph.js | 17 +++++++++++++++++ lib/index.js | 7 +++++++ package.json | 3 +++ 4 files changed, 42 insertions(+) create mode 100644 lib/cmds/graph.js diff --git a/lib/cmd.js b/lib/cmd.js index ab76482a..2977d69e 100644 --- a/lib/cmd.js +++ b/lib/cmd.js @@ -18,6 +18,7 @@ class Cmd { this.simulator(); this.test(); this.reset(); + this.graph(); this.upload(); this.versionCmd(); this.otherCommands(); @@ -171,6 +172,19 @@ class Cmd { }); } + graph() { + program + .command('graph [environment]') + .description('generates documentation based on the smart contracts configured') + .action(function (env, options) { + embark.initConfig(env || 'development', { + embarkConfig: 'embark.json', + interceptLogs: false + }); + embark.graph(); + }); + } + reset() { program .command('reset') @@ -206,6 +220,7 @@ class Cmd { process.exit(0); }); } + } diff --git a/lib/cmds/graph.js b/lib/cmds/graph.js new file mode 100644 index 00000000..dba9c2aa --- /dev/null +++ b/lib/cmds/graph.js @@ -0,0 +1,17 @@ +const fs = require("fs"); +const klaw = require('klaw'); +const path = require('path'); +const SolidityParser = require("solidity-parser"); +const Viz = require('viz.js'); + +class GraphGenerator { + constructor(config) { + this.config = config; + } + + generate() { + console.log("TODO"); + } +} + +module.exports = GraphGenerator; diff --git a/lib/index.js b/lib/index.js index e08870ae..14a78911 100644 --- a/lib/index.js +++ b/lib/index.js @@ -185,6 +185,13 @@ class Embark { return new Test(options); } + graph() { + const GraphGenerator = new require('./cmds/graph.js'); + console.log(this.config); + let graphGen = new GraphGenerator(this.config); + graphGen.generate(); + } + reset() { let resetCmd = require('./cmds/reset.js'); resetCmd(); diff --git a/package.json b/package.json index 9de8bab9..7807007d 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "globule": "^1.1.0", "http-shutdown": "^1.2.0", "ipfs-api": "17.2.4", + "klaw": "^2.1.1", "merge": "^1.2.0", "mocha": "^2.2.5", "orbit-db": "^0.17.3", @@ -51,12 +52,14 @@ "serve-static": "^1.11.1", "shelljs": "^0.5.0", "solc": "0.4.17", + "solidity-parser": "^0.4.0", "style-loader": "^0.19.0", "tar": "^3.1.5", "toposort": "^1.0.0", "underscore": "^1.8.3", "underscore.string": "^3.3.4", "url-loader": "^0.6.2", + "viz.js": "^1.8.1", "web3": "1.0.0-beta.27", "webpack": "^3.10.0", "window-size": "^1.1.0" From d7b33a309be2c49cecee99950244164bb9d36a71 Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Thu, 22 Mar 2018 15:09:01 -0400 Subject: [PATCH 02/22] Changed logic of deploy manager to be able to only compile the code and not deploy it --- lib/cmd.js | 7 ++-- lib/contracts/deploy_manager.js | 8 ++++ lib/core/engine.js | 3 +- lib/index.js | 69 ++++++++++++++++++++++++++++++--- 4 files changed, 77 insertions(+), 10 deletions(-) diff --git a/lib/cmd.js b/lib/cmd.js index 2977d69e..5df6eb61 100644 --- a/lib/cmd.js +++ b/lib/cmd.js @@ -177,11 +177,10 @@ class Cmd { .command('graph [environment]') .description('generates documentation based on the smart contracts configured') .action(function (env, options) { - embark.initConfig(env || 'development', { - embarkConfig: 'embark.json', - interceptLogs: false + embark.graph({ + env: env || 'development', + logfile: options.logfile }); - embark.graph(); }); } diff --git a/lib/contracts/deploy_manager.js b/lib/contracts/deploy_manager.js index 0562574e..edcd49e7 100644 --- a/lib/contracts/deploy_manager.js +++ b/lib/contracts/deploy_manager.js @@ -17,6 +17,7 @@ class DeployManager { this.gasLimit = false; this.fatalErrors = false; this.deployOnlyOnConfig = false; + this.onlyCompile = options.onlyCompile !== undefined ? options.onlyCompile : false; } deployContracts(done) { @@ -33,6 +34,13 @@ class DeployManager { self.contractsManager.deployOnlyOnConfig = self.deployOnlyOnConfig; // temporary, should refactor self.contractsManager.build(callback); }, + function checkCompileOnly(contractsManager, callback){ + if(self.onlyCompile){ + self.events.emit('contractsDeployed', contractsManager); + return done(); + } + return callback(contractsManager, null); + }, function checkWeb3IsConnected(contractsManager, callback) { if (!self.web3) { return callback(Error("no web3 instance found")); diff --git a/lib/core/engine.js b/lib/core/engine.js index 53ee6203..4d3bb00e 100644 --- a/lib/core/engine.js +++ b/lib/core/engine.js @@ -153,7 +153,8 @@ class Engine { logger: this.logger, plugins: this.plugins, events: this.events, - contractsManager: this.contractsManager + contractsManager: this.contractsManager, + onlyCompile: options.onlyCompile }); this.events.on('file-event', function (fileType, _path) { diff --git a/lib/index.js b/lib/index.js index 14a78911..21bc71f4 100644 --- a/lib/index.js +++ b/lib/index.js @@ -185,11 +185,70 @@ class Embark { return new Test(options); } - graph() { - const GraphGenerator = new require('./cmds/graph.js'); - console.log(this.config); - let graphGen = new GraphGenerator(this.config); - graphGen.generate(); + graph(options) { + + + + let self = this; + + options.onlyCompile = true; + + let engine = new Engine({ + env: options.env, + version: this.version, + embarkConfig: options.embarkConfig || 'embark.json', + logfile: options.logfile + }); + engine.init(); + + + async.parallel([ + + function (callback) { + let pluginList = engine.plugins.listPlugins(); + if (pluginList.length > 0) { + engine.logger.info("loaded plugins: " + pluginList.join(", ")); + } + + engine.startMonitor(); + engine.startService("libraryManager"); + engine.startService("pipeline"); + engine.startService("codeGenerator"); + engine.startService("deployment", {onlyCompile: true}); + + engine.deployManager.deployContracts(function (err) { + callback(err); + }); + } + ], function (err, _result) { + if (err) { + engine.logger.error(err.message); + engine.logger.info(err.stack); + } else { + + const GraphGenerator = require('./cmds/graph.js'); + let graphGen = new GraphGenerator(engine.config); + graphGen.generate(); + + engine.logger.info("Done".underline); + process.exit(); + } + }); + + + + + + + + + + + + + + + } reset() { From 01eaa0fe7f15a7891ee70271c31b6c02474c4c63 Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Thu, 22 Mar 2018 16:18:13 -0400 Subject: [PATCH 03/22] Generating basic diagram that includes methods --- lib/cmds/graph.js | 61 +++++++++++++++++++++++++++++++++++++++++------ lib/index.js | 16 +------------ 2 files changed, 55 insertions(+), 22 deletions(-) diff --git a/lib/cmds/graph.js b/lib/cmds/graph.js index dba9c2aa..8bc67086 100644 --- a/lib/cmds/graph.js +++ b/lib/cmds/graph.js @@ -1,16 +1,63 @@ -const fs = require("fs"); -const klaw = require('klaw'); -const path = require('path'); -const SolidityParser = require("solidity-parser"); const Viz = require('viz.js'); +const fs = require('fs'); class GraphGenerator { - constructor(config) { - this.config = config; + constructor(engine) { + this.engine = engine; } generate() { - console.log("TODO"); + let id = 0; + let contractString = ""; + + for (let contract in this.engine.contractsManager.contracts) { + id++; + let contractLabel = ""; + + contractLabel += `${contract}`; + + let fHashes = this.engine.contractsManager.contracts[contract].functionHashes; + if(fHashes != {} && fHashes != undefined){ + contractLabel += "|"; + for(let method in this.engine.contractsManager.contracts[contract].functionHashes){ + contractLabel += method + '\\l'; + } + } + + for(let i = 0; i < this.engine.contractsManager.contracts[contract].abiDefinition.length; i++){ + if(this.engine.contractsManager.contracts[contract].abiDefinition[i].type == 'fallback') + contractLabel += "«fallback»()" + '\\l'; + } + + /*if(c.methods.length > 0){ + contractLabel += "|"; + c.methods.forEach(function(a){ + contractLabel += a + '\\l'; + }) + + } */ + + contractString += `${id}[label = "{${contractLabel}}"]` + contractString += "\n"; + } + + + let dot = ` + digraph hierarchy { + node[shape=record,style=filled,fillcolor=gray95] + edge[dir=back, arrowtail=empty] + ${contractString} + }`; + + let svg = Viz(dot); + + let filename = "diagram.svg"; + + fs.writeFileSync(filename, svg, (err) => { + if (err) throw err; + }); + + } } diff --git a/lib/index.js b/lib/index.js index 21bc71f4..d31decd9 100644 --- a/lib/index.js +++ b/lib/index.js @@ -227,7 +227,7 @@ class Embark { } else { const GraphGenerator = require('./cmds/graph.js'); - let graphGen = new GraphGenerator(engine.config); + let graphGen = new GraphGenerator(engine); graphGen.generate(); engine.logger.info("Done".underline); @@ -235,20 +235,6 @@ class Embark { } }); - - - - - - - - - - - - - - } reset() { From 403f2daee2e18ff4d6eb946da76fb54936e71696 Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Thu, 22 Mar 2018 17:11:11 -0400 Subject: [PATCH 04/22] Added relationships between contracts --- lib/cmds/graph.js | 61 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/lib/cmds/graph.js b/lib/cmds/graph.js index 8bc67086..b9dfcb4c 100644 --- a/lib/cmds/graph.js +++ b/lib/cmds/graph.js @@ -9,44 +9,77 @@ class GraphGenerator { generate() { let id = 0; let contractString = ""; + let relationshipString = ""; + let idMapping = {}; + let contractInheritance = {}; + for (let contract in this.engine.contractsManager.contracts) { id++; + + idMapping[contract] = id; + let contractLabel = ""; contractLabel += `${contract}`; + if(this.engine.contractsManager.contracts[contract].instanceOf !== undefined && + this.engine.contractsManager.contracts[this.engine.contractsManager.contracts[contract].instanceOf] !== undefined){ + contractInheritance[contract] = this.engine.contractsManager.contracts[contract].instanceOf; + } + + contractLabel += "|"; + + for(let i = 0; i < this.engine.contractsManager.contracts[contract].abiDefinition.length; i++){ + switch(this.engine.contractsManager.contracts[contract].abiDefinition[i].type){ + case 'fallback': + contractLabel += "«fallback»()" + '\\l'; + break; + case 'constructor': + contractLabel += "«constructor»("; + for(let j = 0; j < this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs.length; j++){ + contractLabel += (j == 0 ? "" : ", ") + this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs[j].type; + } + contractLabel += ")\\l"; + break; + default: break; + } + } + let fHashes = this.engine.contractsManager.contracts[contract].functionHashes; if(fHashes != {} && fHashes != undefined){ - contractLabel += "|"; for(let method in this.engine.contractsManager.contracts[contract].functionHashes){ contractLabel += method + '\\l'; } } - - for(let i = 0; i < this.engine.contractsManager.contracts[contract].abiDefinition.length; i++){ - if(this.engine.contractsManager.contracts[contract].abiDefinition[i].type == 'fallback') - contractLabel += "«fallback»()" + '\\l'; - } - - /*if(c.methods.length > 0){ - contractLabel += "|"; - c.methods.forEach(function(a){ - contractLabel += a + '\\l'; - }) - - } */ + contractString += `${id}[label = "{${contractLabel}}"]` contractString += "\n"; } + for (let c in this.engine.contractsManager.contractDependencies){ + let contractDependencies = Array.from(new Set(this.engine.contractsManager.contractDependencies[c])); + contractDependencies.forEach(function(d){ + if(idMapping[c] !== undefined && idMapping[d] !== undefined){ + relationshipString += `${idMapping[d]}->${idMapping[c]}[constraint=true, arrowtail=diamond]` + relationshipString += "\n"; + } + }); + } + + for (let c in contractInheritance){ + relationshipString += `${idMapping[contractInheritance[c]]}->${idMapping[c]}` + relationshipString += "\n"; + } + let dot = ` digraph hierarchy { node[shape=record,style=filled,fillcolor=gray95] edge[dir=back, arrowtail=empty] ${contractString} + ${relationshipString} }`; let svg = Viz(dot); From 7dcae55b8bf1e4afacf7e3644f2b1735c7a88e9e Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Fri, 23 Mar 2018 08:28:42 -0400 Subject: [PATCH 05/22] Added events to graph and fixed problems in IDE --- lib/cmds/graph.js | 21 +++++++++++++-------- lib/index.js | 5 ----- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/cmds/graph.js b/lib/cmds/graph.js index b9dfcb4c..073ddd6c 100644 --- a/lib/cmds/graph.js +++ b/lib/cmds/graph.js @@ -33,15 +33,22 @@ class GraphGenerator { for(let i = 0; i < this.engine.contractsManager.contracts[contract].abiDefinition.length; i++){ switch(this.engine.contractsManager.contracts[contract].abiDefinition[i].type){ case 'fallback': - contractLabel += "«fallback»()" + '\\l'; + contractLabel += "«fallback»()\\l"; break; - case 'constructor': + case 'constructor': contractLabel += "«constructor»("; for(let j = 0; j < this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs.length; j++){ contractLabel += (j == 0 ? "" : ", ") + this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs[j].type; } contractLabel += ")\\l"; break; + case 'event': + contractLabel += "«event»" + this.engine.contractsManager.contracts[contract].abiDefinition[i].name + "("; + for(let j = 0; j < this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs.length; j++){ + contractLabel += (j == 0 ? "" : ", ") + this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs[j].type; + } + contractLabel += ")\\l"; + break; default: break; } } @@ -54,23 +61,21 @@ class GraphGenerator { } - contractString += `${id}[label = "{${contractLabel}}"]` - contractString += "\n"; + contractString += `${id}[label = "{${contractLabel}}"]\n`; + } for (let c in this.engine.contractsManager.contractDependencies){ let contractDependencies = Array.from(new Set(this.engine.contractsManager.contractDependencies[c])); contractDependencies.forEach(function(d){ if(idMapping[c] !== undefined && idMapping[d] !== undefined){ - relationshipString += `${idMapping[d]}->${idMapping[c]}[constraint=true, arrowtail=diamond]` - relationshipString += "\n"; + relationshipString += `${idMapping[d]}->${idMapping[c]}[constraint=true, arrowtail=diamond]\n`; } }); } for (let c in contractInheritance){ - relationshipString += `${idMapping[contractInheritance[c]]}->${idMapping[c]}` - relationshipString += "\n"; + relationshipString += `${idMapping[contractInheritance[c]]}->${idMapping[c]}\n`; } diff --git a/lib/index.js b/lib/index.js index d31decd9..42315373 100644 --- a/lib/index.js +++ b/lib/index.js @@ -186,11 +186,6 @@ class Embark { } graph(options) { - - - - let self = this; - options.onlyCompile = true; let engine = new Engine({ From 5d0e86bb727c8d28585e8e8cf6441111b0774a9c Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Fri, 23 Mar 2018 11:27:21 -0400 Subject: [PATCH 06/22] Removed unneeded packages and added tooltips and colors --- package.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/package.json b/package.json index 7807007d..90591420 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,6 @@ "globule": "^1.1.0", "http-shutdown": "^1.2.0", "ipfs-api": "17.2.4", - "klaw": "^2.1.1", "merge": "^1.2.0", "mocha": "^2.2.5", "orbit-db": "^0.17.3", @@ -52,7 +51,6 @@ "serve-static": "^1.11.1", "shelljs": "^0.5.0", "solc": "0.4.17", - "solidity-parser": "^0.4.0", "style-loader": "^0.19.0", "tar": "^3.1.5", "toposort": "^1.0.0", From 58b5ea329e9af8a10e6c392110b47e029e2b84cd Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Fri, 23 Mar 2018 11:37:56 -0400 Subject: [PATCH 07/22] Styles for contract instances --- lib/cmds/graph.js | 80 ++++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/lib/cmds/graph.js b/lib/cmds/graph.js index 073ddd6c..28fb9ac6 100644 --- a/lib/cmds/graph.js +++ b/lib/cmds/graph.js @@ -22,46 +22,54 @@ class GraphGenerator { let contractLabel = ""; contractLabel += `${contract}`; + let tooltip = contract; if(this.engine.contractsManager.contracts[contract].instanceOf !== undefined && this.engine.contractsManager.contracts[this.engine.contractsManager.contracts[contract].instanceOf] !== undefined){ contractInheritance[contract] = this.engine.contractsManager.contracts[contract].instanceOf; - } + contractLabel += ": " + this.engine.contractsManager.contracts[contract].instanceOf; + tooltip += " instance of " + this.engine.contractsManager.contracts[contract].instanceOf; + } else { + contractLabel += "|"; - contractLabel += "|"; + for(let i = 0; i < this.engine.contractsManager.contracts[contract].abiDefinition.length; i++){ + switch(this.engine.contractsManager.contracts[contract].abiDefinition[i].type){ + case 'fallback': + contractLabel += "«fallback»()\\l"; + break; + case 'constructor': + contractLabel += "«constructor»("; + for(let j = 0; j < this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs.length; j++){ + contractLabel += (j == 0 ? "" : ", ") + this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs[j].type; + } + contractLabel += ")\\l"; + break; + case 'event': + contractLabel += "«event»" + this.engine.contractsManager.contracts[contract].abiDefinition[i].name + "("; + for(let j = 0; j < this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs.length; j++){ + contractLabel += (j == 0 ? "" : ", ") + this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs[j].type; + } + contractLabel += ")\\l"; + break; + default: break; + } + } - for(let i = 0; i < this.engine.contractsManager.contracts[contract].abiDefinition.length; i++){ - switch(this.engine.contractsManager.contracts[contract].abiDefinition[i].type){ - case 'fallback': - contractLabel += "«fallback»()\\l"; - break; - case 'constructor': - contractLabel += "«constructor»("; - for(let j = 0; j < this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs.length; j++){ - contractLabel += (j == 0 ? "" : ", ") + this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs[j].type; - } - contractLabel += ")\\l"; - break; - case 'event': - contractLabel += "«event»" + this.engine.contractsManager.contracts[contract].abiDefinition[i].name + "("; - for(let j = 0; j < this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs.length; j++){ - contractLabel += (j == 0 ? "" : ", ") + this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs[j].type; - } - contractLabel += ")\\l"; - break; - default: break; - } - } - - let fHashes = this.engine.contractsManager.contracts[contract].functionHashes; - if(fHashes != {} && fHashes != undefined){ - for(let method in this.engine.contractsManager.contracts[contract].functionHashes){ - contractLabel += method + '\\l'; + let fHashes = this.engine.contractsManager.contracts[contract].functionHashes; + if(fHashes != {} && fHashes != undefined){ + for(let method in this.engine.contractsManager.contracts[contract].functionHashes){ + contractLabel += method + '\\l'; + } } } - - contractString += `${id}[label = "{${contractLabel}}"]\n`; + let others = '' + if(!this.engine.contractsManager.contracts[contract].deploy){ + others = 'fontcolor="#c3c3c3", color="#a0a0a0"'; + tooltip += " (not deployed)"; + } + + contractString += `${id}[label = "{${contractLabel}}", tooltip="${tooltip}", fillcolor=gray95, ${others}]\n`; } @@ -69,20 +77,20 @@ class GraphGenerator { let contractDependencies = Array.from(new Set(this.engine.contractsManager.contractDependencies[c])); contractDependencies.forEach(function(d){ if(idMapping[c] !== undefined && idMapping[d] !== undefined){ - relationshipString += `${idMapping[d]}->${idMapping[c]}[constraint=true, arrowtail=diamond]\n`; + relationshipString += `${idMapping[d]}->${idMapping[c]}[constraint=true, arrowtail=diamond, tooltip="${d} uses ${c}"]\n`; } }); } for (let c in contractInheritance){ - relationshipString += `${idMapping[contractInheritance[c]]}->${idMapping[c]}\n`; + relationshipString += `${idMapping[contractInheritance[c]]}->${idMapping[c]}[tooltip="${c} instance of ${contractInheritance[c]}"]\n`; } let dot = ` - digraph hierarchy { - node[shape=record,style=filled,fillcolor=gray95] - edge[dir=back, arrowtail=empty] + digraph Contracts { + node[shape=record,style=filled] + edge[dir=back, arrowtail=empty] ${contractString} ${relationshipString} }`; From 0326890abeb6967e739f21d80ff0157fafac8802 Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Fri, 23 Mar 2018 11:39:42 -0400 Subject: [PATCH 08/22] Fix: Relationship was incorrect --- lib/cmds/graph.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cmds/graph.js b/lib/cmds/graph.js index 28fb9ac6..ef401111 100644 --- a/lib/cmds/graph.js +++ b/lib/cmds/graph.js @@ -68,7 +68,7 @@ class GraphGenerator { others = 'fontcolor="#c3c3c3", color="#a0a0a0"'; tooltip += " (not deployed)"; } - + contractString += `${id}[label = "{${contractLabel}}", tooltip="${tooltip}", fillcolor=gray95, ${others}]\n`; } @@ -77,7 +77,7 @@ class GraphGenerator { let contractDependencies = Array.from(new Set(this.engine.contractsManager.contractDependencies[c])); contractDependencies.forEach(function(d){ if(idMapping[c] !== undefined && idMapping[d] !== undefined){ - relationshipString += `${idMapping[d]}->${idMapping[c]}[constraint=true, arrowtail=diamond, tooltip="${d} uses ${c}"]\n`; + relationshipString += `${idMapping[d]}->${idMapping[c]}[constraint=true, arrowtail=diamond, tooltip="${c} uses ${d}"]\n`; } }); } From f56b42d91ff13a1520d96cb5eefbcfcd1dfbad46 Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Thu, 5 Apr 2018 11:41:28 -0400 Subject: [PATCH 09/22] Linting --- lib/cmds/graph.js | 14 +++++++------- package-lock.json | 5 +++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/cmds/graph.js b/lib/cmds/graph.js index ef401111..7621fe65 100644 --- a/lib/cmds/graph.js +++ b/lib/cmds/graph.js @@ -39,16 +39,16 @@ class GraphGenerator { break; case 'constructor': contractLabel += "«constructor»("; - for(let j = 0; j < this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs.length; j++){ - contractLabel += (j == 0 ? "" : ", ") + this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs[j].type; - } + this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs.forEach(function(elem, index){ + contractLabel += (index == 0 ? "" : ", ") + elem.type; + }); contractLabel += ")\\l"; break; case 'event': contractLabel += "«event»" + this.engine.contractsManager.contracts[contract].abiDefinition[i].name + "("; - for(let j = 0; j < this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs.length; j++){ - contractLabel += (j == 0 ? "" : ", ") + this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs[j].type; - } + this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs.forEach(function(elem, index){ + contractLabel += (index == 0 ? "" : ", ") + elem.type; + }); contractLabel += ")\\l"; break; default: break; @@ -63,7 +63,7 @@ class GraphGenerator { } } - let others = '' + let others = ''; if(!this.engine.contractsManager.contracts[contract].deploy){ others = 'fontcolor="#c3c3c3", color="#a0a0a0"'; tooltip += " (not deployed)"; diff --git a/package-lock.json b/package-lock.json index e2e62dd0..188cefdf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10063,6 +10063,11 @@ "extsprintf": "1.3.0" } }, + "viz.js": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/viz.js/-/viz.js-1.8.1.tgz", + "integrity": "sha512-KrSNgnIxec+JCAqDPliO6xYA69ToH2WTYB2Kbt8Bp/XRUvm23rTyfffFi4rvQLFkIRNUz/xCnnqhh/gChhsgGA==" + }, "vlq": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", From 4a9b52e5df0c14116947c1d364129171ef2bf87e Mon Sep 17 00:00:00 2001 From: emizzle Date: Thu, 12 Apr 2018 13:47:34 +1000 Subject: [PATCH 10/22] Removed annoying [Object object] from the log that was appearing during contract compilation. The warnings in object that were attempted to be logged were already being logged in a previous loop, so this was simply removed. --- lib/modules/solidity/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/modules/solidity/index.js b/lib/modules/solidity/index.js index c4db9dae..244f6015 100644 --- a/lib/modules/solidity/index.js +++ b/lib/modules/solidity/index.js @@ -75,7 +75,6 @@ class Solidity { return callback(new Error("Solidity errors: " + output.errors[i].formattedMessage).message); } } - self.logger.warn(output.errors.join('\n')); } callback(null, output); }); From e3fde1ad225f2c72c8d06a8c6ab47104e9b46b89 Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Thu, 12 Apr 2018 17:54:08 -0400 Subject: [PATCH 11/22] support mapping contract file in contracts config --- lib/core/config.js | 12 ++++++++++++ test_apps/test_app/config/contracts.json | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/lib/core/config.js b/lib/core/config.js index c6aafe59..89a66c36 100644 --- a/lib/core/config.js +++ b/lib/core/config.js @@ -47,6 +47,7 @@ Config.prototype.loadConfigFiles = function(options) { this.loadPipelineConfigFile(); this.loadContractsConfigFile(); + this.loadExternalContractsFiles(); this.loadWebServerConfigFile(); this.loadChainTrackerFile(); this.loadPluginContractFiles(); @@ -60,6 +61,7 @@ Config.prototype.reloadConfig = function() { this.loadContractsConfigFile(); this.loadPipelineConfigFile(); this.loadContractsConfigFile(); + this.loadExternalContractsFiles(); this.loadChainTrackerFile(); }; @@ -140,6 +142,16 @@ Config.prototype.loadContractsConfigFile = function() { this.contractsConfig = this._mergeConfig(configFilePath, configObject, this.env); }; +Config.prototype.loadExternalContractsFiles = function() { + let contracts = this.contractsConfig.contracts; + for (let contractName in contracts) { + let contract = contracts[contractName]; + if (contract.file) { + this.contractsFiles.push(new File({filename: contract.file, type: "dapp_file", basedir: '', path: contract.file})); + } + } +}; + Config.prototype.loadStorageConfigFile = function() { var versions = utils.recursiveMerge({"ipfs-api": "17.2.4"}, this.embarkConfig.versions || {}); diff --git a/test_apps/test_app/config/contracts.json b/test_apps/test_app/config/contracts.json index d504a8ff..8ab61e18 100644 --- a/test_apps/test_app/config/contracts.json +++ b/test_apps/test_app/config/contracts.json @@ -62,6 +62,12 @@ ["$MyToken2", "$SimpleStorage"], 100 ] + }, + "SimpleStorageTest": { + "file": "./some_folder/test_contract.sol", + "args": [ + 1000 + ] } }, "afterDeploy": [ From db61e355c1b4ed488ef9a0b721b4ac9773580aad Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Thu, 12 Apr 2018 17:55:57 -0400 Subject: [PATCH 12/22] look for contract import in dapp dir and node_modules --- lib/modules/solidity/solcP.js | 17 +++++++++++++- .../test_app/another_folder/another_test.sol | 21 +++++++++++++++++ test_apps/test_app/embark.json | 2 +- test_apps/test_app/package.json | 3 ++- .../test_app/some_folder/test_contract.sol | 23 +++++++++++++++++++ 5 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 test_apps/test_app/another_folder/another_test.sol create mode 100644 test_apps/test_app/some_folder/test_contract.sol diff --git a/lib/modules/solidity/solcP.js b/lib/modules/solidity/solcP.js index 5550c9b1..e4d04cab 100644 --- a/lib/modules/solidity/solcP.js +++ b/lib/modules/solidity/solcP.js @@ -1,5 +1,20 @@ let solc; +let fs = require('fs-extra'); +let path = require('path'); + +function findImports(filename) { + console.dir(filename); + if (!fs.existsSync(filename)) { + if (fs.existsSync(path.join('./node_modules/', filename))) { + return {contents: fs.readFileSync(path.join('./node_modules/', filename)).toString()}; + } else { + return {error: 'File not found'}; + } + } + return {contents: fs.readFileSync(filename).toString()}; +} + process.on('message', function (msg) { if (msg.action === 'loadCompiler') { solc = require(msg.solcLocation); @@ -8,7 +23,7 @@ process.on('message', function (msg) { if (msg.action === 'compile') { // TODO: only available in 0.4.11; need to make versions warn about this - let output = solc.compileStandardWrapper(JSON.stringify(msg.jsonObj)); + let output = solc.compileStandardWrapper(JSON.stringify(msg.jsonObj), findImports); process.send({result: "compilation", output: output}); } }); diff --git a/test_apps/test_app/another_folder/another_test.sol b/test_apps/test_app/another_folder/another_test.sol new file mode 100644 index 00000000..ddd06f3e --- /dev/null +++ b/test_apps/test_app/another_folder/another_test.sol @@ -0,0 +1,21 @@ +pragma solidity ^0.4.17; + +contract SimpleStorageTest2 { + uint public storedData; + + function() public payable { } + + function SimpleStorage(uint initialValue) public { + storedData = initialValue; + } + + function set(uint x) public { + storedData = x; + } + + function get() public view returns (uint retVal) { + return storedData; + } + +} + diff --git a/test_apps/test_app/embark.json b/test_apps/test_app/embark.json index e4974bb6..0b6e48a0 100644 --- a/test_apps/test_app/embark.json +++ b/test_apps/test_app/embark.json @@ -16,7 +16,7 @@ "config": "config/", "versions": { "web3.js": "1.0.0-beta.27", - "solc": "0.4.17", + "solc": "0.4.21", "ipfs-api": "17.2.6" }, "plugins": { diff --git a/test_apps/test_app/package.json b/test_apps/test_app/package.json index 234db24d..8711dde1 100644 --- a/test_apps/test_app/package.json +++ b/test_apps/test_app/package.json @@ -18,6 +18,7 @@ "jquery": "^1.11.3", "react": "^16.0.0", "react-bootstrap": "^0.32.0", - "react-dom": "^16.2.0" + "react-dom": "^16.2.0", + "zeppelin-solidity": "^1.8.0" } } diff --git a/test_apps/test_app/some_folder/test_contract.sol b/test_apps/test_app/some_folder/test_contract.sol new file mode 100644 index 00000000..233605e4 --- /dev/null +++ b/test_apps/test_app/some_folder/test_contract.sol @@ -0,0 +1,23 @@ +pragma solidity ^0.4.17; + +import "another_folder/another_test.sol"; +import "zeppelin-solidity/contracts/ownership/Ownable.sol"; + +contract SimpleStorageTest is Ownable { + uint public storedData; + + function() public payable { } + + function SimpleStorage(uint initialValue) public { + storedData = initialValue; + } + + function set(uint x) public { + storedData = x; + } + + function get() public view returns (uint retVal) { + return storedData; + } + +} From e0ab9cbde406d676f9811d86e0daf4fc72eebd4f Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Thu, 12 Apr 2018 17:57:55 -0400 Subject: [PATCH 13/22] refactor findImports --- lib/modules/solidity/solcP.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/modules/solidity/solcP.js b/lib/modules/solidity/solcP.js index e4d04cab..2922c088 100644 --- a/lib/modules/solidity/solcP.js +++ b/lib/modules/solidity/solcP.js @@ -4,15 +4,13 @@ let fs = require('fs-extra'); let path = require('path'); function findImports(filename) { - console.dir(filename); - if (!fs.existsSync(filename)) { - if (fs.existsSync(path.join('./node_modules/', filename))) { - return {contents: fs.readFileSync(path.join('./node_modules/', filename)).toString()}; - } else { - return {error: 'File not found'}; - } + if (fs.existsSync(filename)) { + return {contents: fs.readFileSync(filename).toString()}; } - return {contents: fs.readFileSync(filename).toString()}; + if (fs.existsSync(path.join('./node_modules/', filename))) { + return {contents: fs.readFileSync(path.join('./node_modules/', filename)).toString()}; + } + return {error: 'File not found'}; } process.on('message', function (msg) { From 7dd36a7a3b56f90d1339c3b1940ad14d77359e4b Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Thu, 12 Apr 2018 18:50:47 -0400 Subject: [PATCH 14/22] support getting contract from module; fix bug in which entire contract path was being replaced instead of just the beginning (if matching contracts in embark.json) --- lib/core/config.js | 7 ++++++- lib/modules/solidity/index.js | 3 ++- test_apps/test_app/config/contracts.json | 3 +++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/core/config.js b/lib/core/config.js index 89a66c36..bbc09cf2 100644 --- a/lib/core/config.js +++ b/lib/core/config.js @@ -146,8 +146,13 @@ Config.prototype.loadExternalContractsFiles = function() { let contracts = this.contractsConfig.contracts; for (let contractName in contracts) { let contract = contracts[contractName]; - if (contract.file) { + if (!contract.file) { + continue; + } + if (fs.existsSync(contract.file)) { this.contractsFiles.push(new File({filename: contract.file, type: "dapp_file", basedir: '', path: contract.file})); + } else if (fs.existsSync(path.join('./node_modules/', contract.file))) { + this.contractsFiles.push(new File({filename: path.join('./node_modules/', contract.file), type: "dapp_file", basedir: '', path: path.join('./node_modules/', contract.file)})); } } }; diff --git a/lib/modules/solidity/index.js b/lib/modules/solidity/index.js index c4db9dae..596cd414 100644 --- a/lib/modules/solidity/index.js +++ b/lib/modules/solidity/index.js @@ -22,7 +22,8 @@ class Solidity { let filename = file.filename; for (let directory of self.contractDirectories) { - filename = filename.replace(directory, ''); + let match = new RegExp("^" + directory); + filename = filename.replace(match, ''); } file.content(function(fileContent) { diff --git a/test_apps/test_app/config/contracts.json b/test_apps/test_app/config/contracts.json index 8ab61e18..c2cd9b55 100644 --- a/test_apps/test_app/config/contracts.json +++ b/test_apps/test_app/config/contracts.json @@ -63,6 +63,9 @@ 100 ] }, + "ERC20": { + "file": "zeppelin-solidity/contracts/token/ERC20/ERC20.sol" + }, "SimpleStorageTest": { "file": "./some_folder/test_contract.sol", "args": [ From 7243c6ea8b779b4a3b4bcf08ad4822badb96baa3 Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Thu, 12 Apr 2018 18:52:13 -0400 Subject: [PATCH 15/22] revert to lower versions of solc --- test_apps/test_app/embark.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_apps/test_app/embark.json b/test_apps/test_app/embark.json index 0b6e48a0..8459e8af 100644 --- a/test_apps/test_app/embark.json +++ b/test_apps/test_app/embark.json @@ -16,7 +16,7 @@ "config": "config/", "versions": { "web3.js": "1.0.0-beta.27", - "solc": "0.4.21", + "solc": "0.4.18", "ipfs-api": "17.2.6" }, "plugins": { From 5ed1e787b256a283378005850b1eb9266b48fe45 Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Thu, 12 Apr 2018 20:30:20 -0400 Subject: [PATCH 16/22] print error if contract file is not found --- lib/core/config.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/core/config.js b/lib/core/config.js index bbc09cf2..26743320 100644 --- a/lib/core/config.js +++ b/lib/core/config.js @@ -153,6 +153,8 @@ Config.prototype.loadExternalContractsFiles = function() { this.contractsFiles.push(new File({filename: contract.file, type: "dapp_file", basedir: '', path: contract.file})); } else if (fs.existsSync(path.join('./node_modules/', contract.file))) { this.contractsFiles.push(new File({filename: path.join('./node_modules/', contract.file), type: "dapp_file", basedir: '', path: path.join('./node_modules/', contract.file)})); + } else { + this.logger.error("contract file not found: " + contract.file); } } }; From 6647c31d38e6929ae3fd73441f9510429ea5e2e7 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Fri, 13 Apr 2018 14:54:46 -0400 Subject: [PATCH 17/22] hotfix: callback with wrong parameter order --- lib/contracts/deploy_manager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/contracts/deploy_manager.js b/lib/contracts/deploy_manager.js index edcd49e7..2ddbea33 100644 --- a/lib/contracts/deploy_manager.js +++ b/lib/contracts/deploy_manager.js @@ -39,7 +39,7 @@ class DeployManager { self.events.emit('contractsDeployed', contractsManager); return done(); } - return callback(contractsManager, null); + return callback(null, contractsManager); }, function checkWeb3IsConnected(contractsManager, callback) { if (!self.web3) { From 7d8c7b119c65d4746c18b4ffebc14e7e6557986c Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Wed, 11 Apr 2018 09:47:55 -0400 Subject: [PATCH 18/22] add warning after compile for files without a compatible compiler --- lib/contracts/compiler.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/contracts/compiler.js b/lib/contracts/compiler.js index c9a7ffa4..fa474e52 100644 --- a/lib/contracts/compiler.js +++ b/lib/contracts/compiler.js @@ -7,9 +7,10 @@ class Compiler { } compile_contracts(contractFiles, cb) { + const self = this; let available_compilers = {}; - let pluginCompilers = this.plugins.getPluginsProperty('compilers', 'compilers'); + let pluginCompilers = self.plugins.getPluginsProperty('compilers', 'compilers'); pluginCompilers.forEach(function (compilerObject) { available_compilers[compilerObject.extension] = compilerObject.cb; }); @@ -18,10 +19,13 @@ class Compiler { async.eachObject(available_compilers, function (extension, compiler, callback) { - // TODO: warn about files it doesn't know how to compile let matchingFiles = contractFiles.filter(function (file) { let fileMatch = file.filename.match(/\.[0-9a-z]+$/); - return (fileMatch && (fileMatch[0] === extension)); + if (fileMatch && (fileMatch[0] === extension)) { + file.compiled = true; + return true; + } + return false; }); compiler.call(compiler, matchingFiles || [], function (err, compileResult) { @@ -30,6 +34,12 @@ class Compiler { }); }, function (err) { + contractFiles.forEach(file => { + if (!file.compiled) { + self.logger.warn(`${file.filename} doesn't have a compatible contract compiler. Maybe a plugin exists for it.`); + } + }); + cb(err, compiledObject); } ); From dc9e6c168bcbb5afcacd748009a6bdc378defa08 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Thu, 12 Apr 2018 13:24:54 -0400 Subject: [PATCH 19/22] start vyper implementation --- lib/core/engine.js | 3 ++ lib/modules/solidity/index.js | 2 +- lib/modules/vyper/index.js | 75 +++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 lib/modules/vyper/index.js diff --git a/lib/core/engine.js b/lib/core/engine.js index b4ebe928..9c02a5da 100644 --- a/lib/core/engine.js +++ b/lib/core/engine.js @@ -137,6 +137,9 @@ class Engine { this.registerModule('solidity', { contractDirectories: self.config.contractDirectories }); + this.registerModule('vyper', { + contractDirectories: self.config.contractDirectories + }); this.contractsManager = new ContractsManager({ contractFiles: this.config.contractsFiles, diff --git a/lib/modules/solidity/index.js b/lib/modules/solidity/index.js index d59564a4..a4f5c035 100644 --- a/lib/modules/solidity/index.js +++ b/lib/modules/solidity/index.js @@ -49,7 +49,7 @@ class Solidity { }); }, function compileContracts(callback) { - self.logger.info("compiling contracts..."); + self.logger.info("compiling solidity contracts..."); let jsonObj = { language: 'Solidity', sources: input, diff --git a/lib/modules/vyper/index.js b/lib/modules/vyper/index.js new file mode 100644 index 00000000..b18830bb --- /dev/null +++ b/lib/modules/vyper/index.js @@ -0,0 +1,75 @@ +let async = require('../../utils/async_extend.js'); +const shelljs = require('shelljs'); + +class Vyper { + + constructor(embark, options) { + this.logger = embark.logger; + this.events = embark.events; + this.contractDirectories = options.contractDirectories; + + console.log('Construct VYPER'); + embark.registerCompiler(".py", this.compile_vyper.bind(this)); + } + + compile_vyper(contractFiles, cb) { + let self = this; + async.waterfall([ + function compileContracts(callback) { + self.logger.info("compiling vyper contracts..."); + async.each(contractFiles, + function(file, fileCb) { + shelljs.exec(`vyper ${file.filename}`, (code, stdout, stderr) => { + console.log('Code', code); + console.log('Stdout', stdout); + console.log('Stderr', stderr); + fileCb(); + }); + }, + function (err) { + process.exit(); // TODO remove me + callback(err); + }); + }, + function createCompiledObject(output, callback) { + let json = output.contracts; + + if (!output || !output.contracts) { + return callback(new Error("error compiling for unknown reasons")); + } + + if (Object.keys(output.contracts).length === 0 && output.sourceList.length > 0) { + return callback(new Error("error compiling. There are sources available but no code could be compiled, likely due to fatal errors in the solidity code").message); + } + + let compiled_object = {}; + + for (let contractFile in json) { + for (let contractName in json[contractFile]) { + let contract = json[contractFile][contractName]; + + const className = contractName; + const filename = contractFile; + + compiled_object[className] = {}; + compiled_object[className].code = contract.evm.bytecode.object; + compiled_object[className].runtimeBytecode = contract.evm.deployedBytecode.object; + compiled_object[className].realRuntimeBytecode = contract.evm.deployedBytecode.object.slice(0, -68); + compiled_object[className].swarmHash = contract.evm.deployedBytecode.object.slice(-68).slice(0, 64); + compiled_object[className].gasEstimates = contract.evm.gasEstimates; + compiled_object[className].functionHashes = contract.evm.methodIdentifiers; + compiled_object[className].abiDefinition = contract.abi; + compiled_object[className].filename = filename; + } + } + + callback(null, compiled_object); + } + ], function (err, result) { + cb(err, result); + }); + } + +} + +module.exports = Vyper; From 17e1c71506959bf5435f43e197557e868c7b0cbd Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Thu, 12 Apr 2018 16:33:01 -0400 Subject: [PATCH 20/22] submit contract for deployment, not working yet --- lib/modules/vyper/index.js | 92 +++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/lib/modules/vyper/index.js b/lib/modules/vyper/index.js index b18830bb..d75fbe8c 100644 --- a/lib/modules/vyper/index.js +++ b/lib/modules/vyper/index.js @@ -1,5 +1,6 @@ let async = require('../../utils/async_extend.js'); const shelljs = require('shelljs'); +const path = require('path'); class Vyper { @@ -8,7 +9,6 @@ class Vyper { this.events = embark.events; this.contractDirectories = options.contractDirectories; - console.log('Construct VYPER'); embark.registerCompiler(".py", this.compile_vyper.bind(this)); } @@ -17,53 +17,53 @@ class Vyper { async.waterfall([ function compileContracts(callback) { self.logger.info("compiling vyper contracts..."); + const compiled_object = {}; async.each(contractFiles, - function(file, fileCb) { - shelljs.exec(`vyper ${file.filename}`, (code, stdout, stderr) => { - console.log('Code', code); - console.log('Stdout', stdout); - console.log('Stderr', stderr); - fileCb(); + function (file, fileCb) { + const fileNameOnly = path.basename(file.filename); + compiled_object[fileNameOnly] = {}; + async.parallel([ + function getByteCode(paraCb) { + shelljs.exec(`vyper ${file.filename}`, { silent: true }, (code, stdout, stderr) => { + if (stderr) { + return paraCb(stderr); + } + if (code !== 0) { + return paraCb(`Vyper exited with error code ${code}`) + } + if (!stdout) { + return paraCb('Execution returned no bytecode'); + } + compiled_object[fileNameOnly].code = stdout.replace(/\n/g, ''); + paraCb(); }); - }, - function (err) { - process.exit(); // TODO remove me - callback(err); - }); - }, - function createCompiledObject(output, callback) { - let json = output.contracts; - - if (!output || !output.contracts) { - return callback(new Error("error compiling for unknown reasons")); - } - - if (Object.keys(output.contracts).length === 0 && output.sourceList.length > 0) { - return callback(new Error("error compiling. There are sources available but no code could be compiled, likely due to fatal errors in the solidity code").message); - } - - let compiled_object = {}; - - for (let contractFile in json) { - for (let contractName in json[contractFile]) { - let contract = json[contractFile][contractName]; - - const className = contractName; - const filename = contractFile; - - compiled_object[className] = {}; - compiled_object[className].code = contract.evm.bytecode.object; - compiled_object[className].runtimeBytecode = contract.evm.deployedBytecode.object; - compiled_object[className].realRuntimeBytecode = contract.evm.deployedBytecode.object.slice(0, -68); - compiled_object[className].swarmHash = contract.evm.deployedBytecode.object.slice(-68).slice(0, 64); - compiled_object[className].gasEstimates = contract.evm.gasEstimates; - compiled_object[className].functionHashes = contract.evm.methodIdentifiers; - compiled_object[className].abiDefinition = contract.abi; - compiled_object[className].filename = filename; - } - } - - callback(null, compiled_object); + }, + function getABI(paraCb) { + shelljs.exec(`vyper -f json ${file.filename}`, { silent: true }, (code, stdout, stderr) => { + if (stderr) { + return paraCb(stderr); + } + if (code !== 0) { + return paraCb(`Vyper exited with error code ${code}`) + } + if (!stdout) { + return paraCb('Execution returned no ABI'); + } + let ABI = []; + try { + ABI = JSON.parse(stdout.replace(/\n/g, '')); + } catch (e) { + return paraCb('ABI is not valid JSON'); + } + compiled_object[fileNameOnly].abiDefinition = ABI; + paraCb(); + }); + } + ], fileCb); + }, + function (err) { + callback(err, compiled_object); + }); } ], function (err, result) { cb(err, result); From 99c04b405f5c7091be0cf011568e45cc19d92a77 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Fri, 13 Apr 2018 15:48:19 -0400 Subject: [PATCH 21/22] fix clas name and bytecode --- lib/contracts/deploy.js | 3 ++- lib/modules/vyper/index.js | 19 +++++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/contracts/deploy.js b/lib/contracts/deploy.js index d6f6636e..d1b87ade 100644 --- a/lib/contracts/deploy.js +++ b/lib/contracts/deploy.js @@ -305,7 +305,8 @@ class Deploy { let contractObject = new self.web3.eth.Contract(contract.abiDefinition); try { - deployObject = contractObject.deploy({arguments: contractParams, data: "0x" + contractCode}); + const dataCode = contractCode.startsWith('0x') ? contractCode : "0x" + contractCode; + deployObject = contractObject.deploy({arguments: contractParams, data: dataCode}); } catch(e) { if (e.message.indexOf('Invalid number of parameters for "undefined"') >= 0) { return next(new Error("attempted to deploy " + contract.className + " without specifying parameters")); diff --git a/lib/modules/vyper/index.js b/lib/modules/vyper/index.js index d75fbe8c..df805a21 100644 --- a/lib/modules/vyper/index.js +++ b/lib/modules/vyper/index.js @@ -20,31 +20,34 @@ class Vyper { const compiled_object = {}; async.each(contractFiles, function (file, fileCb) { - const fileNameOnly = path.basename(file.filename); - compiled_object[fileNameOnly] = {}; + const className = path.basename(file.filename).split('.')[0]; + compiled_object[className] = {}; async.parallel([ function getByteCode(paraCb) { - shelljs.exec(`vyper ${file.filename}`, { silent: true }, (code, stdout, stderr) => { + shelljs.exec(`vyper ${file.filename}`, {silent: true}, (code, stdout, stderr) => { if (stderr) { return paraCb(stderr); } if (code !== 0) { - return paraCb(`Vyper exited with error code ${code}`) + return paraCb(`Vyper exited with error code ${code}`); } if (!stdout) { return paraCb('Execution returned no bytecode'); } - compiled_object[fileNameOnly].code = stdout.replace(/\n/g, ''); + const byteCode = stdout.replace(/\n/g, ''); + compiled_object[className].runtimeBytecode = byteCode; + compiled_object[className].realRuntimeBytecode = byteCode; + compiled_object[className].code = byteCode; paraCb(); }); }, function getABI(paraCb) { - shelljs.exec(`vyper -f json ${file.filename}`, { silent: true }, (code, stdout, stderr) => { + shelljs.exec(`vyper -f json ${file.filename}`, {silent: true}, (code, stdout, stderr) => { if (stderr) { return paraCb(stderr); } if (code !== 0) { - return paraCb(`Vyper exited with error code ${code}`) + return paraCb(`Vyper exited with error code ${code}`); } if (!stdout) { return paraCb('Execution returned no ABI'); @@ -55,7 +58,7 @@ class Vyper { } catch (e) { return paraCb('ABI is not valid JSON'); } - compiled_object[fileNameOnly].abiDefinition = ABI; + compiled_object[className].abiDefinition = ABI; paraCb(); }); } From d3e9dc75ec064f19621bf62553da7aa4efb39060 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Fri, 13 Apr 2018 16:06:56 -0400 Subject: [PATCH 22/22] update readme to include Vyper doc --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dec3eb07..aa5ec7b8 100644 --- a/README.md +++ b/README.md @@ -160,13 +160,18 @@ Solidity/Serpent files in the contracts directory will automatically be deployed Libraries and languages available ====== -Embark can build and deploy contracts coded in Solidity. It will make them available on the client side using EmbarkJS and Web3.js. +Embark can build and deploy contracts coded in Solidity and now also in Vyper. It will make them available on the client side using EmbarkJS and Web3.js. Further documentation for these can be found below: -* Smart Contracts: [Solidity](https://solidity.readthedocs.io/en/develop/) and [Serpent](https://github.com/ethereum/wiki/wiki/Serpent) +* Smart Contracts: + * [Solidity](https://solidity.readthedocs.io/en/develop/) + * [Vyper](https://vyper.readthedocs.io/en/latest/index.html) + * [Serpent](https://github.com/ethereum/wiki/wiki/Serpent) * Client Side: [Web3.js](https://github.com/ethereum/wiki/wiki/JavaScript-API) and [EmbarkJS](#embarkjs) +However, to use Vyper, you need to have Vyper installed on you computer beforehand. Meaning that doing `vyper contract.v.py` is possible. + Using Contracts ====== Embark will automatically take care of deployment for you and set all needed JS bindings. For example, the contract below: