UNPKG

@matterlabs/hardhat-zksync-solc

Version:
370 lines (369 loc) 18.4 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.saltFromUrl = exports.ZKSOLC_BIN_REPOSITORY = exports.getZksolcUrl = void 0; const task_names_1 = require("hardhat/builtin-tasks/task-names"); const config_env_1 = require("hardhat/internal/core/config/config-env"); const global_dir_1 = require("hardhat/internal/util/global-dir"); require("./type-extensions"); const artifacts_1 = require("hardhat/internal/artifacts"); const await_semaphore_1 = require("hardhat/internal/vendor/await-semaphore"); const fs_1 = __importDefault(require("fs")); const chalk_1 = __importDefault(require("chalk")); const semver_1 = __importDefault(require("semver")); const debug_1 = __importDefault(require("debug")); const compile_1 = require("./compile"); const utils_1 = require("./utils"); Object.defineProperty(exports, "getZksolcUrl", { enumerable: true, get: function () { return utils_1.getZksolcUrl; } }); Object.defineProperty(exports, "saltFromUrl", { enumerable: true, get: function () { return utils_1.saltFromUrl; } }); const constants_1 = require("./constants"); Object.defineProperty(exports, "ZKSOLC_BIN_REPOSITORY", { enumerable: true, get: function () { return constants_1.ZKSOLC_BIN_REPOSITORY; } }); const downloader_1 = require("./compile/downloader"); const zkvm_solc_downloader_1 = require("./compile/zkvm-solc-downloader"); const config_extractor_1 = require("./config-extractor"); const plugin_1 = require("./plugin"); require("@matterlabs/hardhat-zksync-telemetry"); const logDebug = (0, debug_1.default)('hardhat:core:tasks:compile'); const extractors = [ new config_extractor_1.SolcStringUserConfigExtractor(), new config_extractor_1.SolcSoloUserConfigExtractor(), new config_extractor_1.SolcMultiUserConfigExtractor(), ]; const zkVmSolcCompilerDownloaderMutex = new await_semaphore_1.Mutex(); const zkSolcCompilerDownloaderMutex = new await_semaphore_1.Mutex(); (0, config_env_1.extendConfig)((config, userConfig) => { if (userConfig.zksolc?.settings?.compilerPath) { constants_1.defaultZkSolcConfig.version = constants_1.ZKSOLC_COMPILER_PATH_VERSION; } config.zksolc = { ...constants_1.defaultZkSolcConfig, ...userConfig?.zksolc }; config.zksolc.settings = { ...constants_1.defaultZkSolcConfig.settings, ...userConfig?.zksolc?.settings }; config.zksolc.settings.optimizer = { ...constants_1.defaultZkSolcConfig.settings.optimizer, ...userConfig?.zksolc?.settings?.optimizer, }; config.zksolc.settings.libraries = { ...constants_1.defaultZkSolcConfig.settings.libraries, ...userConfig?.zksolc?.settings?.libraries, }; }); (0, config_env_1.extendEnvironment)((hre) => { if (hre.network.config.zksync) { hre.network.zksync = hre.network.config.zksync; let artifactsPath = hre.config.paths.artifacts; if (!artifactsPath.endsWith('-zk')) { artifactsPath = `${artifactsPath}-zk`; } let cachePath = hre.config.paths.cache; if (!cachePath.endsWith('-zk')) { cachePath = `${cachePath}-zk`; } // Forcibly update the artifacts object. hre.config.paths.artifacts = artifactsPath; hre.config.paths.cache = cachePath; hre.artifacts = new artifacts_1.Artifacts(artifactsPath); hre.config.solidity.compilers.forEach(async (compiler) => (0, utils_1.updateDefaultCompilerConfig)({ compiler }, hre.config.zksolc)); for (const [file, compiler] of Object.entries(hre.config.solidity.overrides)) { (0, utils_1.updateDefaultCompilerConfig)({ compiler, file }, hre.config.zksolc); } } }); (0, config_env_1.task)(task_names_1.TASK_COMPILE).setAction(async (compilationArgs, hre, runSuper) => { if (hre.network.zksync) { await hre.run(constants_1.TASK_DOWNLOAD_ZKSOLC); await hre.run(constants_1.TASK_UPDATE_SOLIDITY_COMPILERS); } await runSuper(compilationArgs); }); (0, config_env_1.subtask)(constants_1.TASK_COMPILE_LINK) .addParam('sourceName', 'Source name of the artifact') .addParam('contractName', 'Contract name of the artifact') .addOptionalParam('libraries', undefined, undefined, config_env_1.types.any) .addFlag('withoutError', undefined) .setAction(plugin_1.compileLink); (0, config_env_1.subtask)(constants_1.TASK_DOWNLOAD_ZKSOLC, async (_args, hre) => { if (!hre.network.zksync) { return; } const compilersCache = await (0, global_dir_1.getCompilersDir)(); await zkSolcCompilerDownloaderMutex.use(async () => { const zksolcDownloader = await downloader_1.ZksolcCompilerDownloader.getDownloaderWithVersionValidated(hre.config.zksolc.version, hre.config.zksolc.settings.compilerPath ?? '', compilersCache); const isZksolcDownloaded = await zksolcDownloader.isCompilerDownloaded(); if (!isZksolcDownloaded) { await zksolcDownloader.downloadCompiler(); } hre.config.zksolc.settings.compilerPath = zksolcDownloader.getCompilerPath(); hre.config.zksolc.version = zksolcDownloader.getVersion(); }); }); (0, config_env_1.subtask)(constants_1.TASK_UPDATE_SOLIDITY_COMPILERS, async (_args, hre) => { if (!hre.network.zksync) { return; } const userSolidityConfig = hre.userConfig.solidity; const extractedConfigs = extractors .find((extractor) => extractor.suitable(userSolidityConfig)) ?.extract(userSolidityConfig); hre.config.solidity.compilers.forEach(async (compiler) => (0, utils_1.updateBreakableCompilerConfig)({ compiler }, hre.config.zksolc, semver_1.default.gte(hre.config.zksolc.version, '1.5.13') ? '1.0.2' : '1.0.1', extractedConfigs?.compilers ?? [])); for (const [file, compiler] of Object.entries(hre.config.solidity.overrides)) { (0, utils_1.updateBreakableCompilerConfig)({ compiler, file }, hre.config.zksolc, semver_1.default.gte(hre.config.zksolc.version, '1.5.13') ? '1.0.2' : '1.0.1', extractedConfigs?.overides ?? new Map()); } }); (0, config_env_1.subtask)(task_names_1.TASK_COMPILE_SOLIDITY_GET_SOURCE_NAMES, async (args, hre, runSuper) => { if (hre.network.zksync !== true) { return await runSuper(args); } if (hre.config.zksolc.settings.forceContractsToCompile) { return hre.config.zksolc.settings.forceContractsToCompile; } const contractsToCompile = hre.config.zksolc.settings.contractsToCompile; if (!contractsToCompile || contractsToCompile.length === 0) { return await runSuper(args); } const sourceNames = await runSuper(args); return sourceNames.filter((sourceName) => contractsToCompile.some((contractToCompile) => sourceName.includes(contractToCompile))); }); // This override is needed to invalidate cache when zksolc config is changed. (0, config_env_1.subtask)(task_names_1.TASK_COMPILE_SOLIDITY_GET_COMPILATION_JOBS, async (args, hre, runSuper) => { const { jobs, errors } = await runSuper(args); if (hre.network.zksync !== true || hre.config.zksolc.compilerSource !== 'binary') { return { jobs, errors }; } jobs.forEach((job) => { job.solidityConfig.zksolc = hre.config.zksolc; job.solidityConfig.zksolc.settings.compilerPath = hre.config.zksolc.settings.compilerPath; if (hre.config.zksolc.settings.libraries) { job.solidityConfig.settings.libraries = hre.config.zksolc.settings.libraries; } }); return { jobs, errors }; }); (0, config_env_1.subtask)(task_names_1.TASK_COMPILE_SOLIDITY_GET_ARTIFACT_FROM_COMPILATION_OUTPUT, async ({ sourceName, contractName, contractOutput, }, hre) => { if (hre.network.zksync !== true) { return (0, artifacts_1.getArtifactFromContractOutput)(sourceName, contractName, contractOutput); } let bytecode = contractOutput.evm?.bytecode?.object || contractOutput.evm?.deployedBytecode?.object || ''; bytecode = (0, utils_1.zeroxlify)(bytecode); const factoryDeps = {}; const entries = Object.entries(contractOutput.factoryDependencies || {}); for (const [hash, dependency] of entries) { factoryDeps[(0, utils_1.zeroxlify)(hash)] = dependency; } return { _format: constants_1.ZK_ARTIFACT_FORMAT_VERSION, contractName, sourceName, abi: contractOutput.abi, // technically, zkEVM has no difference between bytecode & deployedBytecode, // but both fields are included just in case bytecode, deployedBytecode: bytecode, // zksolc does not support unlinked objects, // all external libraries are either linked during compilation or inlined linkReferences: {}, deployedLinkReferences: {}, // ZKsync-specific field factoryDeps, }; }); (0, config_env_1.subtask)(task_names_1.TASK_COMPILE_SOLIDITY_RUN_SOLC, async (args, hre, runSuper) => { if (hre.network.zksync !== true) { return await runSuper(args); } return await (0, compile_1.compile)(hre.config.zksolc, args.input, args.solcPath); }); (0, config_env_1.subtask)(task_names_1.TASK_COMPILE_SOLIDITY_RUN_SOLCJS, async (args, hre, runSuper) => { if (hre.network.zksync !== true) { return await runSuper(args); } const solcPath = `${args.solcJsPath}.executable`; if (!fs_1.default.existsSync(solcPath)) { const solcJsExecutableCode = (0, utils_1.generateSolcJSExecutableCode)(args.solcJsPath, process.cwd()); fs_1.default.writeFileSync(solcPath, Buffer.from(solcJsExecutableCode), { encoding: 'utf-8', flag: 'w' }); fs_1.default.chmodSync(solcPath, '755'); } return await (0, compile_1.compile)(hre.config.zksolc, args.input, solcPath); }); /* * This task is overriden to: * - use valid zkvm solc version if that is needed and return valid SolcBuild object */ (0, config_env_1.subtask)(task_names_1.TASK_COMPILE_SOLIDITY_COMPILE_SOLC, async (args, hre, runSuper) => { if (hre.network.zksync !== true) { return await runSuper(args); } const solcBuild = await hre.run(task_names_1.TASK_COMPILE_SOLIDITY_GET_SOLC_BUILD, { quiet: args.quiet, solcVersion: args.solcVersion, compilationJob: args.compilationJob, }); await hre.run(task_names_1.TASK_COMPILE_SOLIDITY_LOG_RUN_COMPILER_START, { compilationJob: args.compilationJob, compilationJobs: args.compilationJobs, compilationJobIndex: args.compilationJobIndex, quiet: args.quiet, }); let output; if (solcBuild.isSolcJs) { output = await hre.run(task_names_1.TASK_COMPILE_SOLIDITY_RUN_SOLCJS, { input: args.input, solcJsPath: solcBuild.compilerPath, }); } else { output = await hre.run(task_names_1.TASK_COMPILE_SOLIDITY_RUN_SOLC, { input: args.input, solcPath: solcBuild.compilerPath, }); } await hre.run(task_names_1.TASK_COMPILE_SOLIDITY_LOG_RUN_COMPILER_END, { compilationJob: args.compilationJob, compilationJobs: args.compilationJobs, compilationJobIndex: args.compilationJobIndex, output, quiet: args.quiet, }); return { output, solcBuild }; }); // This task is overriden to: // - prevent unnecessary solc downloads when using docker // - download zksolc binary if needed // - validate zksolc binary (0, config_env_1.subtask)(task_names_1.TASK_COMPILE_SOLIDITY_GET_SOLC_BUILD, async (args, hre, runSuper) => { if (hre.network.zksync !== true) { return await runSuper(args); } if (hre.config.zksolc.compilerSource === 'docker') { // Versions are wrong here when using docker, because there is no // way to know them beforehand except to run the docker image, which // adds 5-10 seconds to startup time. We cannot read them from artifacts, // since that would make cache invalid every time, if the version is // different from the one in the docker image. // // If you wish to know the actual versions from build-info files, // please look at `output.version`, `output.long_version` // and `output.zk_version` in the generated JSON. return { compilerPath: '', isSolcJs: false, version: args.solcVersion, longVersion: '', }; } const compiler = args.compilationJob?.getSolcConfig(); if (compiler && compiler.eraVersion) { const compilersCache = await (0, global_dir_1.getCompilersDir)(); let compilerPath = ''; let version = ''; let normalizedVersion = ''; await zkVmSolcCompilerDownloaderMutex.use(async () => { const zkVmSolcCompilerDownloader = await zkvm_solc_downloader_1.ZkVmSolcCompilerDownloader.getDownloaderWithVersionValidated(compiler.eraVersion, compiler.version, compilersCache); const isZksolcDownloaded = await zkVmSolcCompilerDownloader.isCompilerDownloaded(); if (!isZksolcDownloaded) { await zkVmSolcCompilerDownloader.downloadCompiler(); } compilerPath = zkVmSolcCompilerDownloader.getCompilerPath(); version = zkVmSolcCompilerDownloader.getVersion(); normalizedVersion = (0, utils_1.getZkVmNormalizedVersion)(zkVmSolcCompilerDownloader.getSolcVersion(), zkVmSolcCompilerDownloader.getZkVmSolcVersion()); }); console.info(chalk_1.default.yellow((0, constants_1.COMPILING_INFO_MESSAGE_ZKVM_SOLC)(hre.config.zksolc.version, version))); return { compilerPath, isSolcJs: false, version, longVersion: normalizedVersion, }; } else { const solcBuild = await runSuper(args); console.info(chalk_1.default.yellow((0, constants_1.COMPILING_INFO_MESSAGE)(hre.config.zksolc.version, args.solcVersion))); return solcBuild; } }); (0, config_env_1.subtask)(task_names_1.TASK_COMPILE_SOLIDITY_LOG_COMPILATION_RESULT, async ({ compilationJobs }, hre, _runSuper) => { if (hre.config.zksolc.settings.areLibrariesMissing) { console.info(chalk_1.default.yellow(constants_1.MISSING_LIBRARIES_NOTICE)); console.info(chalk_1.default.red(constants_1.COMPILE_AND_DEPLOY_LIBRARIES_INSTRUCTIONS)); console.info(chalk_1.default.yellow(constants_1.MISSING_LIBRARY_LINK)); } else { let count = 0; for (const job of compilationJobs) { count += job.getResolvedFiles().filter((file) => job.emitsArtifacts(file)).length; } if (count > 0) { console.info(chalk_1.default.green(`Successfully compiled ${count} Solidity ${(0, utils_1.pluralize)(count, 'file')}`)); } } }); (0, config_env_1.subtask)(task_names_1.TASK_COMPILE_SOLIDITY_LOG_DOWNLOAD_COMPILER_START).setAction(async ({ isCompilerDownloaded, solcVersion, }) => { if (isCompilerDownloaded) { return; } console.info(chalk_1.default.yellow(`Downloading solc ${solcVersion}`)); }); (0, config_env_1.subtask)(task_names_1.TASK_COMPILE_SOLIDITY_LOG_RUN_COMPILER_START).setAction(async ({ compilationJob, }) => { const count = compilationJob.getResolvedFiles().length; if (count > 0) { console.info(chalk_1.default.yellow(`Compiling ${count} Solidity ${(0, utils_1.pluralize)(count, 'file')}`)); } }); (0, config_env_1.subtask)(task_names_1.TASK_COMPILE_SOLIDITY_EMIT_ARTIFACTS).setAction(async ({ compilationJob, input, output, solcBuild, }, { artifacts, run, network }, runSuper) => { if (network.zksync !== true) { return await runSuper({ compilationJob, input, output, solcBuild, }); } const version = compilationJob.getSolcConfig().eraVersion ? (0, utils_1.getZkVmNormalizedVersion)(compilationJob.getSolcConfig().version, compilationJob.getSolcConfig().eraVersion) : compilationJob.getSolcConfig().version; const pathToBuildInfo = await artifacts.saveBuildInfo(version, solcBuild.longVersion, input, output); const artifactsEmittedPerFile = await Promise.all(compilationJob .getResolvedFiles() .filter((f) => compilationJob.emitsArtifacts(f)) .map(async (file) => { const artifactsEmitted = await Promise.all(Object.entries(output.contracts?.[file.sourceName] ?? {}).map(async ([contractName, contractOutput]) => { logDebug(`Emitting artifact for contract '${contractName}'`); const artifact = await run(task_names_1.TASK_COMPILE_SOLIDITY_GET_ARTIFACT_FROM_COMPILATION_OUTPUT, { sourceName: file.sourceName, contractName, contractOutput, }); await artifacts.saveArtifactAndDebugFile(artifact, pathToBuildInfo); return artifact.contractName; })); return { file, artifactsEmitted, }; })); return { artifactsEmittedPerFile }; }); (0, config_env_1.subtask)(task_names_1.TASK_COMPILE_SOLIDITY_GET_COMPILER_INPUT, async (taskArgs, hre, runSuper) => { const compilerInput = await runSuper(taskArgs); if (hre.network.zksync !== true) { return compilerInput; } if (hre.config.zksolc.settings.suppressedErrors && hre.config.zksolc.settings.suppressedErrors.length > 0) { compilerInput.suppressedErrors = hre.config.zksolc.settings.suppressedErrors; } if (hre.config.zksolc.settings.suppressedWarnings && hre.config.zksolc.settings.suppressedWarnings.length > 0) { compilerInput.suppressedWarnings = hre.config.zksolc.settings.suppressedWarnings; } return compilerInput; }); (0, config_env_1.subtask)(task_names_1.TASK_COMPILE_REMOVE_OBSOLETE_ARTIFACTS, async (taskArgs, hre, runSuper) => { if (hre.network.zksync !== true || !hre.config.zksolc.settings.areLibrariesMissing) { return await runSuper(taskArgs); } // Delete all artifacts and cache files because there are missing libraries and the compilation output is invalid. const artifactsDir = hre.config.paths.artifacts; const cacheDir = hre.config.paths.cache; fs_1.default.rmSync(artifactsDir, { recursive: true }); fs_1.default.rmSync(cacheDir, { recursive: true }); }); //# sourceMappingURL=index.js.map