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 ;
2017-12-30 21:48:53 +00:00
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 ;
2018-06-14 23:37:52 +00:00
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 ) ) ;
2018-08-07 04:28:26 +00:00
embark . registerAPICall (
'post' ,
'/embark-api/contract/compile' ,
( req , res ) => {
2018-08-13 11:44:42 +00:00
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 ) ;
2018-08-07 04:28:26 +00:00
} ) ;
}
) ;
2017-12-16 20:39:30 +00:00
}
2018-08-13 11:44:42 +00:00
_compile ( jsonObj , returnAllErrors , callback ) {
2018-08-27 20:22:53 +00:00
const self = this ;
self . solcW . compile ( jsonObj , function ( err , output ) {
self . events . emit ( 'contracts:compile:solc' , jsonObj ) ;
if ( err ) {
2018-08-08 06:27:14 +00:00
return callback ( err ) ;
}
2018-08-27 20:22:53 +00:00
2018-08-08 06:27:14 +00:00
if ( output . errors ) {
2018-08-27 20:22:53 +00:00
for ( let i = 0 ; i < output . errors . length ; i ++ ) {
2018-08-08 06:27:14 +00:00
if ( output . errors [ i ] . type === 'Warning' ) {
2018-08-27 20:22:53 +00:00
self . logger . warn ( output . errors [ i ] . formattedMessage ) ;
2018-08-08 06:27:14 +00:00
}
if ( output . errors [ i ] . type === 'Error' || output . errors [ i ] . severity === 'error' ) {
return callback ( new Error ( "Solidity errors: " + output . errors [ i ] . formattedMessage ) . message ) ;
}
}
}
2018-08-27 20:22:53 +00:00
self . events . emit ( 'contracts:compiled:solc' , output ) ;
2018-08-08 06:27:14 +00:00
callback ( null , output ) ;
} ) ;
}
2018-08-13 11:44:42 +00:00
compile _solidity _code ( codeInputs , originalFilepaths , returnAllErrors , cb ) {
2018-08-07 04:28:26 +00:00
const self = this ;
2018-04-17 21:51:36 +00:00
2017-12-16 20:39:30 +00:00
async . waterfall ( [
function loadCompiler ( callback ) {
2018-05-18 17:41:25 +00:00
if ( self . solcAlreadyLoaded ) {
2017-12-16 20:39:30 +00:00
return callback ( ) ;
}
2018-06-14 23:37:52 +00:00
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" ) + "..." ) ;
2018-08-13 11:44:42 +00:00
let jsonObj = {
2018-01-27 20:07:48 +00:00
language : 'Solidity' ,
2018-08-07 04:28:26 +00:00
sources : codeInputs ,
2018-01-27 20:07:48 +00:00
settings : {
optimizer : {
2018-08-30 17:27:18 +00:00
enabled : ( ! options . disableOptimizations && self . options . optimize ) ,
2018-08-20 13:27:23 +00:00
runs : self . options [ "optimize-runs" ]
2018-01-27 20:07:48 +00:00
} ,
outputSelection : {
'*' : {
2018-09-19 19:51:11 +00:00
'' : [ 'ast' ] ,
2018-08-07 19:26:39 +00:00
'*' : [
'abi' ,
'devdoc' ,
'evm.bytecode' ,
'evm.deployedBytecode' ,
'evm.gasEstimates' ,
'evm.legacyAssembly' ,
'evm.methodIdentifiers' ,
'metadata' ,
'userdoc'
]
2018-01-27 20:07:48 +00:00
}
}
}
} ;
2018-08-27 20:22:53 +00:00
self . _compile ( jsonObj , returnAllErrors , callback ) ;
2017-12-16 20:39:30 +00:00
} ,
function createCompiledObject ( output , callback ) {
let json = output . contracts ;
2018-01-17 20:09:19 +00:00
if ( ! output || ! output . contracts ) {
2018-05-08 21:49:46 +00:00
return callback ( new Error ( _ _ ( "error compiling for unknown reasons" ) ) ) ;
2018-01-17 20:09:19 +00:00
}
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 = { } ;
2018-01-27 20:07:48 +00:00
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 ;
2018-08-07 04:28:26 +00:00
compiled _object [ className ] . originalFilename = originalFilepaths [ filename ] ;
2018-01-27 20:07:48 +00:00
}
2017-12-16 20:39:30 +00:00
}
callback ( null , compiled _object ) ;
}
] , function ( err , result ) {
cb ( err , result ) ;
} ) ;
}
2018-08-07 04:28:26 +00:00
compile _solidity ( contractFiles , cb ) {
if ( ! contractFiles . length ) {
return cb ( ) ;
}
let self = this ;
let input = { } ;
let originalFilepath = { } ;
async . waterfall ( [
function prepareInput ( callback ) {
async . each ( contractFiles ,
2018-08-13 11:44:42 +00:00
function ( file , fileCb ) {
2018-08-07 04:28:26 +00:00
let filename = file . filename ;
for ( let directory of self . contractDirectories ) {
let match = new RegExp ( "^" + directory ) ;
filename = filename . replace ( match , '' ) ;
}
originalFilepath [ filename ] = file . filename ;
2018-08-13 11:44:42 +00:00
file . content ( function ( fileContent ) {
2018-08-07 04:28:26 +00:00
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 ) {
2018-08-08 06:27:14 +00:00
self . compile _solidity _code ( input , originalFilepath , false , callback ) ;
2018-08-07 04:28:26 +00:00
}
] , function ( err , result ) {
cb ( err , result ) ;
} ) ;
}
2017-12-16 20:39:30 +00:00
}
module . exports = Solidity ;