diff --git a/packages/solc-transpiler/package.json b/packages/solc-transpiler/package.json index 24459d182ae8..e6c779c8d3bd 100644 --- a/packages/solc-transpiler/package.json +++ b/packages/solc-transpiler/package.json @@ -31,6 +31,7 @@ "dependencies": { "@eth-optimism/core-utils": "~0.0.1-alpha.7", "@eth-optimism/rollup-dev-tools": "~0.0.1-alpha.7", + "require-from-string": "^2.0.2", "solc": "^0.5.12" }, "devDependencies": { diff --git a/packages/solc-transpiler/src/compiler.ts b/packages/solc-transpiler/src/compiler.ts index ca96344aad7a..c9078b9f2de9 100644 --- a/packages/solc-transpiler/src/compiler.ts +++ b/packages/solc-transpiler/src/compiler.ts @@ -17,6 +17,8 @@ import { remove0x, } from '@eth-optimism/core-utils' import * as solc from 'solc' +import { execSync } from 'child_process' +import * as requireFromString from 'require-from-string' const log: Logger = getLogger('solc-transpiler') @@ -36,6 +38,7 @@ interface TranspilationOutput { * @returns The Solc output as a string. */ export const compile = (configJsonString: string, callbacks?: any): string => { + const compiler = getCompiler(process.env.SOLC_VERSION) log.debug(`Trying to transpile with config: ${configJsonString}`) let json: any try { @@ -43,7 +46,7 @@ export const compile = (configJsonString: string, callbacks?: any): string => { } catch (e) { log.debug(`Cannot parse JSON: ${JSON.stringify(e)}`) // todo: populate some errors - return solc.compile(configJsonString) + return compiler.compile(configJsonString) } const inputErrors: string = getInputErrors(json) @@ -53,8 +56,8 @@ export const compile = (configJsonString: string, callbacks?: any): string => { const solcConfig: string = getSolcConfig(json) const resString = !!callbacks - ? solc.compile(solcConfig, callbacks) - : solc.compile(solcConfig) + ? compiler.compile(solcConfig, callbacks) + : compiler.compile(solcConfig) const res = JSON.parse(resString) if ( @@ -110,6 +113,64 @@ export const compile = (configJsonString: string, callbacks?: any): string => { return formatOutput(res, json) } +/** + * Gets the requested version of the solc module. solc-js provides downloadable + * versions of itself which can be downloaded and used to compile contracts that + * require different compiler versions. This function must be synchronous so it + * can be used in the compilation process which is also synchronous. To achieve + * this we construct a string of JavaScript which downloads the latest version + * of solc and run that code using `execSync` + * + * @param versionString The requested version of solc + * @returns The requested version of the `solc` module or the latest version + */ +const getCompiler = (versionString: string): typeof solc => { + if (!versionString) { + return solc + } + + const getCompilerString = ` + function httpsRequest(params, postData) { + return new Promise(function(resolve, reject) { + var req = https.request(params, function(res) { + var body = []; + res.on("data", function(chunk) { + body.push(chunk); + }); + res.on("end", function() { + try { + body = Buffer.concat(body).toString(); + } catch(e) { + reject(e); + } + resolve(body); + }); + }); + req.on("error", function(err) { + reject(err); + }); + req.end(); + }); + } + + async function getSolcVersion(versionString) { + const listUrl = "https://ethereum.github.io/solc-bin/bin/list.json"; + const {releases} = JSON.parse(await httpsRequest(listUrl)) + const solcUrl = "https://ethereum.github.io/solc-bin/bin/" + releases[versionString]; + return await httpsRequest(solcUrl); + } + + (async () => { + await process.stdout.write(await getSolcVersion("${versionString}")); + })(); + ` + return solc.setupMethods( + requireFromString( + execSync(`${process.argv[0]} -e '${getCompilerString}'`).toString() + ) + ) +} + const getExecutionManagerAddress = (configObject: any): string => { return ( configObject.settings.executionManagerAddress || diff --git a/yarn.lock b/yarn.lock index 83295b388290..2a242b9148f0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8906,7 +8906,7 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= -require-from-string@^2.0.0: +require-from-string@^2.0.0, require-from-string@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==