embark-area-51/lib/modules/solidity/index.js

234 lines
7.9 KiB
JavaScript
Raw Normal View History

2017-12-16 20:39:30 +00:00
let async = require('../../utils/async_extend.js');
let SolcW = require('./solcW.js');
class Solidity {
2018-06-04 17:12:51 +00:00
constructor(embark, options) {
2017-12-16 20:39:30 +00:00
this.logger = embark.logger;
this.events = embark.events;
2018-06-04 19:36:43 +00:00
this.ipc = options.ipc;
2018-05-30 16:26:49 +00:00
this.contractDirectories = embark.config.contractDirectories;
2018-05-18 17:41:25 +00:00
this.solcAlreadyLoaded = false;
this.solcW = null;
this.useDashboard = options.useDashboard;
2018-08-20 13:27:23 +00:00
this.options = embark.config.embarkConfig.options.solc;
2017-12-16 20:39:30 +00:00
embark.registerCompiler(".sol", this.compile_solidity.bind(this));
embark.registerAPICall(
'post',
'/embark-api/contract/compile',
(req, res) => {
const input = {'fiddler': {content: req.body.code.replace(/\r\n/g, '\n')}};
this.compile_solidity_code(input, {}, true, (errors, compilationResult) => {
const responseData = {errors: errors, compilationResult: compilationResult};
this.logger.trace(`POST response /embark-api/contract/compile:\n ${JSON.stringify(responseData)}`);
res.send(responseData);
});
}
);
2017-12-16 20:39:30 +00:00
}
_compile(jsonObj, returnAllErrors, callback) {
this.solcW.compile(jsonObj, (err, output) => {
if (err) {
return callback(err);
}
if (output.errors && returnAllErrors) {
return callback(output.errors);
}
if (output.errors) {
for (let i = 0; i < output.errors.length; i++) {
if (output.errors[i].type === 'Warning') {
this.logger.warn(output.errors[i].formattedMessage);
}
if (output.errors[i].type === 'Error' || output.errors[i].severity === 'error') {
return callback(new Error("Solidity errors: " + output.errors[i].formattedMessage).message);
}
}
}
callback(null, output);
});
}
compile_solidity_code(codeInputs, originalFilepaths, returnAllErrors, cb) {
const self = this;
2017-12-16 20:39:30 +00:00
async.waterfall([
function prepareInput(callback) {
async.each(contractFiles,
function(file, fileCb) {
let filename = file.filename;
for (let directory of self.contractDirectories) {
let match = new RegExp("^" + directory);
filename = filename.replace(match, '');
2017-12-16 20:39:30 +00:00
}
originalFilepath[filename] = file.filename;
2017-12-16 20:39:30 +00:00
file.content(function(fileContent) {
if (!fileContent) {
2018-05-08 21:49:46 +00:00
self.logger.error(__('Error while loading the content of ') + filename);
return fileCb();
}
2018-08-07 19:26:39 +00:00
input[filename] = {content: fileContent.replace(/\r\n/g, '\n'), path: file.path};
fileCb();
2017-12-16 20:39:30 +00:00
});
},
function (err) {
callback(err);
}
);
},
function loadCompiler(callback) {
2018-05-18 17:41:25 +00:00
if (self.solcAlreadyLoaded) {
2017-12-16 20:39:30 +00:00
return callback();
}
self.solcW = new SolcW({logger: self.logger, events: self.events, ipc: self.ipc, useDashboard: self.useDashboard});
2017-12-16 20:39:30 +00:00
2018-05-08 21:49:46 +00:00
self.logger.info(__("loading solc compiler") + "..");
2018-05-18 17:41:25 +00:00
self.solcW.load_compiler(function (err) {
self.solcAlreadyLoaded = true;
2017-12-16 20:39:30 +00:00
callback(err);
});
},
function compileContracts(callback) {
2018-05-08 21:49:46 +00:00
self.logger.info(__("compiling solidity contracts") + "...");
let jsonObj = {
language: 'Solidity',
sources: codeInputs,
settings: {
optimizer: {
enabled: (!options.disableOptimizations && self.options.optimize),
2018-08-20 13:27:23 +00:00
runs: self.options["optimize-runs"]
},
outputSelection: {
'*': {
'': ['ast'],
2018-08-07 19:26:39 +00:00
'*': [
'abi',
'devdoc',
'evm.bytecode',
'evm.deployedBytecode',
'evm.gasEstimates',
'evm.legacyAssembly',
'evm.methodIdentifiers',
'metadata',
'userdoc'
]
}
}
}
};
self.solcW.compile(jsonObj, function (err, output) {
2018-08-07 19:26:39 +00:00
self.events.emit('contracts:compile:solc', jsonObj);
if(err){
return callback(err);
}
2018-08-07 19:26:39 +00:00
2017-12-16 20:39:30 +00:00
if (output.errors) {
2017-12-27 18:07:13 +00:00
for (let i=0; i<output.errors.length; i++) {
if (output.errors[i].type === 'Warning') {
self.logger.warn(output.errors[i].formattedMessage);
2017-12-27 18:07:13 +00:00
}
2018-02-08 00:40:59 +00:00
if (output.errors[i].type === 'Error' || output.errors[i].severity === 'error') {
2018-03-02 23:01:48 +00:00
return callback(new Error("Solidity errors: " + output.errors[i].formattedMessage).message);
2017-12-16 20:39:30 +00:00
}
}
}
2018-08-07 19:26:39 +00:00
self.events.emit('contracts:compiled:solc', output);
2017-12-16 20:39:30 +00:00
callback(null, output);
});
},
function createCompiledObject(output, callback) {
let json = output.contracts;
if (!output || !output.contracts) {
2018-05-08 21:49:46 +00:00
return callback(new Error(__("error compiling for unknown reasons")));
}
2017-12-27 18:07:13 +00:00
if (Object.keys(output.contracts).length === 0 && output.sourceList.length > 0) {
2018-05-08 21:49:46 +00:00
return callback(new Error(__("error compiling. There are sources available but no code could be compiled, likely due to fatal errors in the solidity code")).message);
2017-12-27 18:07:13 +00:00
}
2017-12-16 20:39:30 +00:00
let compiled_object = {};
for (let contractFile in json) {
for (let contractName in json[contractFile]) {
let contract = json[contractFile][contractName];
const className = contractName;
const filename = contractFile;
compiled_object[className] = {};
compiled_object[className].code = contract.evm.bytecode.object;
compiled_object[className].runtimeBytecode = contract.evm.deployedBytecode.object;
compiled_object[className].realRuntimeBytecode = contract.evm.deployedBytecode.object.slice(0, -68);
compiled_object[className].swarmHash = contract.evm.deployedBytecode.object.slice(-68).slice(0, 64);
compiled_object[className].gasEstimates = contract.evm.gasEstimates;
compiled_object[className].functionHashes = contract.evm.methodIdentifiers;
compiled_object[className].abiDefinition = contract.abi;
compiled_object[className].filename = filename;
compiled_object[className].originalFilename = originalFilepaths[filename];
}
2017-12-16 20:39:30 +00:00
}
callback(null, compiled_object);
}
], function (err, result) {
cb(err, result);
});
}
compile_solidity(contractFiles, cb) {
if (!contractFiles.length) {
return cb();
}
let self = this;
let input = {};
let originalFilepath = {};
async.waterfall([
function prepareInput(callback) {
async.each(contractFiles,
function (file, fileCb) {
let filename = file.filename;
for (let directory of self.contractDirectories) {
let match = new RegExp("^" + directory);
filename = filename.replace(match, '');
}
originalFilepath[filename] = file.filename;
file.content(function (fileContent) {
if (!fileContent) {
self.logger.error(__('Error while loading the content of ') + filename);
return fileCb();
}
input[filename] = {content: fileContent.replace(/\r\n/g, '\n')};
fileCb();
});
},
function (err) {
callback(err);
}
);
},
function compile(callback) {
self.compile_solidity_code(input, originalFilepath, false, callback);
}
], function (err, result) {
cb(err, result);
});
}
2017-12-16 20:39:30 +00:00
}
module.exports = Solidity;