Skip to content

How to Verify a Smart Contract on Etherscan with Hardhat

DodaTech Updated 2026-06-24 4 min read

In this tutorial, you'll learn about How to Verify a Smart Contract on Etherscan with Hardhat. We cover key concepts, practical examples, and best practices.

The Problem

You run npx hardhat verify and get The Etherscan API returned an error: Invalid API Key, Already Verified, or The constructor arguments could not be decoded. Without verification, your contract remains unverified on Etherscan — users cannot read the source or interact with it.

Quick Fix

Fix 1: Missing or Invalid API Key

WRONG — no API key configured:

npx hardhat verify --network sepolia DEPLOYED_ADDRESS "arg1" "arg2"
# Error: The Etherscan API returned an error:
# Invalid API Key

RIGHT — set the API key in config or environment:

export ETHERSCAN_API_KEY=YOUR_ETHERSCAN_API_KEY

Or in hardhat.config.js:

module.exports = {
    etherscan: {
        apiKey: {
            sepolia: process.env.ETHERSCAN_API_KEY,
        },
    },
};

Get the API key from etherscan.io/myapikey.

Fix 2: Wrong Network Name

WRONG — using the wrong network name in hardhat.config.js:

module.exports = {
    etherscan: {
        apiKey: {
            sepolia: "YOUR_KEY",   // custom name
        },
    },
    networks: {
        sepolia: { /* ... */ },
    },
};
npx hardhat verify --network sepolia DEPLOYED_ADDRESS
# Error: Network 'sepolia' is not a valid Etherscan network

RIGHT — use the correct Etherscan network name:

module.exports = {
    etherscan: {
        apiKey: {
            sepolia: "YOUR_KEY",  // 'sepolia' is correct
        },
    },
};

Common network names for Etherscan: mainnet, sepolia, goerli, polygon, polygonMumbai, bsc, bscTestnet.

Fix 3: Constructor Arguments Not Provided

WRONG — deploying with constructor args but not providing them for verification:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract Token {
    constructor(string memory name, string memory symbol) { }
}
npx hardhat verify --network sepolia DEPLOYED_ADDRESS
# Error: The constructor arguments could not be decoded

RIGHT — pass constructor arguments:

npx hardhat verify --network sepolia DEPLOYED_ADDRESS "MyToken" "MTK"
# Successfully verified contract on Etherscan

For complex arguments, use a file:

npx hardhat verify --network sepolia DEPLOYED_ADDRESS --constructor-args args.js

args.js:

module.exports = [
    "MyToken",
    "MTK",
    18,
    "0x...",
];

Fix 4: Source Code Already Verified

# Already Verified: the contract is already verified on Etherscan
# (no action needed — the source matches)

If you deployed a different version:

npx hardhat verify --network sepolia DEPLOYED_ADDRESS
# The Etherscan API returned an error: Contract source code already verified

RIGHT — check on Etherscan and deploy a new instance if needed:

# No need to re-verify. Users can interact with the verified contract.
# For a new version, deploy a new address and verify that.

Fix 5: Proxy Contract Verification

// For ERC-1967 transparent proxies:
npx hardhat verify --network sepolia PROXY_ADDRESS
// Bytecode does not match — proxy verification needs special handling

RIGHT — verify the implementation first, then the proxy:

npx hardhat verify --network sepolia IMPLEMENTATION_ADDRESS
npx hardhat verify --network sepolia PROXY_ADDRESS IMPLEMENTATION_ADDRESS "0x..."

Or use the @openzeppelin/hardhat-upgrades plugin:

// deployments file includes verification data

Fix 6: Multiple Solidity Versions

// hardhat.config.js has multiple compilers:
module.exports = {
    solidity: {
        compilers: [
            { version: "0.8.20" },
            { version: "0.7.6" },
        ],
    },
};

Verification works as long as the correct compiler version matches the deployed bytecode.

Use DodaTech's Verification Manager to verify contracts across multiple block explorers (Etherscan, Polygonscan, BscScan) with a single command.

Prevention

  • Store the ETHERSCAN_API_KEY in .env (never commit it).
  • Save constructor arguments when deploying.
  • Verify immediately after deployment while the deployment context is fresh.
  • Use hardhat-etherscan plugin v4+ for latest compatibility.
  • Test verification on a testnet before mainnet.

Common Mistakes with verify contract

  1. Misunderstanding that String is [Char] with poor performance for large text operations
  2. Using foldl instead of foldl' causing stack overflow on large lists
  3. Forgetting deriving (Show, Eq) on custom data types needed for debugging

These mistakes appear frequently in real-world HARDHAT code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### Why does verification say "Bytecode does not match"?

The deployed bytecode does not match the compiled bytecode from your source. This happens when the optimizer settings differ, the compiler version does not match, or you have metadata appended. Ensure solc settings in hardhat.config.js match exactly.

Can I verify a contract that imports other contracts?

Yes, Hardhat flattens the source code automatically during verification. Ensure all imported contracts are resolvable. For OpenZeppelin imports, use @openzeppelin/contracts paths that resolve correctly.

How do I verify on BlockScout or other explorers?

Use the --network flag with the custom explorer. In hardhat.config.js, add customChains for non-Etherscan explorers. Alternatively, use the BlockScout web interface: upload the flattened source file manually.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro