@tenderly/hardhat-tenderly

August 12, 2026 · View on GitHub

npm (tag)

@tenderly/hardhat-tenderly

Hardhat plugin for verifying contracts on Tenderly.

Verified contracts unlock the rest of the Tenderly platform: the Debugger, Simulator, and readable traces on Virtual Environments.

Full documentation: docs.tenderly.co/contract-verification/hardhat.

Installation

npm install --save-dev @tenderly/hardhat-tenderly

Add a single import to your hardhat.config.ts (or hardhat.config.js), after the other plugin imports (@nomicfoundation/hardhat-toolbox, @nomicfoundation/hardhat-ethers, @openzeppelin/hardhat-upgrades, and similar):

import "@nomicfoundation/hardhat-toolbox";
import "@tenderly/hardhat-tenderly";

That's the whole setup. Calling tdly.setup() is no longer needed (it's a no-op kept for backward compatibility since 2.4.0).

Tenderly CLI login

Verifying on public networks authenticates with your Tenderly access key. Install the Tenderly CLI and log in once:

tenderly login --authentication-method access-key --access-key {your_access_key} --force

You can generate an access key in the Tenderly Dashboard under Account Settings → Authorization.

Verifying on Virtual Environments needs no access key: the environment's RPC URL authenticates the request by itself.

Configuration

Add a tenderly field to your Hardhat config:

const config: HardhatUserConfig = {
  solidity: "0.8.23",
  networks: {
    // see "Verification targets" below
  },
  tenderly: {
    // The account slug (your username, or the organization slug if the
    // project belongs to an organization). Both are visible in the
    // project's dashboard URL: https://dashboard.tenderly.co/{username}/{project}
    username: process.env.TENDERLY_USERNAME ?? "",
    project: process.env.TENDERLY_PROJECT ?? "",

    // true  -> contracts are visible only inside your project
    // false or omitted -> contracts are verified publicly (default)
    privateVerification: process.env.TENDERLY_PRIVATE_VERIFICATION === "true",
  },
};

Environment variables the plugin reads:

VariableDefaultEffect
TENDERLY_AUTOMATIC_VERIFICATIONtrueVerify automatically after each deployment. Set to false to verify only through explicit tenderly.verify() calls or the tenderly:verify task.
TENDERLY_AUTOMATIC_POPULATE_HARDHAT_VERIFY_CONFIGfalseAuto-fill the @nomicfoundation/hardhat-verify etherscan configuration; needed for proxy verification.
TENDERLY_ENABLE_OUTDATED_VERSION_CHECKtrueSet to false to silence the new-version notice.

Note that TENDERLY_PRIVATE_VERIFICATION in the example above is plain dotenv wiring into privateVerification — the switch itself is the config field.

Verification targets

Virtual Environments

Point a Hardhat network at your Virtual Environment RPC URL:

networks: {
  my_tenderly_environment: {
    // The environment's Admin RPC URL, from the dashboard or the API
    url: "https://virtual.mainnet.eu.rpc.tenderly.co/{org}/{project}/{environment-slug}",
  },
},

Contracts deployed with --network my_tenderly_environment are verified against the environment through its own RPC verifier ({rpc-url}/verify). The URL authenticates the request, so no access key is involved, and source visibility follows the environment's Contract visibility setting.

Public networks (mainnets and testnets)

Point a network at any RPC for the chain, for example a Tenderly Node RPC gateway:

networks: {
  mainnet: {
    url: "https://mainnet.gateway.tenderly.co",
    accounts: [process.env.PRIVATE_KEY ?? ""],
    chainId: 1,
  },
},
  • Public verification (default): the contract's source becomes visible to everyone on Tenderly.
  • Private verification (privateVerification: true): the contract is verified only inside your project.

Verification approaches

The examples/contract-verification projects exercise every approach below.

With TENDERLY_AUTOMATIC_VERIFICATION on (the default), contracts verify right after deployment — precisely, when the deployment is awaited:

import { ethers } from "hardhat";

const greeter = await ethers.deployContract("Greeter", ["Hello, Hardhat!"]);
await greeter.waitForDeployment();

To turn it off for a run:

TENDERLY_AUTOMATIC_VERIFICATION=false npx hardhat run scripts/deploy.ts --network my_tenderly_environment

Manual

The plugin extends the Hardhat runtime with tenderly.verify() — the same method the automatic flow calls:

import { ethers, tenderly } from "hardhat";

let greeter = await ethers.deployContract("Greeter", ["Hello, Hardhat!"]);
greeter = await greeter.waitForDeployment();

await tenderly.verify({
  name: "Greeter",
  address: await greeter.getAddress(),
  // optional, for contracts with linked libraries:
  libraries: {
    LibraryName1: "0x...",
  },
});

verify takes variadic arguments, so several contracts can be verified in one call.

Task

npx hardhat tenderly:verify Greeter=0x... --network {network_name}

Run npx hardhat help tenderly:verify for the details.

Proxy contract verification

Proxies deployed and upgraded with @openzeppelin/hardhat-upgradesTransparentUpgradeableProxy, UUPSUpgradeableProxy, and BeaconProxy — are verified automatically on public networks, together with their implementation and related contracts.

Proxy verification delegates to @nomicfoundation/hardhat-verify under the hood, so set:

TENDERLY_AUTOMATIC_POPULATE_HARDHAT_VERIFY_CONFIG=true

and the plugin fills in the required etherscan configuration for you. See the proxy examples for complete deploy-and-upgrade scripts.

Troubleshooting

Re-run with --verbose and capture the log:

npx hardhat run scripts/{your_deploy_script.ts} --network {network_name} --verbose > tenderly.log 2>&1

Attach tenderly.log when contacting support@tenderly.co. The Hardhat verification docs cover the common failure modes.