UNPKG

hardhat

Version:

Hardhat is an extensible developer tool that helps smart contract developers increase productivity by reliably bringing together the tools they want.

155 lines (129 loc) 5.05 kB
import type { Artifact, ArtifactManager } from "../../../types/artifacts.js"; import type { BuildInfoAndOutput, Artifact as EdrArtifact, } from "@nomicfoundation/edr"; import { assertHardhatInvariant } from "@nomicfoundation/hardhat-errors"; import { readBinaryFile } from "@nomicfoundation/hardhat-utils/fs"; const BUILD_INFO_FORMAT = /^solc-(?<major>\d+)_(?<minor>\d+)_(?<patch>\d+)-[0-9a-fA-F]*$/; /** * This function returns all the build infos and associated outputs. * * @param artifactManager The artifact manager. * @returns The build infos in the Hardhat v3 format as expected by the EDR. */ export async function getBuildInfos( artifactManager: ArtifactManager, ): Promise<BuildInfoAndOutput[]> { const buildIds = await artifactManager.getAllBuildInfoIds(); return Promise.all( Array.from(buildIds).map(async (buildId) => { const buildInfoPath = await artifactManager.getBuildInfoPath(buildId); const buildInfoOutputPath = await artifactManager.getBuildInfoOutputPath(buildId); // This is only safe because of how we currently interact with getBuildInfos // i.e. we call it immediately after a build which should ensure both // the build info and build info output exist. If the usage pattern of this // function changes, these invariants might not hold anymore and should be // transformed into other errors instead. assertHardhatInvariant( buildInfoPath !== undefined, "buildInfoPath should not be undefined", ); assertHardhatInvariant( buildInfoOutputPath !== undefined, "buildInfoOutputPath should not be undefined", ); const buildInfo = await readBinaryFile(buildInfoPath); const output = await readBinaryFile(buildInfoOutputPath); return { buildInfo, output, }; }), ); } /** * This function returns the artifacts generated during the compilation. * * @param artifactManager The artifact manager. * @returns The artifacts in the format expected by the EDR. */ export async function getEdrArtifacts( artifactManager: ArtifactManager, ): Promise<Array<{ edrAtifact: EdrArtifact; userSourceName: string }>> { const fullyQualifiedNames = await artifactManager.getAllFullyQualifiedNames(); const artifacts = await Promise.all( Array.from(fullyQualifiedNames).map(async (fullyQualifiedName) => { return artifactManager.readArtifact(fullyQualifiedName); }), ); const buildInfoIds: string[] = Array.from( new Set( artifacts.map((artifact) => { assertHardhatInvariant( artifact.buildInfoId !== undefined, `buildInfoId should not be undefined for artifact: ${displayArtifactForError(artifact)}`, ); return artifact.buildInfoId; }), ), ); const solcVersionsArray: Array<[string, string]> = buildInfoIds .map((buildInfoId) => { const match = BUILD_INFO_FORMAT.exec(buildInfoId); // If the build info doesn't match this pattern it was probably generated // by something other than Hardhat and/or using a different compiler, so // we just ignore it. if (match === null) { return undefined; } assertHardhatInvariant( match.groups !== undefined, "The match must have groups", ); const solcShortVersion = `${match.groups.major}.${match.groups.minor}.${match.groups.patch}`; const result: [string, string] = [buildInfoId, solcShortVersion]; return result; }) .filter((solcVersionBuildInfoId) => solcVersionBuildInfoId !== undefined); const solcVersions = new Map(solcVersionsArray); return artifacts.map((artifact) => { assertHardhatInvariant( artifact.buildInfoId !== undefined, `buildInfoId should not be undefined for artifact: ${displayArtifactForError(artifact)}`, ); const solcVersion = solcVersions.get(artifact.buildInfoId); assertHardhatInvariant( solcVersion !== undefined, `solcVersion should not be undefined for artifact: ${displayArtifactForError(artifact)}`, ); const id = { name: artifact.contractName, solcVersion, source: artifact.inputSourceName ?? artifact.sourceName, }; const contract = { abi: JSON.stringify(artifact.abi), bytecode: artifact.bytecode, linkReferences: artifact.linkReferences, deployedBytecode: artifact.deployedBytecode, deployedLinkReferences: artifact.deployedLinkReferences, }; // TODO: This is a temporary solution. Ideally EDR would be aware that there // are both input and user source names, or we'd have a cheap way to match // from an artifact id between the `run` call and the events emitted by the // test runner. return { edrAtifact: { id, contract, }, userSourceName: artifact.sourceName, }; }); } function displayArtifactForError(artifact: Artifact): string { return `'${artifact.contractName}' in '${artifact.sourceName}'`; }