mirror of
https://github.com/status-im/embark-area-51.git
synced 2025-01-11 22:44:45 +00:00
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
|
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:
|
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)
|
* 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
|
Using Contracts
|
||||||
======
|
======
|
||||||
Embark will automatically take care of deployment for you and set all needed JS bindings. For example, the contract below:
|
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) {
|
compile_contracts(contractFiles, cb) {
|
||||||
|
const self = this;
|
||||||
let available_compilers = {};
|
let available_compilers = {};
|
||||||
|
|
||||||
let pluginCompilers = this.plugins.getPluginsProperty('compilers', 'compilers');
|
let pluginCompilers = self.plugins.getPluginsProperty('compilers', 'compilers');
|
||||||
pluginCompilers.forEach(function (compilerObject) {
|
pluginCompilers.forEach(function (compilerObject) {
|
||||||
available_compilers[compilerObject.extension] = compilerObject.cb;
|
available_compilers[compilerObject.extension] = compilerObject.cb;
|
||||||
});
|
});
|
||||||
@ -18,10 +19,13 @@ class Compiler {
|
|||||||
|
|
||||||
async.eachObject(available_compilers,
|
async.eachObject(available_compilers,
|
||||||
function (extension, compiler, callback) {
|
function (extension, compiler, callback) {
|
||||||
// TODO: warn about files it doesn't know how to compile
|
|
||||||
let matchingFiles = contractFiles.filter(function (file) {
|
let matchingFiles = contractFiles.filter(function (file) {
|
||||||
let fileMatch = file.filename.match(/\.[0-9a-z]+$/);
|
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) {
|
compiler.call(compiler, matchingFiles || [], function (err, compileResult) {
|
||||||
@ -30,6 +34,12 @@ class Compiler {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
function (err) {
|
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);
|
cb(err, compiledObject);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -305,7 +305,8 @@ class Deploy {
|
|||||||
let contractObject = new self.web3.eth.Contract(contract.abiDefinition);
|
let contractObject = new self.web3.eth.Contract(contract.abiDefinition);
|
||||||
|
|
||||||
try {
|
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) {
|
} catch(e) {
|
||||||
if (e.message.indexOf('Invalid number of parameters for "undefined"') >= 0) {
|
if (e.message.indexOf('Invalid number of parameters for "undefined"') >= 0) {
|
||||||
return next(new Error("attempted to deploy " + contract.className + " without specifying parameters"));
|
return next(new Error("attempted to deploy " + contract.className + " without specifying parameters"));
|
||||||
|
@ -137,6 +137,9 @@ class Engine {
|
|||||||
this.registerModule('solidity', {
|
this.registerModule('solidity', {
|
||||||
contractDirectories: self.config.contractDirectories
|
contractDirectories: self.config.contractDirectories
|
||||||
});
|
});
|
||||||
|
this.registerModule('vyper', {
|
||||||
|
contractDirectories: self.config.contractDirectories
|
||||||
|
});
|
||||||
|
|
||||||
this.contractsManager = new ContractsManager({
|
this.contractsManager = new ContractsManager({
|
||||||
contractFiles: this.config.contractsFiles,
|
contractFiles: this.config.contractsFiles,
|
||||||
|
@ -49,7 +49,7 @@ class Solidity {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
function compileContracts(callback) {
|
function compileContracts(callback) {
|
||||||
self.logger.info("compiling contracts...");
|
self.logger.info("compiling solidity contracts...");
|
||||||
let jsonObj = {
|
let jsonObj = {
|
||||||
language: 'Solidity',
|
language: 'Solidity',
|
||||||
sources: input,
|
sources: input,
|
||||||
|
78
lib/modules/vyper/index.js
Normal file
78
lib/modules/vyper/index.js
Normal file
@ -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…
x
Reference in New Issue
Block a user