Store, retrieve, and manage deployment artifacts with comprehensive metadata tracking, deployment execution control, and artifact access.
Save and manage deployment artifacts with comprehensive metadata.
/**
* Save a deployment with metadata
* @param name - Deployment name
* @param deployment - Deployment data to save
* @returns Promise that resolves when saved
*/
save(name: string, deployment: DeploymentSubmission): Promise<void>;
/**
* Delete a saved deployment
* @param name - Deployment name to delete
* @returns Promise that resolves when deleted
*/
delete(name: string): Promise<void>;
interface DeploymentSubmission {
/** Contract ABI */
abi: ABI;
/** Deployed contract address */
address: Address;
/** Deployment transaction receipt */
receipt?: Receipt;
/** Deployment transaction hash */
transactionHash?: string;
/** Constructor arguments */
args?: any[];
/** Additional deployment metadata */
linkedData?: any;
/** Implementation address for proxies */
implementation?: string;
/** Diamond facets for diamond contracts */
facets?: Facet[];
/** Execution details for initialization */
execute?: {
methodName: string;
args: any[];
};
/** Linked library addresses */
libraries?: Libraries;
/** Contract metadata from compilation */
metadata?: string;
/** Contract creation bytecode */
bytecode?: string;
/** Contract runtime bytecode */
deployedBytecode?: string;
/** Deployment history for upgrades */
history?: Deployment[];
/** Solidity compiler input */
solcInput?: string;
/** Hash of solidity compiler input */
solcInputHash?: string;
/** Contract documentation */
userdoc?: any;
devdoc?: any;
/** Method identifiers mapping */
methodIdentifiers?: any;
/** Contract storage layout */
storageLayout?: any;
/** Gas usage estimates */
gasEstimates?: any;
/** Factory dependencies (zksync) */
factoryDeps?: string[];
}Usage Examples:
import { deployments } from "hardhat";
// Save custom deployment
await deployments.save("CustomContract", {
abi: contractAbi,
address: "0x1234567890123456789012345678901234567890",
args: ["constructor", "arguments"],
linkedData: { version: "1.0.0", deployer: "Alice" },
metadata: "contract metadata string",
libraries: {
MathLib: "0x9876543210987654321098765432109876543210",
},
});
// Save deployment with receipt
await deployments.save("TrackedContract", {
abi: abi,
address: contractAddress,
receipt: transactionReceipt,
transactionHash: txHash,
args: constructorArgs,
bytecode: compiledBytecode,
deployedBytecode: runtimeBytecode,
});
// Save proxy deployment
await deployments.save("ProxyContract", {
abi: mergedAbi,
address: proxyAddress,
implementation: implementationAddress,
execute: {
methodName: "initialize",
args: ["init", "params"],
},
history: [previousDeployment], // For upgrade tracking
});
// Delete deployment
await deployments.delete("OldContract");Access stored deployment information with error handling.
/**
* Get a deployment by name (throws if not found)
* @param name - Deployment name to retrieve
* @returns Promise resolving to deployment data
*/
get(name: string): Promise<Deployment>;
/**
* Get a deployment by name (returns null if not found)
* @param name - Deployment name to retrieve
* @returns Promise resolving to deployment data or null
*/
getOrNull(name: string): Promise<Deployment | null>;
/**
* Get all deployments for a specific address
* @param address - Contract address to find deployments for
* @returns Promise resolving to array of deployments
*/
getDeploymentsFromAddress(address: string): Promise<Deployment[]>;
/**
* Get all saved deployments
* @returns Promise resolving to mapping of deployment names to data
*/
all(): Promise<{ [name: string]: Deployment }>;
interface Deployment {
address: Address;
abi: ABI;
receipt?: Receipt;
transactionHash?: string;
args?: any[];
linkedData?: any;
implementation?: string;
facets?: Facet[];
libraries?: Libraries;
metadata?: string;
bytecode?: string;
deployedBytecode?: string;
history?: Deployment[];
numDeployments?: number;
solcInputHash?: string;
userdoc?: any;
devdoc?: any;
methodIdentifiers?: any;
storageLayout?: any;
gasEstimates?: any;
factoryDeps?: string[];
}Usage Examples:
// Get deployment (throws if not exists)
try {
const deployment = await deployments.get("MyContract");
console.log(`Contract at: ${deployment.address}`);
console.log(`ABI functions: ${deployment.abi.length}`);
} catch (error) {
console.log("Contract not deployed");
}
// Get deployment safely
const deployment = await deployments.getOrNull("OptionalContract");
if (deployment) {
console.log(`Found contract at: ${deployment.address}`);
} else {
console.log("Contract not found");
}
// Get all deployments
const allDeployments = await deployments.all();
for (const [name, deployment] of Object.entries(allDeployments)) {
console.log(`${name}: ${deployment.address}`);
}
// Find deployments by address
const deployments_at_address = await deployments.getDeploymentsFromAddress(
"0x1234567890123456789012345678901234567890"
);
console.log(`Found ${deployments_at_address.length} deployments at address`);
// Access deployment metadata
const contract = await deployments.get("DetailedContract");
if (contract.implementation) {
console.log(`Proxy implementation: ${contract.implementation}`);
}
if (contract.libraries) {
console.log(`Linked libraries:`, contract.libraries);
}
if (contract.history) {
console.log(`Upgrade history: ${contract.history.length} versions`);
}Run deployment scripts with tagging and dependency management.
/**
* Execute deployment scripts
* @param tags - Optional tags to filter deployment scripts
* @param options - Execution configuration options
* @returns Promise resolving to deployments that were executed
*/
run(
tags?: string | string[],
options?: {
/** Reset deployment memory before execution */
resetMemory?: boolean;
/** Delete existing deployment files */
deletePreviousDeployments?: boolean;
/** Write deployments to disk */
writeDeploymentsToFiles?: boolean;
/** Export deployments to file */
export?: string;
/** Export all network deployments to file */
exportAll?: string;
}
): Promise<{ [name: string]: Deployment }>;Usage Examples:
// Run all deployment scripts
const deployments_result = await deployments.run();
console.log(`Deployed ${Object.keys(deployments_result).length} contracts`);
// Run specific tagged deployments
await deployments.run(["Token", "DEX"]);
// Run with reset
await deployments.run(["Core"], {
resetMemory: true,
deletePreviousDeployments: true,
});
// Run with export
await deployments.run(["Production"], {
writeDeploymentsToFiles: true,
export: "./exports/mainnet-deployments.json",
});
// Run multiple tags
await deployments.run(["Infrastructure", "Business", "Frontend"]);
// Run with comprehensive options
const result = await deployments.run(["System"], {
resetMemory: false,
deletePreviousDeployments: false,
writeDeploymentsToFiles: true,
export: "./deployments-export.json",
exportAll: "./all-networks-export.json",
});
// Check what was deployed
for (const [name, deployment] of Object.entries(result)) {
console.log(`Deployed ${name} at ${deployment.address}`);
}Access contract compilation artifacts without deployment information.
/**
* Get hardhat compilation artifact
* @param name - Contract name to get artifact for
* @returns Promise resolving to compilation artifact
*/
getArtifact(name: string): Promise<Artifact>;
/**
* Get extended artifact with additional compilation information
* @param name - Contract name to get extended artifact for
* @returns Promise resolving to extended artifact
*/
getExtendedArtifact(name: string): Promise<ExtendedArtifact>;
interface Artifact {
contractName: string;
sourceName: string;
abi: ABI;
bytecode: string;
deployedBytecode: string;
linkReferences: LinkReferences;
deployedLinkReferences: LinkReferences;
}
interface ExtendedArtifact {
abi: ABI;
bytecode: string;
deployedBytecode?: string;
metadata?: string;
linkReferences?: LinkReferences;
deployedLinkReferences?: LinkReferences;
solcInput?: string;
solcInputHash?: string;
userdoc?: any;
devdoc?: any;
methodIdentifiers?: any;
storageLayout?: any;
evm?: any;
}Usage Examples:
// Get basic artifact
const artifact = await deployments.getArtifact("MyContract");
console.log(`Contract name: ${artifact.contractName}`);
console.log(`Source file: ${artifact.sourceName}`);
console.log(`ABI entries: ${artifact.abi.length}`);
// Get extended artifact with metadata
const extendedArtifact = await deployments.getExtendedArtifact("DetailedContract");
if (extendedArtifact.storageLayout) {
console.log("Storage layout available");
}
if (extendedArtifact.userdoc) {
console.log("User documentation available");
}
if (extendedArtifact.methodIdentifiers) {
console.log("Method identifiers:", extendedArtifact.methodIdentifiers);
}
// Use artifact for deployment
const contractArtifact = await deployments.getArtifact("CustomContract");
await deployments.deploy("CustomDeployment", {
from: deployer,
contract: contractArtifact,
args: ["arg1", "arg2"],
});
// Access compilation metadata
const artifact = await deployments.getExtendedArtifact("VerifiableContract");
if (artifact.solcInput && artifact.solcInputHash) {
console.log("Contract can be verified with solc input");
// Use for contract verification
}Task identifiers used by hardhat-deploy for defining and referencing deployment tasks.
/** Main deploy task identifier */
const TASK_DEPLOY = 'deploy';
/** Internal main deployment task */
const TASK_DEPLOY_MAIN = 'deploy:main';
/** Internal run deployment subtask */
const TASK_DEPLOY_RUN_DEPLOY = 'deploy:runDeploy';
/** Export deployment data task */
const TASK_EXPORT = 'export';
/** Etherscan verification task */
const TASK_ETHERSCAN_VERIFY = 'etherscan-verify';
/** Sourcify verification task */
const TASK_SOURCIFY = 'sourcify';Usage Examples:
import { TASK_DEPLOY, TASK_EXPORT } from "hardhat-deploy";
// Use in custom tasks
task("custom-deploy", "Custom deployment task")
.addFlag("verify", "Verify contracts after deployment")
.setAction(async (taskArgs, hre) => {
// Run main deployment task
await hre.run(TASK_DEPLOY, {
tags: "core",
export: "./deployments.json",
});
if (taskArgs.verify) {
await hre.run(TASK_ETHERSCAN_VERIFY);
}
});
// Reference in scripts
if (hre.hardhatArguments.task === TASK_DEPLOY) {
console.log("Running deployment task");
}Access deployment state information, logging, and helper utilities.
/**
* Log messages (only shown when logging is enabled)
* @param args - Arguments to log
*/
log(...args: any[]): void;
/**
* Get the current network name
* @returns Network name string
*/
getNetworkName(): string;
/**
* Get total gas used in current deployment session
* @returns Total gas used as number
*/
getGasUsed(): number;
/**
* Get network name from network object
* @param network - Hardhat network object
* @returns Network name string
*/
function getNetworkName(network: Network): string;
/**
* Traverse multiple directories and return all subdirectories
* @param dirs - Array of directory paths to traverse
* @returns Array of all subdirectory paths found
*/
function traverseMultipleDirectory(dirs: string[]): string[];
/**
* Filter ABI entries based on filter criteria
* @param abi - Contract ABI to filter
* @param filter - Filter criteria object
* @returns Filtered ABI array
*/
function filterABI(abi: ABI[], filter: any): ABI[];
/**
* Merge multiple ABIs into a single ABI
* @param abis - Array of ABIs to merge
* @param options - Merge options
* @returns Merged ABI array
*/
function mergeABIs(abis: ABI[][], options?: any): ABI[];Usage Examples:
// Network utilities
import { getNetworkName } from "hardhat-deploy";
const network = hre.network;
const name = getNetworkName(network);
console.log(`Current network: ${name}`);
// Directory traversal for deployment scripts
import { traverseMultipleDirectory } from "hardhat-deploy";
const deployPaths = ["./deploy", "./deploy-scripts", "./migrations"];
const allDirs = traverseMultipleDirectory(deployPaths);
console.log(`Found deployment directories: ${allDirs.length}`);
// ABI manipulation
import { filterABI, mergeABIs } from "hardhat-deploy";
// Filter ABI to only include specific function types
const fullABI = contractArtifact.abi;
const viewFunctions = filterABI(fullABI, { type: "function", stateMutability: "view" });
console.log(`Contract has ${viewFunctions.length} view functions`);
// Merge multiple contract ABIs
const tokenABI = await deployments.getArtifact("Token").then(a => a.abi);
const saleABI = await deployments.getArtifact("Sale").then(a => a.abi);
const mergedABI = mergeABIs([tokenABI, saleABI], {
deduplicate: true,
filter: { type: "function" }
});
console.log(`Merged ABI has ${mergedABI.length} entries`);Handle deployment errors and unknown signer scenarios.
/**
* Error thrown when a required signer is not available
*/
class UnknownSignerError extends Error {
/** Transaction that failed due to unknown signer */
txInfo: {
from: string;
to?: string;
value?: string;
data?: string;
};
constructor(message: string, txInfo: any);
}
/**
* Catch and handle unknown signer errors gracefully
* @param action - Promise or function that might throw UnknownSignerError
* @param options - Error handling options
* @returns Transaction info if error caught, null if successful
*/
catchUnknownSigner(
action: Promise<any> | (() => Promise<any>),
options?: { log?: boolean }
): Promise<null | {
from: string;
to?: string;
value?: string;
data?: string;
}>;Usage Examples:
// Handle unknown signer scenarios
try {
await deployments.execute("MyContract",
{ from: multisigAddress },
"updateSettings",
newValue
);
} catch (error) {
if (error instanceof UnknownSignerError) {
console.log("Multisig signer not available locally");
console.log("Transaction details:", error.txInfo);
}
}
// Use catchUnknownSigner wrapper
const result = await deployments.catchUnknownSigner(
deployments.execute("ProxyContract",
{ from: proxyOwner },
"upgrade",
newImplementation
),
{ log: true }
);
if (result) {
// Transaction details for manual execution
console.log("Manual transaction required:");
console.log(`From: ${result.from}`);
console.log(`To: ${result.to}`);
console.log(`Data: ${result.data}`);
} else {
console.log("Transaction executed successfully");
}
// Wrap deployment for multisig scenarios
const txInfo = await deployments.catchUnknownSigner(async () => {
return await deployments.deploy("NewContract", {
from: deployerMultisig,
args: ["constructor", "args"],
proxy: {
owner: upgradeMultisig,
proxyContract: "OpenZeppelinTransparentProxy",
},
});
});
if (txInfo) {
console.log("Deployment requires multisig execution");
// Save transaction details for later execution
}
// Logging during deployment
await deployments.log("Starting deployment phase 1");
await deployments.deploy("Contract1", { from: deployer });
await deployments.log("Contract1 deployed successfully");
// Get network information
const networkName = deployments.getNetworkName();
console.log(`Deploying on network: ${networkName}`);
// Track gas usage
const initialGas = deployments.getGasUsed();
await deployments.deploy("GasHeavyContract", { from: deployer });
const finalGas = deployments.getGasUsed();
console.log(`Deployment used ${finalGas - initialGas} gas`);
// Conditional behavior based on network
const network = deployments.getNetworkName();
if (network === "mainnet") {
deployments.log("Deploying to mainnet - using conservative gas settings");
} else {
deployments.log("Deploying to testnet - using aggressive gas settings");
}Manage deployment-related files and metadata.
/**
* Read a dot file from deployments directory
* @param name - File name to read (without .dot prefix)
* @returns Promise resolving to file contents
*/
readDotFile(name: string): Promise<string>;
/**
* Save content to a dot file in deployments directory
* @param name - File name to save (without .dot prefix)
* @param content - Content to save
* @returns Promise that resolves when saved
*/
saveDotFile(name: string, content: string): Promise<void>;
/**
* Delete a dot file from deployments directory
* @param name - File name to delete (without .dot prefix)
* @returns Promise that resolves when deleted
*/
deleteDotFile(name: string): Promise<void>;Usage Examples:
// Save deployment metadata
await deployments.saveDotFile("deployment-info", JSON.stringify({
timestamp: Date.now(),
deployer: "0x...",
network: "mainnet",
version: "1.0.0",
}));
// Read deployment metadata
try {
const info = await deployments.readDotFile("deployment-info");
const metadata = JSON.parse(info);
console.log(`Deployment from: ${new Date(metadata.timestamp)}`);
} catch (error) {
console.log("No deployment info found");
}
// Save configuration
await deployments.saveDotFile("config", JSON.stringify({
tokenName: "MyToken",
tokenSymbol: "MT",
initialSupply: "1000000",
}));
// Delete temporary files
await deployments.deleteDotFile("temp-data");
// Use for deployment state management
const deploymentState = {
phase: "initialization",
contracts: ["Token", "Sale", "Governance"],
completed: ["Token"],
pending: ["Sale", "Governance"],
};
await deployments.saveDotFile("state", JSON.stringify(deploymentState));
// Later, resume deployment
const stateContent = await deployments.readDotFile("state");
const state = JSON.parse(stateContent);
console.log(`Resuming deployment at phase: ${state.phase}`);interface DeploymentSubmission {
abi: ABI;
address: Address;
receipt?: Receipt;
transactionHash?: string;
args?: any[];
linkedData?: any;
implementation?: string;
facets?: Facet[];
execute?: {
methodName: string;
args: any[];
};
libraries?: Libraries;
metadata?: string;
bytecode?: string;
deployedBytecode?: string;
history?: Deployment[];
solcInput?: string;
solcInputHash?: string;
userdoc?: any;
devdoc?: any;
methodIdentifiers?: any;
storageLayout?: any;
gasEstimates?: any;
factoryDeps?: string[];
}
interface Deployment {
address: Address;
abi: ABI;
receipt?: Receipt;
transactionHash?: string;
args?: any[];
linkedData?: any;
implementation?: string;
facets?: Facet[];
libraries?: Libraries;
metadata?: string;
bytecode?: string;
deployedBytecode?: string;
history?: Deployment[];
numDeployments?: number;
solcInputHash?: string;
userdoc?: any;
devdoc?: any;
methodIdentifiers?: any;
storageLayout?: any;
gasEstimates?: any;
factoryDeps?: string[];
}
interface Facet {
facetAddress: string;
functionSelectors: string[];
}
type Libraries = { [libraryName: string]: Address };
type Address = string;
type ABI = any[];