Merge pull request #363 from embark-framework/features/vyper-plugin
Add Vyper contract support
This commit is contained in:
commit
1bd0b9931c
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
Loading…
Reference in New Issue