feat(@embark/solc): add embark-solc to monorepo

This commit is contained in:
Jonathan Rainville 2019-06-28 14:02:27 -04:00 committed by Michael Bradley
parent ad796bc8f8
commit 1e59b58887
8 changed files with 359 additions and 1 deletions

View File

@ -0,0 +1,5 @@
engine-strict = true
package-lock = false
save-exact = true
scripts-prepend-node-path = true

View File

@ -0,0 +1,29 @@
Embark-Solc
======
Plugin for [Embark](https://github.com/embark-framework/embark) to compile contracts using solc
## Installation
In your embark dapp directory:
```npm install embark-solc --save```
then add embark-solc to the plugins section in `embark.json`:
```Json
"plugins": {
"embark-solc": {
"outputBinary": false
}
}
```
- `outputBinary` can be specified to generate a .bin file that contains the binary of the contracts in hex. Default value is `false`.
## Requirements
- [Embark](https://www.npmjs.com/package/embark) 4.0.0 or higher
- [Solc](https://github.com/ethereum/solidity/releases) installed and available globally on your machine (h)

View File

@ -0,0 +1,68 @@
{
"name": "embark-solc",
"version": "4.1.0-beta.4",
"author": "Richard Ramos",
"contributors": [],
"description": "Solc plugin for Embark (uses command line)",
"homepage": "https://github.com/embark-framework/embark/tree/master/packages/embark-solc#readme",
"bugs": "https://github.com/embark-framework/embark/issues",
"keywords": [
"blockchain",
"dapps",
"ethereum",
"ipfs",
"serverless",
"solc",
"solidity"
],
"files": [
"dist"
],
"license": "MIT",
"repository": {
"directory": "packages/embark-solc",
"type": "git",
"url": "https://github.com/embark-framework/embark.git"
},
"main": "./dist/index.js",
"scripts": {
"build": "cross-env BABEL_ENV=node babel src --copy-files --extensions \".ts\" --out-dir dist --root-mode upward --source-maps",
"ci": "npm run qa",
"clean": "npm run reset",
"lint": "npm-run-all lint:*",
"lint:js": "eslint src/",
"// lint:ts": "tslint -c tslint.json \"src/**/*.ts\"",
"package": "npm pack",
"// qa": "npm-run-all lint typecheck build package",
"qa": "npm-run-all lint build package",
"reset": "npx rimraf dist embark-*.tgz package",
"start": "npm run watch",
"// typecheck": "tsc",
"watch": "run-p watch:*",
"watch:build": "npm run build -- --verbose --watch",
"// watch:typecheck": "npm run typecheck -- --preserveWatchOutput --watch"
},
"eslintConfig": {
"extends": "../../.eslintrc.json"
},
"dependencies": {
"async": "^2.6.0",
"semver": "^5.6.0",
"shelljs": "^0.8.1"
},
"devDependencies": {
"@babel/cli": "7.2.3",
"@babel/core": "7.2.2",
"cross-env": "5.2.0",
"eslint": "5.7.0",
"npm-run-all": "4.1.5",
"rimraf": "2.6.3",
"tslint": "5.16.0",
"typescript": "3.4.5"
},
"engines": {
"node": ">=8.12.0 <12.0.0",
"npm": ">=6.4.1",
"yarn": ">=1.12.3"
}
}

View File

@ -0,0 +1,28 @@
/*global require, module*/
const Compiler = require("./lib/Compiler");
const semver = require('semver');
module.exports = (embark) => {
if (embark.config.embarkConfig.versions.solc) {
embark.registerCompiler('.sol', (contractFiles, options, cb) => {
if (!contractFiles || !contractFiles.length) {
return cb();
}
Compiler.getSolcVersion(embark.logger, (err, version) => {
if (err) {
embark.logger.error(err);
embark.logger.error("Error getting solc's version. Will default back to Embark's compiler");
return cb(null, false);
}
if (semver.lt(version, embark.config.embarkConfig.versions.solc)) {
embark.logger.warn(`Current version of solc lower than version in embark.json`);
embark.logger.warn(`Current: ${version} | Wanted: ${embark.config.embarkConfig.versions.solc}`);
embark.logger.warn('Will default back to Embark\'s compiler');
return cb(null, false);
}
Compiler.compileSolc(embark, contractFiles, embark.config.contractDirectories, options, cb);
});
});
}
};

View File

@ -0,0 +1,221 @@
const async = require('async');
const shelljs = require('shelljs');
const fs = require('fs');
const path = require('path');
function compileSolcContract(logger, compileSettings, allowedDirectories, callback) {
const command = `solc --standard-json --allow-paths ${allowedDirectories.join(',')}`;
shelljs.ShellString(JSON.stringify(compileSettings)).exec(command, {silent: true}, (code, stdout, stderr) => {
if (stderr) {
logger.warn(stderr);
}
if (code !== 0) {
return callback(`solc exited with error code ${code}`);
}
if (!stdout) {
return callback('solc execution returned nothing');
}
callback(null, stdout.replace(/\n/g, ''));
});
}
function getSolcVersion(logger, callback) {
shelljs.exec('solc --version', {silent: true}, (code, stdout, stderr) => {
if (stderr) {
logger.warn(stderr);
}
if (code !== 0) {
return callback(`solc exited with error code ${code}`);
}
if (!stdout) {
return callback('solc execution returned nothing');
}
const result = stdout.match(/(\d+.\d+.\d+)/);
callback(null, result[1]);
});
}
function compileSolc(embark, contractFiles, contractDirectories, options, callback) {
if (!contractFiles || !contractFiles.length) {
return callback();
}
const logger = embark.logger;
const outputBinary = embark.pluginConfig.outputBinary;
const outputDir = embark.config.buildDir + embark.config.contractDirectories[0];
const solcConfig = embark.config.embarkConfig.options.solc;
let allowedDirectories = [];
const remappings = [];
const compilationSettings = {
language: 'Solidity',
sources: {},
settings: {
optimizer: {
enabled: solcConfig['optimize'],
runs: solcConfig['optimize-runs']
},
remappings,
outputSelection: {
'*': {
'': ['ast'],
'*': [
'abi',
'devdoc',
'evm.bytecode',
'evm.deployedBytecode',
'evm.gasEstimates',
'evm.legacyAssembly',
'evm.methodIdentifiers',
'metadata',
'userdoc'
]
}
}
}
};
async.waterfall([
function checkSolc(next) {
const solc = shelljs.which('solc');
if (!solc) {
logger.error('solc is not installed on your machine');
logger.info('You can install it by following the instructions on: http://solidity.readthedocs.io/en/latest/installing-solidity.html');
return next('Compiler not installed');
}
logger.info("compiling solidity contracts with command line solc...");
next();
},
function getContentAndRemappings(next) {
async.each(contractFiles, (file, eachCb) => {
file.prepareForCompilation(options.isCoverage).then((content) => {
// add contract directory and all it's recusrive import direcotries to allowed directories
let dir = path.dirname(file.path);
if (!allowedDirectories.includes(dir)) allowedDirectories.push(dir);
file.importRemappings.forEach((importRemapping) => {
dir = path.dirname(importRemapping.target);
if (!allowedDirectories.includes(dir)) allowedDirectories.push(dir);
const remapping = `${importRemapping.prefix}=${importRemapping.target}`;
if (!remappings.includes(remapping)) {
remappings.push(remapping);
}
});
// TODO change this to Embark's utils function once embark-solc is in the mono-repo
compilationSettings.sources[file.path.replace(/\\/g, '/')] = {
content: content.replace(/\r\n/g, '\n')
};
eachCb();
}).catch(eachCb);
}, next);
},
function compile(next) {
compileSolcContract(logger, compilationSettings, allowedDirectories, (err, compileString) => {
if (err) {
return next(err);
}
let json;
try {
json = JSON.parse(compileString);
} catch (e) {
logger.error(e.message || e);
return callback(`Compiling returned an unreadable result`);
}
embark.events.emit('contracts:compiled:solc', json);
const contracts = json.contracts;
// Check for errors
if (json.errors) {
let isError = false;
json.errors.forEach(error => {
if (error.severity === 'error') {
isError = true;
logger.error(error.formattedMessage);
} else {
logger.warn(error.formattedMessage);
}
logger.debug(error.message); // Print more error information in debug
});
if (isError) {
return next(`Error while compiling`);
}
}
next(null, contracts);
});
},
function populateCompiledObject(contracts, next) {
const compiledObject = {};
for (let contractFile in contracts) {
for (let contractName in contracts[contractFile]) {
let contract = contracts[contractFile][contractName];
let filename = contractFile;
for (let directory of contractDirectories) {
let match = new RegExp("^" + directory);
filename = filename.replace(match, '');
}
let className = contractName;
const contractFileMatch = className.match(/.sol:(.*)/);
if (contractFileMatch) {
className = contractFileMatch[1];
}
compiledObject[className] = {};
compiledObject[className].code = contract.evm.bytecode.object;
compiledObject[className].linkReferences = contract.evm.bytecode.linkReferences;
compiledObject[className].runtimeBytecode = contract.evm.deployedBytecode.object;
compiledObject[className].realRuntimeBytecode = contract.evm.deployedBytecode.object.slice(0, -68);
compiledObject[className].swarmHash = contract.evm.deployedBytecode.object.slice(-68).slice(0, 64);
compiledObject[className].gasEstimates = contract.evm.gasEstimates;
compiledObject[className].functionHashes = contract.evm.methodIdentifiers;
compiledObject[className].abiDefinition = contract.abi;
compiledObject[className].userdoc = contract.userdoc;
compiledObject[className].filename = filename;
const normalized = path.normalize(filename);
const origContract = contractFiles.find(contractFile => normalized.includes(path.normalize(contractFile.originalPath)));
if (origContract) {
compiledObject[className].originalFilename = path.normalize(origContract.originalPath);
}
}
}
next(null, compiledObject);
}
], (err, compiledObject) => {
callback(err, compiledObject);
if (outputBinary) {
embark.events.once("outputDone", () => {
async.eachOf(compiledObject, (contract, className, eachCb) => {
fs.writeFile(path.join(outputDir, className + ".bin"), compiledObject[className].code, eachCb);
}, (err) => {
if (err) {
logger.error("Error writing binary file", err.message || err);
}
});
});
}
});
}
module.exports = {
compileSolc,
compileSolcContract,
getSolcVersion
};

View File

@ -0,0 +1,4 @@
{
"extends": "../../tsconfig.json",
"include": ["src/**/*"]
}

View File

@ -0,0 +1,3 @@
{
"extends": "../../tslint.json"
}

View File

@ -16698,7 +16698,7 @@ shelljs@0.5.3:
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.5.3.tgz#c54982b996c76ef0c1e6b59fbdc5825f5b713113" resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.5.3.tgz#c54982b996c76ef0c1e6b59fbdc5825f5b713113"
integrity sha1-xUmCuZbHbvDB5rWfvcWCX1txMRM= integrity sha1-xUmCuZbHbvDB5rWfvcWCX1txMRM=
shelljs@^0.8.2: shelljs@^0.8.1, shelljs@^0.8.2:
version "0.8.3" version "0.8.3"
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097" resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097"
integrity sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A== integrity sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==