Works on: Virtual Environments and public networks (mainnets and testnets). The same plugin handles both; point it at the right network in
hardhat.config.ts.tenderly.verify() explicitly from your scripts.
On public networks, the plugin verifies publicly by default. To verify privately (visible only inside your project/organization), set
privateVerification: true in hardhat.config.ts. See Configure authentication and verification visibility.Versions and compatibility
Depending on the Ethers version youβre using with Hardhat, you need to download the corresponding version of the Tenderly-Hardhat plugin.| Your stack | Hardhat version | Tenderly-Hardhat plugin version |
|---|---|---|
| Ethers 6+ with Hardhat Ignition | >=2.19.0 <=2.22.0 | @tenderly/hardhat-tenderly@^2.3.0 |
| Ethers 6+ with hardhat-verify | >=2.19.0 <=2.22.0 | @tenderly/hardhat-tenderly@^2.2.1 |
| Ethers 5+ with hardhat-verify | < 2.19.0 | @tenderly/hardhat-tenderly@1.8.0 |
Verification methods
The Tenderly-Hardhat plugin supports three methods for contract verification.-
Automatic verification (recommended): Simply import and set up the plugin. This method is ideal for verification during deployment because the process is fully automated. Automatic verification works with plain hardhat deployment setup, as well as using hardhat-ignition. Control automatic verification by using the
TENDERLY_AUTOMATIC_VERIFICATIONenvironment variable. - Manual verification (low-code): Offers an explicit verification step within your code, which is useful for scenarios like post-deployment verification, conditional verification (e.g. only after a failing test), or verifying factory contractsβ instances.
- Verbose manual verification (high-code): Provides detailed control over the verification process, specifying library addresses, source codes, and compiler configurations. This is necessary for verifying multiple contracts with varying compiler versions or settings.
Examples
The best way to explore the automatic verification process is to go through an example that you can in our GitHub repo. All the examples use the sampleGreeter contract. Browse the example projects directly:
Tenderly-Hardhat plugin setup
Follow the steps below to install and initialize the Tenderly-Hardhat plugin.The plugin requires you to be logged into the Tenderly CLI.
Include the Tenderly-Hardhat package in your
hardhat.config.ts or hardhat.config.js file with a simple import
statement and call the setup method.Make sure to import
@tenderly/hardhat-tenderly after other packages, such as
@nomicfoundation/hardhat-toolbox, @nomiclabs/hardhat-ethers, @openzeppelin/hardhat-upgrades and similar.privateVerification parameter ensures your source code is kept visible only to your project collaborators
or organization.TENDERLY_PUBLIC_VERIFICATION.
const config: HardhatUserConfig = {
solidity: "0.8.19",
tenderly: {
username: "Your account slug" ?? "error",
project: "Your project slug",
// Contract visible only in Tenderly.
// Omitting or setting to `false` makes it visible to the whole world.
// Alternatively, configure verification visibility using
// an environment variable `TENDERLY_PUBLIC_VERIFICATION`.
privateVerification: process.env.TENDERLY_PUBLIC_VERIFICATION !== 'true',
},
};
export default config;
With the Tenderly-Hardhat plugin set up in your Hardhat project, you can verify contracts deployed to various
development and production networks:
To enable verification when working with hardhat-ignition, specify the
etherscan configuration. For apiUrl use
the verification URL: $TENDERLY_VIRTUAL_TESTNET_RPC/verify/etherscan.Automatic verification
Automatic verification occurs seamlessly when you deploy a contract using Ethers.js. The automatic verification approach will perform the verification automatically after collecting the compiler settings, the deployed contractβs address, and the source code. To enable or disable automatic verification, use theTENDERLY_AUTOMATIC_VERIFICATION environment variable recognized by the plugin.
The Tenderly-Hardhat plugin will verify contracts when it detects that the contract has been deployed, and Ethers has received the receipt of the deployment transaction.
To enable this, you need to await for deployment when you deploy contracts using Ethersβ helper methods ethers.deployContract() and ethers.getContractFactory(), by calling waitForDeployment() or deployed() on the contract instance, respectively.
Ethers 6
Modify the Hardhat script to capture the value returned from In more compact form:
waitForDeployment().deploy.ts
Ethers 5
The best way to explore how the automatic verification process works is to go through an example in our
GitHub repo.This example uses our sample In more compact form:
Greeter contract.Modify the Hardhat script to capture the value returned from deployed().deploy.ts
When running Hardhat scripts, you can set the
TENDERLY_AUTOMATIC_VERIFICATION environment variable to true to
enable automatic verification on a per-run basis.Run the script with the commands below. The link to the verified contract will be displayed in the Terminal output.
Hardhat Ignition (Virtual Environment)
Make sure to add
--deployment-id with a specific value when running the command. Hardhat (Virtual Environment)
Public network
When deploying to a public mainnet or testnet, specify whether you want public or private verification. Make sure your
hardhat.config.ts reads this env variable in the tenderly section.Verifying proxy contracts
Automatic verification of proxy contracts deployed and upgraded withhardhat-upgrades is possible with the following versions of @tenderly/hardhat-tenderly package:
- >= 1.10.0
- >= 2.1.0
1.x.x < 1.10.0 and 2.x.x < 2.1.0 follow the proxy verification guide.
Manual verification
Low-code verification throughtenderly.verify() allows you to be explicit about the exact point of verification within a deployment script or a Hardhat test.
This method is particularly beneficial for:
- Verifying previously deployed contracts through custom scripts.
- Verifying instances created by factory contracts.
- Enhancing test runs by selectively verifying contracts at the end of a failing suite (
after), which speeds up execution.
TENDERLY_AUTOMATIC_VERIFICATION to false when running scripts.
The verify function
The verify() function takes an object where you must provide the:
nameof the contractaddresswhere the contract is deployedlibraries(optional) used by the contract
Itβs necessary to invoke
verify() after the contract has been deployed.If youβre performing a verification alongside to deployment, you have to await for waitForDeployment() in
the case of Ethers 6, and deployed() in the case of Ethers 5.
- tdly.setup();
+ tdly.setup({automaticVerifications: false});
const config: HardhatUserConfig = {
This uses the same examples as in automatic verification, but this time with the
tenderly.verify() method to verify the contract.When running Hardhat scripts, you can set the
TENDERLY_AUTOMATIC_VERIFICATION environment variable to false to disable automatic verification.Verbose manual verification
The methodverifyMultiCompilerAPI() gives you full control over the verification process, allowing you to specify every detail of the verification process.
This is rarely recommended but can be useful if youβre verifying contracts compiled with different compiler versions or configurations.
The fully controlled verification method allows you to explicitly:
- Specify the source code of the contracts (
sources) - Set compilation arguments (
compiler) - Set linked libraries (
libraries)
Verification arguments
TheverifyMultiCompilerAPI() method takes one argument β an array of contract objects. Each contract object consists of the following:
contractToVerify | string | The name of the contract is to be verified. This can be a short name like Greeter or a fully qualified contract name like contracts/A/Greeter.sol:Greeter. |
sources | map | A map of all sources that are needed to compile the contract. The key of the map is a source path to the contract, whereas the value is an object containing the name and UTF-8-encoded contract source. js sources: { 'contracts/Greeter.sol': { name: 'Greeter', code: readFileSync('contracts/Greeter.sol', 'utf-8').toString(), }, 'hardhat/console.sol': { name: 'console', code: readFileSync('node_modules/hardhat/console.sol', 'utf-8').toString(), }, }, |
networks | map | A map containing all deployment addresses on multiple networks. js { networks: { [NETWORK_ID]: { address: greeterAddress, }, }, } |
libraries | map | A map containing information about deployments of libraries. The key is the relative path to the library source, relative to the contracts folder. js compiler.settings.libraries = { "path/to/lib.sol": { addresses: { "LibName1": "0x...", "LibName2": "0x..." } } } |