How to Verify a Smart Contract on Etherscan with Hardhat
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-etherscanplugin v4+ for latest compatibility. - Test verification on a testnet before mainnet.
Common Mistakes with verify contract
- Misunderstanding that
Stringis[Char]with poor performance for large text operations - Using
foldlinstead offoldl'causing stack overflow on large lists - 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
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro