Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
16 changes: 13 additions & 3 deletions lib/contracts/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
});
Expand All @@ -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) {
Expand All @@ -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);
}
);
Expand Down
3 changes: 2 additions & 1 deletion lib/contracts/deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
Expand Down
3 changes: 3 additions & 0 deletions lib/core/engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion lib/modules/solidity/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
78 changes: 78 additions & 0 deletions lib/modules/vyper/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
let async = require('../../utils/async_extend.js');
const shelljs = require('shelljs');
const path = require('path');

class Vyper {

constructor(embark, options) {
this.logger = embark.logger;
this.events = embark.events;
this.contractDirectories = options.contractDirectories;

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...");
const compiled_object = {};
async.each(contractFiles,
function (file, fileCb) {
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) => {
if (stderr) {
return paraCb(stderr);
}
if (code !== 0) {
return paraCb(`Vyper exited with error code ${code}`);
}
if (!stdout) {
return paraCb('Execution returned no bytecode');
}
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) => {
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[className].abiDefinition = ABI;
paraCb();
});
}
], fileCb);
},
function (err) {
callback(err, compiled_object);
});
}
], function (err, result) {
cb(err, result);
});
}

}

module.exports = Vyper;