|
|
|
@ -4,11 +4,13 @@ import { update } from 'solc/abi' |
|
|
|
|
import * as webworkify from 'webworkify-webpack' |
|
|
|
|
import compilerInput from './compiler-input' |
|
|
|
|
import EventManager from '../lib/eventManager' |
|
|
|
|
import { default as txHelper } from './txHelper'; |
|
|
|
|
import { Source, SourceWithTarget, MessageFromWorker, CompilerState, CompilationResult,
|
|
|
|
|
visitContractsCallbackParam, visitContractsCallbackInterface, CompilationError,
|
|
|
|
|
gatherImportsCallbackInterface,
|
|
|
|
|
isFunctionDescription } from './types' |
|
|
|
|
import txHelper from './txHelper' |
|
|
|
|
import { |
|
|
|
|
Source, SourceWithTarget, MessageFromWorker, CompilerState, CompilationResult, |
|
|
|
|
visitContractsCallbackParam, visitContractsCallbackInterface, CompilationError, |
|
|
|
|
gatherImportsCallbackInterface, |
|
|
|
|
isFunctionDescription |
|
|
|
|
} from './types' |
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
trigger compilationFinished, compilerLoaded, compilationStarted, compilationDuration |
|
|
|
@ -41,7 +43,7 @@ export class Compiler { |
|
|
|
|
} |
|
|
|
|
this.state.compilationStartTime = null |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.event.register('compilationStarted', () => { |
|
|
|
|
this.state.compilationStartTime = new Date().getTime() |
|
|
|
|
}) |
|
|
|
@ -53,7 +55,7 @@ export class Compiler { |
|
|
|
|
* @param value value of key in CompilerState |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
set <K extends keyof CompilerState>(key: K, value: CompilerState[K]): void { |
|
|
|
|
set <K extends keyof CompilerState> (key: K, value: CompilerState[K]): void { |
|
|
|
|
this.state[key] = value |
|
|
|
|
if (key === 'runs') this.state['runs'] = parseInt(value) |
|
|
|
|
} |
|
|
|
@ -68,9 +70,8 @@ export class Compiler { |
|
|
|
|
this.gatherImports(files, missingInputs, (error, input) => { |
|
|
|
|
if (error) { |
|
|
|
|
this.state.lastCompilationResult = null |
|
|
|
|
this.event.trigger('compilationFinished', [false, {'error': { formattedMessage: error, severity: 'error' }}, files]) |
|
|
|
|
} else if(this.state.compileJSON && input) |
|
|
|
|
this.state.compileJSON(input) |
|
|
|
|
this.event.trigger('compilationFinished', [false, { error: { formattedMessage: error, severity: 'error' } }, files]) |
|
|
|
|
} else if (this.state.compileJSON && input) { this.state.compileJSON(input) } |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -102,7 +103,7 @@ export class Compiler { |
|
|
|
|
|
|
|
|
|
onInternalCompilerLoaded (): void { |
|
|
|
|
if (this.state.worker === null) { |
|
|
|
|
const compiler: any = typeof (window) !== 'undefined' && window['Module'] ? require('solc/wrapper')(window['Module']) : require('solc')
|
|
|
|
|
const compiler: any = typeof (window) !== 'undefined' && window['Module'] ? require('solc/wrapper')(window['Module']) : require('solc') |
|
|
|
|
this.state.compileJSON = (source: SourceWithTarget) => { |
|
|
|
|
const missingInputs: string[] = [] |
|
|
|
|
const missingInputsCallback = (path: string) => { |
|
|
|
@ -111,9 +112,9 @@ export class Compiler { |
|
|
|
|
} |
|
|
|
|
let result: CompilationResult = {} |
|
|
|
|
try { |
|
|
|
|
if(source && source.sources) { |
|
|
|
|
const {optimize, runs, evmVersion, language} = this.state |
|
|
|
|
const input = compilerInput(source.sources, {optimize, runs, evmVersion, language}) |
|
|
|
|
if (source && source.sources) { |
|
|
|
|
const { optimize, runs, evmVersion, language } = this.state |
|
|
|
|
const input = compilerInput(source.sources, { optimize, runs, evmVersion, language }) |
|
|
|
|
result = JSON.parse(compiler.compile(input, { import: missingInputsCallback })) |
|
|
|
|
} |
|
|
|
|
} catch (exception) { |
|
|
|
@ -138,7 +139,7 @@ export class Compiler { |
|
|
|
|
const checkIfFatalError = (error: CompilationError) => { |
|
|
|
|
// Ignore warnings and the 'Deferred import' error as those are generated by us as a workaround
|
|
|
|
|
const isValidError = (error.message && error.message.includes('Deferred import')) ? false : error.severity !== 'warning' |
|
|
|
|
if(isValidError) noFatalErrors = false |
|
|
|
|
if (isValidError) noFatalErrors = false |
|
|
|
|
} |
|
|
|
|
if (data.error) checkIfFatalError(data.error) |
|
|
|
|
if (data.errors) data.errors.forEach((err) => checkIfFatalError(err)) |
|
|
|
@ -151,9 +152,8 @@ export class Compiler { |
|
|
|
|
this.internalCompile(source.sources, missingInputs) |
|
|
|
|
} else { |
|
|
|
|
data = this.updateInterface(data) |
|
|
|
|
if(source) |
|
|
|
|
{ |
|
|
|
|
source.target = this.state.target; |
|
|
|
|
if (source) { |
|
|
|
|
source.target = this.state.target |
|
|
|
|
this.state.lastCompilationResult = { |
|
|
|
|
data: data, |
|
|
|
|
source: source |
|
|
|
@ -167,7 +167,7 @@ export class Compiler { |
|
|
|
|
* @dev Load compiler using given version (used by remix-tests CLI) |
|
|
|
|
* @param version compiler version |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
loadRemoteVersion (version: string): void { |
|
|
|
|
console.log(`Loading remote solc version ${version} ...`) |
|
|
|
|
const compiler: any = require('solc') |
|
|
|
@ -183,9 +183,9 @@ export class Compiler { |
|
|
|
|
} |
|
|
|
|
let result: CompilationResult = {} |
|
|
|
|
try { |
|
|
|
|
if(source && source.sources) { |
|
|
|
|
const {optimize, runs, evmVersion, language} = this.state |
|
|
|
|
const input = compilerInput(source.sources, {optimize, runs, evmVersion, language}) |
|
|
|
|
if (source && source.sources) { |
|
|
|
|
const { optimize, runs, evmVersion, language } = this.state |
|
|
|
|
const input = compilerInput(source.sources, { optimize, runs, evmVersion, language }) |
|
|
|
|
result = JSON.parse(remoteCompiler.compile(input, { import: missingInputsCallback })) |
|
|
|
|
} |
|
|
|
|
} catch (exception) { |
|
|
|
@ -203,7 +203,7 @@ export class Compiler { |
|
|
|
|
* @param usingWorker if true, load compiler using worker |
|
|
|
|
* @param url URL to load compiler from |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
loadVersion (usingWorker: boolean, url: string): void { |
|
|
|
|
console.log('Loading ' + url + ' ' + (usingWorker ? 'with worker' : 'without worker')) |
|
|
|
|
this.event.trigger('loadingCompiler', [url, usingWorker]) |
|
|
|
@ -222,7 +222,7 @@ export class Compiler { |
|
|
|
|
* @dev Load compiler using 'script' element (without worker) |
|
|
|
|
* @param url URL to load compiler from |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
loadInternal (url: string): void { |
|
|
|
|
delete window['Module'] |
|
|
|
|
// NOTE: workaround some browsers?
|
|
|
|
@ -257,16 +257,16 @@ export class Compiler { |
|
|
|
|
const data: MessageFromWorker = msg.data |
|
|
|
|
switch (data.cmd) { |
|
|
|
|
case 'versionLoaded': |
|
|
|
|
if(data.data) this.onCompilerLoaded(data.data) |
|
|
|
|
if (data.data) this.onCompilerLoaded(data.data) |
|
|
|
|
break |
|
|
|
|
case 'compiled':
|
|
|
|
|
case 'compiled': |
|
|
|
|
{ |
|
|
|
|
let result: CompilationResult |
|
|
|
|
if(data.data && data.job !== undefined && data.job >= 0) { |
|
|
|
|
if (data.data && data.job !== undefined && data.job >= 0) { |
|
|
|
|
try { |
|
|
|
|
result = JSON.parse(data.data) |
|
|
|
|
} catch (exception) { |
|
|
|
|
result = { error : { formattedMessage: 'Invalid JSON output from the compiler: ' + exception }} |
|
|
|
|
result = { error: { formattedMessage: 'Invalid JSON output from the compiler: ' + exception } } |
|
|
|
|
} |
|
|
|
|
let sources: SourceWithTarget = {} |
|
|
|
|
if (data.job in jobs !== undefined) { |
|
|
|
@ -281,23 +281,23 @@ export class Compiler { |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
this.state.worker.addEventListener('error', (msg: Record <'data', MessageFromWorker>) => { |
|
|
|
|
this.onCompilationFinished({ error: { formattedMessage: 'Worker error: ' + msg.data }}) |
|
|
|
|
this.onCompilationFinished({ error: { formattedMessage: 'Worker error: ' + msg.data } }) |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
this.state.compileJSON = (source: SourceWithTarget) => { |
|
|
|
|
if(source && source.sources) { |
|
|
|
|
const {optimize, runs, evmVersion, language} = this.state |
|
|
|
|
jobs.push({sources: source}) |
|
|
|
|
if (source && source.sources) { |
|
|
|
|
const { optimize, runs, evmVersion, language } = this.state |
|
|
|
|
jobs.push({ sources: source }) |
|
|
|
|
this.state.worker.postMessage({ |
|
|
|
|
cmd: 'compile',
|
|
|
|
|
job: jobs.length - 1,
|
|
|
|
|
input: compilerInput(source.sources, {optimize, runs, evmVersion, language}) |
|
|
|
|
cmd: 'compile', |
|
|
|
|
job: jobs.length - 1, |
|
|
|
|
input: compilerInput(source.sources, { optimize, runs, evmVersion, language }) |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.state.worker.postMessage({ |
|
|
|
|
cmd: 'loadVersion',
|
|
|
|
|
cmd: 'loadVersion', |
|
|
|
|
data: url |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
@ -340,8 +340,7 @@ export class Compiler { |
|
|
|
|
} |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
if(cb) |
|
|
|
|
cb(null, { 'sources': files }) |
|
|
|
|
if (cb) { cb(null, { sources: files }) } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@ -353,7 +352,7 @@ export class Compiler { |
|
|
|
|
const tmp: RegExpExecArray | null = /^(\d+.\d+.\d+)/.exec(version) |
|
|
|
|
return tmp ? tmp[1] : version |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @dev Update ABI according to current compiler version |
|
|
|
|
* @param data Compilation result |
|
|
|
@ -366,12 +365,12 @@ export class Compiler { |
|
|
|
|
// yul compiler does not return any abi,
|
|
|
|
|
// we default to accept the fallback function (which expect raw data as argument).
|
|
|
|
|
contract.object.abi.push({ |
|
|
|
|
'payable': true, |
|
|
|
|
'stateMutability': 'payable', |
|
|
|
|
'type': 'fallback' |
|
|
|
|
payable: true, |
|
|
|
|
stateMutability: 'payable', |
|
|
|
|
type: 'fallback' |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
if(data && data.contracts && this.state.currentVersion) { |
|
|
|
|
if (data && data.contracts && this.state.currentVersion) { |
|
|
|
|
const version = this.truncateVersion(this.state.currentVersion) |
|
|
|
|
data.contracts[contract.file][contract.name].abi = update(version, contract.object.abi) |
|
|
|
|
// if "constant" , payable must not be true and stateMutability must be view.
|
|
|
|
@ -379,10 +378,10 @@ export class Compiler { |
|
|
|
|
for (const item of data.contracts[contract.file][contract.name].abi) { |
|
|
|
|
if (isFunctionDescription(item) && item.constant) { |
|
|
|
|
item.payable = false |
|
|
|
|
item.stateMutability = 'view'; |
|
|
|
|
}
|
|
|
|
|
item.stateMutability = 'view' |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}
|
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
return data |
|
|
|
|
} |
|
|
|
@ -392,7 +391,7 @@ export class Compiler { |
|
|
|
|
* @param name contract name |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
getContract (name: string): Record<string, any> | null { |
|
|
|
|
getContract (name: string): Record<string, any> | null { |
|
|
|
|
if (this.state.lastCompilationResult && this.state.lastCompilationResult.data && this.state.lastCompilationResult.data.contracts) { |
|
|
|
|
return txHelper.getContract(name, this.state.lastCompilationResult.data.contracts) |
|
|
|
|
} |
|
|
|
@ -457,4 +456,3 @@ export class Compiler { |
|
|
|
|
return null |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|