Hardhat's artifact management system provides comprehensive functionality for reading, writing, and managing contract compilation artifacts with build information tracking and dependency resolution.
Central interface for artifact operations and management.
interface ArtifactManager {
/** Read a contract artifact by name or fully qualified name */
readArtifact<ContractNameT extends string>(
contractNameOrFullyQualifiedName: ContractNameT
): Promise<GetArtifactByName<ContractNameT>>;
/** Get the absolute path to an artifact */
getArtifactPath(contractNameOrFullyQualifiedName: string): Promise<string>;
/** Check if an artifact exists */
artifactExists(contractNameOrFullyQualifiedName: string): Promise<boolean>;
/** Get all fully qualified contract names */
getAllFullyQualifiedNames(): Promise<ReadonlySet<string>>;
/** Get build info ID for a contract */
getBuildInfoId(contractNameOrFullyQualifiedName: string): Promise<string | undefined>;
/** Get all build info IDs */
getAllBuildInfoIds(): Promise<ReadonlySet<string>>;
/** Get path to build info file */
getBuildInfoPath(buildInfoId: string): Promise<string | undefined>;
/** Get path to build info output */
getBuildInfoOutputPath(buildInfoId: string): Promise<string | undefined>;
/** Clear artifact manager cache */
clearCache(): Promise<void>;
}
type GetArtifactByName<ContractNameT extends string> =
ContractNameT extends keyof ArtifactMap ? ArtifactMap[ContractNameT] : Artifact;
interface ArtifactMap {}Usage Examples:
import { artifacts } from "hardhat";
// Read artifact by contract name
const tokenArtifact = await artifacts.readArtifact("MyToken");
console.log(`ABI: ${JSON.stringify(tokenArtifact.abi)}`);
// Read artifact by fully qualified name
const fqn = "contracts/tokens/MyToken.sol:MyToken";
const artifact = await artifacts.readArtifact(fqn);
// Check if artifact exists
if (await artifacts.artifactExists("MyContract")) {
const artifact = await artifacts.readArtifact("MyContract");
}
// Get all available contracts
const allContracts = await artifacts.getAllFullyQualifiedNames();
console.log(`Available contracts: ${allContracts.join(", ")}`);
// Get build information
const buildInfo = await artifacts.getBuildInfo(fqn);
if (buildInfo) {
console.log(`Solidity version: ${buildInfo.solcVersion}`);
}Complete artifact structure containing all contract compilation information.
interface Artifact<AbiT extends Abi = Abi> {
/** The version identifier of this format */
readonly _format: "hh3-artifact-1";
/** Contract name as defined in the source */
readonly contractName: string;
/** Source file path (relative to project root or npm module identifier) */
readonly sourceName: string;
/** Contract ABI (Application Binary Interface) */
readonly abi: AbiT;
/** Contract creation bytecode (0x-prefixed hex string) */
readonly bytecode: string;
/** Link references for libraries in creation bytecode */
readonly linkReferences: LinkReferences;
/** Contract runtime bytecode (0x-prefixed hex string) */
readonly deployedBytecode: string;
/** Link references for libraries in runtime bytecode */
readonly deployedLinkReferences: LinkReferences;
/** References to immutable variables in deployed bytecode */
readonly immutableReferences?: ImmutableReferences;
/** Build info ID that generated this artifact */
readonly buildInfoId?: string;
}
type Abi = readonly any[];
interface LinkReferences {
[sourceName: string]: {
[libraryName: string]: Array<{
start: number;
length: number;
}>;
};
}
interface ImmutableReferences {
[immutableId: string]: Array<{ start: number; length: number }>;
}Comprehensive build information including compiler settings and metadata.
interface BuildInfo {
/** Unique identifier for this build */
id: string;
/** Solidity compiler version used */
solcVersion: string;
/** Long version string of the compiler */
solcLongVersion: string;
/** Complete compiler input */
input: CompilerInput;
/** Complete compiler output */
output: CompilerOutput;
}
interface CompilerInput {
language: string;
sources: { [sourceName: string]: { content: string } };
settings: {
optimizer?: {
enabled: boolean;
runs?: number;
details?: any;
};
outputSelection: { [sourceName: string]: { [contractName: string]: string[] } };
evmVersion?: string;
metadata?: {
useLiteralContent?: boolean;
bytecodeHash?: string;
};
libraries?: { [sourceName: string]: { [libraryName: string]: string } };
remappings?: string[];
};
}
interface CompilerOutput {
contracts: {
[sourceName: string]: {
[contractName: string]: {
abi: any[];
evm: {
bytecode: {
object: string;
linkReferences: LinkReferences;
};
deployedBytecode: {
object: string;
linkReferences: LinkReferences;
};
};
metadata: string;
userdoc: any;
devdoc: any;
};
};
};
sources: {
[sourceName: string]: {
id: number;
ast: any;
};
};
errors?: Array<{
sourceLocation?: {
file: string;
start: number;
end: number;
};
type: string;
component: string;
severity: string;
message: string;
formattedMessage?: string;
}>;
}Debug file structure for enhanced debugging capabilities.
interface DebugFile {
/** Build info identifier */
buildInfo: string;
/** Path to the build info file */
buildInfoPath: string;
/** Source name this debug file corresponds to */
sourceName: string;
/** Contract name this debug file corresponds to */
contractName: string;
}Functions for resolving artifact file paths and names.
/**
* Get the fully qualified name for a contract
* @param sourceName - Source file name/path
* @param contractName - Contract name within the source
* @returns Fully qualified name in format "sourceName:contractName"
*/
function getFullyQualifiedName(
sourceName: string,
contractName: string
): string;
/**
* Check if a name is a fully qualified name
* @param name - Name to check
* @returns True if the name contains a colon separator
*/
function isFullyQualifiedName(name: string): boolean;
/**
* Parse a fully qualified name into components
* @param fullyQualifiedName - Fully qualified name to parse
* @returns Object with sourceName and contractName
*/
function parseFullyQualifiedName(fullyQualifiedName: string): {
sourceName: string;
contractName: string;
};
/**
* Parse a name that may or may not be fully qualified
* @param name - Name to parse
* @returns Object with optional sourceName and contractName
*/
function parseName(name: string): {
sourceName?: string;
contractName: string;
};Usage Examples:
import {
getFullyQualifiedName,
parseFullyQualifiedName,
isFullyQualifiedName
} from "hardhat/utils/contract-names";
// Create fully qualified name
const fqn = getFullyQualifiedName("contracts/MyToken.sol", "MyToken");
// Result: "contracts/MyToken.sol:MyToken"
// Check if name is fully qualified
if (isFullyQualifiedName("contracts/MyToken.sol:MyToken")) {
const { sourceName, contractName } = parseFullyQualifiedName(fqn);
console.log(`Source: ${sourceName}, Contract: ${contractName}`);
}
// Parse any name format
const { sourceName, contractName } = parseName("MyToken");
// sourceName will be undefined, contractName will be "MyToken"