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 ;
2017-12-16 20:39:30 +00:00
embark . registerCompiler ( ".sol" , this . compile _solidity . bind ( this ) ) ;
}
compile _solidity ( contractFiles , cb ) {
2018-05-17 13:48:01 +00:00
if ( ! contractFiles . length ) {
return cb ( ) ;
}
2017-12-16 20:39:30 +00:00
let self = this ;
let input = { } ;
async . waterfall ( [
function prepareInput ( callback ) {
async . each ( contractFiles ,
function ( file , fileCb ) {
let filename = file . filename ;
for ( let directory of self . contractDirectories ) {
2018-04-12 22:50:47 +00:00
let match = new RegExp ( "^" + directory ) ;
filename = filename . replace ( match , '' ) ;
2017-12-16 20:39:30 +00:00
}
file . content ( function ( fileContent ) {
2018-04-18 16:09:42 +00:00
if ( ! fileContent ) {
2018-05-08 21:49:46 +00:00
self . logger . error ( _ _ ( 'Error while loading the content of ' ) + filename ) ;
2018-04-18 16:09:42 +00:00
return fileCb ( ) ;
}
2018-08-07 19:26:39 +00:00
input [ filename ] = { content : fileContent . replace ( /\r\n/g , '\n' ) , path : file . path } ;
2018-04-10 20:38:49 +00:00
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 ( ) ;
}
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-01-27 20:07:48 +00:00
let jsonObj = {
language : 'Solidity' ,
sources : input ,
settings : {
optimizer : {
enabled : true ,
runs : 200
} ,
outputSelection : {
'*' : {
2018-08-07 19:26:39 +00:00
'' : [
'ast' ,
'legacyAST'
] ,
'*' : [
'abi' ,
'devdoc' ,
'evm.bytecode' ,
'evm.deployedBytecode' ,
'evm.gasEstimates' ,
'evm.legacyAssembly' ,
'evm.methodIdentifiers' ,
'metadata' ,
'userdoc'
]
2018-01-27 20:07:48 +00:00
}
}
}
} ;
2018-06-14 08:09:02 +00:00
self . solcW . compile ( jsonObj , function ( err , output ) {
2018-08-07 19:26:39 +00:00
self . events . emit ( 'contracts:compile:solc' , jsonObj ) ;
2018-06-14 08:09:02 +00:00
if ( err ) {
return callback ( err ) ;
}
2018-08-07 19:26:39 +00:00
output . errors = [ ] ; // TODO REMOVE THIS
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 ++ ) {
2018-01-27 20:07:48 +00:00
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.plugins.emitAndRunActionsForEvent('contracts:compiled:solc', output);
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 ;
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 ;
}
2017-12-16 20:39:30 +00:00
}
callback ( null , compiled _object ) ;
}
] , function ( err , result ) {
cb ( err , result ) ;
} ) ;
}
}
module . exports = Solidity ;