Skip to content

Commit f9b7f5c

Browse files
committed
Merge branch 'develop' of github.com:iurimatias/embark-framework into develop
2 parents 1d80f80 + 1bd0b99 commit f9b7f5c

File tree

19 files changed

+382
-13
lines changed

19 files changed

+382
-13
lines changed

README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,13 +160,18 @@ Solidity/Serpent files in the contracts directory will automatically be deployed
160160
Libraries and languages available
161161
======
162162

163-
Embark can build and deploy contracts coded in Solidity. It will make them available on the client side using EmbarkJS and Web3.js.
163+
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.
164164

165165
Further documentation for these can be found below:
166166

167-
* Smart Contracts: [Solidity](https://solidity.readthedocs.io/en/develop/) and [Serpent](https://github.com/ethereum/wiki/wiki/Serpent)
167+
* Smart Contracts:
168+
* [Solidity](https://solidity.readthedocs.io/en/develop/)
169+
* [Vyper](https://vyper.readthedocs.io/en/latest/index.html)
170+
* [Serpent](https://github.com/ethereum/wiki/wiki/Serpent)
168171
* Client Side: [Web3.js](https://github.com/ethereum/wiki/wiki/JavaScript-API) and [EmbarkJS](#embarkjs)
169172

173+
However, to use Vyper, you need to have Vyper installed on you computer beforehand. Meaning that doing `vyper contract.v.py` is possible.
174+
170175
Using Contracts
171176
======
172177
Embark will automatically take care of deployment for you and set all needed JS bindings. For example, the contract below:

lib/cmd.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class Cmd {
1818
this.simulator();
1919
this.test();
2020
this.reset();
21+
this.graph();
2122
this.upload();
2223
this.versionCmd();
2324
this.otherCommands();
@@ -179,6 +180,18 @@ class Cmd {
179180
});
180181
}
181182

183+
graph() {
184+
program
185+
.command('graph [environment]')
186+
.description('generates documentation based on the smart contracts configured')
187+
.action(function (env, options) {
188+
embark.graph({
189+
env: env || 'development',
190+
logfile: options.logfile
191+
});
192+
});
193+
}
194+
182195
reset() {
183196
program
184197
.command('reset')
@@ -214,6 +227,7 @@ class Cmd {
214227
process.exit(0);
215228
});
216229
}
230+
217231

218232
}
219233

lib/cmds/graph.js

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
const Viz = require('viz.js');
2+
const fs = require('fs');
3+
4+
class GraphGenerator {
5+
constructor(engine) {
6+
this.engine = engine;
7+
}
8+
9+
generate() {
10+
let id = 0;
11+
let contractString = "";
12+
let relationshipString = "";
13+
let idMapping = {};
14+
let contractInheritance = {};
15+
16+
17+
for (let contract in this.engine.contractsManager.contracts) {
18+
id++;
19+
20+
idMapping[contract] = id;
21+
22+
let contractLabel = "";
23+
24+
contractLabel += `${contract}`;
25+
let tooltip = contract;
26+
27+
if(this.engine.contractsManager.contracts[contract].instanceOf !== undefined &&
28+
this.engine.contractsManager.contracts[this.engine.contractsManager.contracts[contract].instanceOf] !== undefined){
29+
contractInheritance[contract] = this.engine.contractsManager.contracts[contract].instanceOf;
30+
contractLabel += ": " + this.engine.contractsManager.contracts[contract].instanceOf;
31+
tooltip += " instance of " + this.engine.contractsManager.contracts[contract].instanceOf;
32+
} else {
33+
contractLabel += "|";
34+
35+
for(let i = 0; i < this.engine.contractsManager.contracts[contract].abiDefinition.length; i++){
36+
switch(this.engine.contractsManager.contracts[contract].abiDefinition[i].type){
37+
case 'fallback':
38+
contractLabel += "«fallback»()\\l";
39+
break;
40+
case 'constructor':
41+
contractLabel += "«constructor»(";
42+
this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs.forEach(function(elem, index){
43+
contractLabel += (index == 0 ? "" : ", ") + elem.type;
44+
});
45+
contractLabel += ")\\l";
46+
break;
47+
case 'event':
48+
contractLabel += "«event»" + this.engine.contractsManager.contracts[contract].abiDefinition[i].name + "(";
49+
this.engine.contractsManager.contracts[contract].abiDefinition[i].inputs.forEach(function(elem, index){
50+
contractLabel += (index == 0 ? "" : ", ") + elem.type;
51+
});
52+
contractLabel += ")\\l";
53+
break;
54+
default: break;
55+
}
56+
}
57+
58+
let fHashes = this.engine.contractsManager.contracts[contract].functionHashes;
59+
if(fHashes != {} && fHashes != undefined){
60+
for(let method in this.engine.contractsManager.contracts[contract].functionHashes){
61+
contractLabel += method + '\\l';
62+
}
63+
}
64+
}
65+
66+
let others = '';
67+
if(!this.engine.contractsManager.contracts[contract].deploy){
68+
others = 'fontcolor="#c3c3c3", color="#a0a0a0"';
69+
tooltip += " (not deployed)";
70+
}
71+
72+
contractString += `${id}[label = "{${contractLabel}}", tooltip="${tooltip}", fillcolor=gray95, ${others}]\n`;
73+
74+
}
75+
76+
for (let c in this.engine.contractsManager.contractDependencies){
77+
let contractDependencies = Array.from(new Set(this.engine.contractsManager.contractDependencies[c]));
78+
contractDependencies.forEach(function(d){
79+
if(idMapping[c] !== undefined && idMapping[d] !== undefined){
80+
relationshipString += `${idMapping[d]}->${idMapping[c]}[constraint=true, arrowtail=diamond, tooltip="${c} uses ${d}"]\n`;
81+
}
82+
});
83+
}
84+
85+
for (let c in contractInheritance){
86+
relationshipString += `${idMapping[contractInheritance[c]]}->${idMapping[c]}[tooltip="${c} instance of ${contractInheritance[c]}"]\n`;
87+
}
88+
89+
90+
let dot = `
91+
digraph Contracts {
92+
node[shape=record,style=filled]
93+
edge[dir=back, arrowtail=empty]
94+
${contractString}
95+
${relationshipString}
96+
}`;
97+
98+
let svg = Viz(dot);
99+
100+
let filename = "diagram.svg";
101+
102+
fs.writeFileSync(filename, svg, (err) => {
103+
if (err) throw err;
104+
});
105+
106+
107+
}
108+
}
109+
110+
module.exports = GraphGenerator;

lib/contracts/compiler.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ class Compiler {
77
}
88

99
compile_contracts(contractFiles, cb) {
10+
const self = this;
1011
let available_compilers = {};
1112

12-
let pluginCompilers = this.plugins.getPluginsProperty('compilers', 'compilers');
13+
let pluginCompilers = self.plugins.getPluginsProperty('compilers', 'compilers');
1314
pluginCompilers.forEach(function (compilerObject) {
1415
available_compilers[compilerObject.extension] = compilerObject.cb;
1516
});
@@ -18,10 +19,13 @@ class Compiler {
1819

1920
async.eachObject(available_compilers,
2021
function (extension, compiler, callback) {
21-
// TODO: warn about files it doesn't know how to compile
2222
let matchingFiles = contractFiles.filter(function (file) {
2323
let fileMatch = file.filename.match(/\.[0-9a-z]+$/);
24-
return (fileMatch && (fileMatch[0] === extension));
24+
if (fileMatch && (fileMatch[0] === extension)) {
25+
file.compiled = true;
26+
return true;
27+
}
28+
return false;
2529
});
2630

2731
compiler.call(compiler, matchingFiles || [], function (err, compileResult) {
@@ -30,6 +34,12 @@ class Compiler {
3034
});
3135
},
3236
function (err) {
37+
contractFiles.forEach(file => {
38+
if (!file.compiled) {
39+
self.logger.warn(`${file.filename} doesn't have a compatible contract compiler. Maybe a plugin exists for it.`);
40+
}
41+
});
42+
3343
cb(err, compiledObject);
3444
}
3545
);

lib/contracts/deploy.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,8 @@ class Deploy {
305305
let contractObject = new self.web3.eth.Contract(contract.abiDefinition);
306306

307307
try {
308-
deployObject = contractObject.deploy({arguments: contractParams, data: "0x" + contractCode});
308+
const dataCode = contractCode.startsWith('0x') ? contractCode : "0x" + contractCode;
309+
deployObject = contractObject.deploy({arguments: contractParams, data: dataCode});
309310
} catch(e) {
310311
if (e.message.indexOf('Invalid number of parameters for "undefined"') >= 0) {
311312
return next(new Error("attempted to deploy " + contract.className + " without specifying parameters"));

lib/contracts/deploy_manager.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class DeployManager {
1717
this.gasLimit = false;
1818
this.fatalErrors = false;
1919
this.deployOnlyOnConfig = false;
20+
this.onlyCompile = options.onlyCompile !== undefined ? options.onlyCompile : false;
2021
}
2122

2223
deployContracts(done) {
@@ -33,6 +34,13 @@ class DeployManager {
3334
self.contractsManager.deployOnlyOnConfig = self.deployOnlyOnConfig; // temporary, should refactor
3435
self.contractsManager.build(callback);
3536
},
37+
function checkCompileOnly(contractsManager, callback){
38+
if(self.onlyCompile){
39+
self.events.emit('contractsDeployed', contractsManager);
40+
return done();
41+
}
42+
return callback(null, contractsManager);
43+
},
3644
function checkWeb3IsConnected(contractsManager, callback) {
3745
if (!self.web3) {
3846
return callback(Error("no web3 instance found"));

lib/core/config.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ Config.prototype.loadConfigFiles = function(options) {
4747
this.loadPipelineConfigFile();
4848

4949
this.loadContractsConfigFile();
50+
this.loadExternalContractsFiles();
5051
this.loadWebServerConfigFile();
5152
this.loadChainTrackerFile();
5253
this.loadPluginContractFiles();
@@ -60,6 +61,7 @@ Config.prototype.reloadConfig = function() {
6061
this.loadContractsConfigFile();
6162
this.loadPipelineConfigFile();
6263
this.loadContractsConfigFile();
64+
this.loadExternalContractsFiles();
6365
this.loadChainTrackerFile();
6466
};
6567

@@ -140,6 +142,23 @@ Config.prototype.loadContractsConfigFile = function() {
140142
this.contractsConfig = this._mergeConfig(configFilePath, configObject, this.env);
141143
};
142144

145+
Config.prototype.loadExternalContractsFiles = function() {
146+
let contracts = this.contractsConfig.contracts;
147+
for (let contractName in contracts) {
148+
let contract = contracts[contractName];
149+
if (!contract.file) {
150+
continue;
151+
}
152+
if (fs.existsSync(contract.file)) {
153+
this.contractsFiles.push(new File({filename: contract.file, type: "dapp_file", basedir: '', path: contract.file}));
154+
} else if (fs.existsSync(path.join('./node_modules/', contract.file))) {
155+
this.contractsFiles.push(new File({filename: path.join('./node_modules/', contract.file), type: "dapp_file", basedir: '', path: path.join('./node_modules/', contract.file)}));
156+
} else {
157+
this.logger.error("contract file not found: " + contract.file);
158+
}
159+
}
160+
};
161+
143162
Config.prototype.loadStorageConfigFile = function() {
144163
var versions = utils.recursiveMerge({"ipfs-api": "17.2.4"}, this.embarkConfig.versions || {});
145164

lib/core/engine.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ class Engine {
137137
this.registerModule('solidity', {
138138
contractDirectories: self.config.contractDirectories
139139
});
140+
this.registerModule('vyper', {
141+
contractDirectories: self.config.contractDirectories
142+
});
140143

141144
this.contractsManager = new ContractsManager({
142145
contractFiles: this.config.contractsFiles,
@@ -153,7 +156,8 @@ class Engine {
153156
logger: this.logger,
154157
plugins: this.plugins,
155158
events: this.events,
156-
contractsManager: this.contractsManager
159+
contractsManager: this.contractsManager,
160+
onlyCompile: options.onlyCompile
157161
});
158162

159163
this.events.on('file-event', function (fileType, _path) {

lib/index.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,53 @@ class Embark {
194194
return new Test(options);
195195
}
196196

197+
graph(options) {
198+
options.onlyCompile = true;
199+
200+
let engine = new Engine({
201+
env: options.env,
202+
version: this.version,
203+
embarkConfig: options.embarkConfig || 'embark.json',
204+
logfile: options.logfile
205+
});
206+
engine.init();
207+
208+
209+
async.parallel([
210+
211+
function (callback) {
212+
let pluginList = engine.plugins.listPlugins();
213+
if (pluginList.length > 0) {
214+
engine.logger.info("loaded plugins: " + pluginList.join(", "));
215+
}
216+
217+
engine.startMonitor();
218+
engine.startService("libraryManager");
219+
engine.startService("pipeline");
220+
engine.startService("codeGenerator");
221+
engine.startService("deployment", {onlyCompile: true});
222+
223+
engine.deployManager.deployContracts(function (err) {
224+
callback(err);
225+
});
226+
}
227+
], function (err, _result) {
228+
if (err) {
229+
engine.logger.error(err.message);
230+
engine.logger.info(err.stack);
231+
} else {
232+
233+
const GraphGenerator = require('./cmds/graph.js');
234+
let graphGen = new GraphGenerator(engine);
235+
graphGen.generate();
236+
237+
engine.logger.info("Done".underline);
238+
process.exit();
239+
}
240+
});
241+
242+
}
243+
197244
reset() {
198245
let resetCmd = require('./cmds/reset.js');
199246
resetCmd();

lib/modules/solidity/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ class Solidity {
2222
let filename = file.filename;
2323

2424
for (let directory of self.contractDirectories) {
25-
filename = filename.replace(directory, '');
25+
let match = new RegExp("^" + directory);
26+
filename = filename.replace(match, '');
2627
}
2728

2829
file.content(function(fileContent) {
@@ -48,7 +49,7 @@ class Solidity {
4849
});
4950
},
5051
function compileContracts(callback) {
51-
self.logger.info("compiling contracts...");
52+
self.logger.info("compiling solidity contracts...");
5253
let jsonObj = {
5354
language: 'Solidity',
5455
sources: input,
@@ -75,7 +76,6 @@ class Solidity {
7576
return callback(new Error("Solidity errors: " + output.errors[i].formattedMessage).message);
7677
}
7778
}
78-
self.logger.warn(output.errors.join('\n'));
7979
}
8080
callback(null, output);
8181
});

0 commit comments

Comments
 (0)