@matterlabs/hardhat-zksync-solc
Version:
Hardhat plugin to compile smart contracts for the ZKsync network
122 lines (101 loc) • 3.9 kB
text/typescript
import path from 'path';
import fsExtra from 'fs-extra';
import chalk from 'chalk';
import { spawnSync } from 'child_process';
import { download, getZkVmSolcUrl } from '../utils';
import {
DEFAULT_TIMEOUT_MILISECONDS,
ZKVM_SOLC_BIN_REPOSITORY,
COMPILER_BINARY_CORRUPTION_ERROR_ZKVM_SOLC,
USER_AGENT,
} from '../constants';
import { ZkSyncSolcPluginError } from '../errors';
/**
* This class is responsible for downloading the zkvm solc binary.
*/
export class ZkVmSolcCompilerDownloader {
public static async getDownloaderWithVersionValidated(
zkVmSolcVersion: string,
solcVersion: string,
compilersDir: string,
): Promise<ZkVmSolcCompilerDownloader> {
if (
!ZkVmSolcCompilerDownloader._instance ||
ZkVmSolcCompilerDownloader._instance.getZkVmSolcVersion() !== zkVmSolcVersion ||
ZkVmSolcCompilerDownloader._instance.getSolcVersion() !== solcVersion
) {
ZkVmSolcCompilerDownloader._instance = new ZkVmSolcCompilerDownloader(
solcVersion,
zkVmSolcVersion,
compilersDir,
);
}
return ZkVmSolcCompilerDownloader._instance;
}
private static _instance: ZkVmSolcCompilerDownloader;
private version: string;
/**
* Use `getDownloaderWithVersionValidated` to create an instance of this class.
*/
private constructor(
private _solcVersion: string,
private _zkVmSolcVersion: string,
private readonly _compilersDirectory: string,
) {
this.version = `${_solcVersion}-${_zkVmSolcVersion}`;
}
public getSolcVersion(): string {
return this._solcVersion;
}
public getZkVmSolcVersion(): string {
return this._zkVmSolcVersion;
}
public getVersion(): string {
return this.version;
}
public getCompilerPath(): string {
return path.join(this._compilersDirectory, 'zkvm-solc', `zkvm-solc-v${this.version}`);
}
public async isCompilerDownloaded(): Promise<boolean> {
const compilerPath = this.getCompilerPath();
return fsExtra.pathExists(compilerPath);
}
public async downloadCompiler(): Promise<void> {
try {
console.info(chalk.yellow(`Downloading zkvm-solc ${this.version}`));
await this._downloadCompiler();
console.info(chalk.green(`zkvm-solc version ${this.version} successfully downloaded`));
} catch (e: any) {
throw new ZkSyncSolcPluginError(e.message.split('\n')[0]);
}
await this._postProcessCompilerDownload();
await this._verifyCompiler();
}
private async _downloadCompiler(): Promise<string> {
const downloadPath = this.getCompilerPath();
const url = this._getCompilerUrl();
await this._attemptDownload(url, downloadPath);
return downloadPath;
}
private _getCompilerUrl(): string {
return getZkVmSolcUrl(ZKVM_SOLC_BIN_REPOSITORY, this.version);
}
private async _attemptDownload(url: string, downloadPath: string): Promise<void> {
return download(url, downloadPath, USER_AGENT, DEFAULT_TIMEOUT_MILISECONDS);
}
private async _postProcessCompilerDownload(): Promise<void> {
const compilerPath = this.getCompilerPath();
fsExtra.chmodSync(compilerPath, 0o755);
}
private async _verifyCompiler(): Promise<void> {
const compilerPath = this.getCompilerPath();
const versionOutput = spawnSync(compilerPath, ['--version']);
const version = versionOutput.stdout
?.toString()
.match(/\d+\.\d+\.\d+/)
?.toString();
if (versionOutput.status !== 0 || version === null) {
throw new ZkSyncSolcPluginError(COMPILER_BINARY_CORRUPTION_ERROR_ZKVM_SOLC(compilerPath));
}
}
}