Hardhat plugin for declarative smart contract deployments and redeployments.
- Declarative deployment configuration
- Deployment runtime accessibility (see hooks and deployment-output)
- If selected, deploys only modified contracts (code or constructor arguments)
- Selective contract verification
- Human-ridable deployment output
run npm install --save-dev @dgma/hardhat-sol-bundler
in addition, the next peer dependencies should be installed:
- "ethers": "^6.11.1",
- "hardhat": "^2.22.2"
- "@nomicfoundation/hardhat-ethers" // no need if you use @nomicfoundation/hardhat-toolbox
- Create deployment config in hardhat.config for the specific network:
import { type HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-ethers";
import { dynamicAddress } from "@dgma/hardhat-sol-bundler";
import { Logging } from "@dgma/hardhat-sol-bundler/plugins/Logging";
const config: HardhatUserConfig = {
networks: {
hardhat: {
deployment: {
plugins: [Logging], // will log the deployment result
config: {
TestLibrary: {},
TestContractOne: {
contractName: "TestContract",
args: ["hello one"],
options: {
libs: {
TestLibrary: dynamicAddress("TestLibrary"),
},
},
},
},
},
},
},
};
export default config;
contractName
property is optional and only needed if the configuration contract key is not the same as the contract name
note: the dependant contract must be located above
- Run task:
npx hardhat deploy-bundle
npx hardhat deploy-bundle --no-compile true
To keep deployment results and deploy only modified contracts, add the lockFile
property to deployment:
config.deployment = {
lockFile: "deployment-lock.json",
config: {
// contracts..
},
};
To deploy contracts as a proxy:
import { SupportedProxies } from "@dgma/hardhat-sol-bundler";
config.deployment = {
lockFile: "deployment-lock.json",
config: {
TestContract: {
proxy: {
type: SupportedProxies.CUSTOM,
},
},
},
};
Simple deployment result logging:
import { Logging } from "@dgma/hardhat-sol-bundler/plugins/Logging";
config.deployment = {
plugins: [Logging],
config: {
// contracts..
},
};
Verify deployed contracts:
// no need @nomicfoundation/hardhat-verify if you use @nomicfoundation/hardhat-toolbox
import "@nomicfoundation/hardhat-verify";
import { VerifyPlugin } from "@dgma/hardhat-sol-bundler/plugins/Verify";
config.deployment = {
plugins: [VerifyPlugin],
// set a config level verification
verify: true,
config: {
TestContract: {
// set a contract level verification. Overrides global verification
verify: true,
},
},
};
note verify plugin uses @nomicfoundation/hardhat-verify. Please make sure you have configured using config according to official plugin guidance.
The library can be easily extended with custom plugins by adding them to deployment.plugins
list. A simple example of the plugins can be found in plugins/*
.
During deployment, sol-bundler can execute additional logic implemented as lifecycle hooks:
BEFORE_CONTEXT_INITIALIZATION - fires once, before deployment runtime context creation;
BEFORE_DEPLOYMENT - fires once, after deployment runtime context creation and before deployment logic initiation;
BEFORE_DEPENDENCY_RESOLUTION - fires for each contract in the config, before resolving dynamically contract dependencies (arguments and libraries);
BEFORE_CONTRACT_BUILD - fires for each contract in the config, before creating contract factory;
AFTER_CONTRACT_BUILD - fires for each contract in the config, after creating contract factory;
BEFORE_CONTRACT_DEPLOY - fires for each contract in the config, before contract deployment;
AFTER_CONTRACT_DEPLOY - fires for each contract in the config, after contract deployment;
AFTER_CONTEXT_SERIALIZATION: "AFTER_CONTEXT_SERIALIZATION" - fires for each contract in the config, after deployment runtime context serialization (preparation for storing output into lock file);
AFTER_DEPLOYMENT - fires once, after all contracts deployment;
Deployment script can be easily attached to the other tasks or libraries:
import hre from "hardhat";
import { solBundler } from "@dgma/hardhat-sol-bundler";
const { ctx, deployedContracts } = await solBundler(hre);
// add custom logic
if (deployedContracts.includes("MyContract")) {
console.log("do something");
}
Contributions are always welcome! Open a PR or an issue!