How to Verify a Smart Contract on Etherscan
If you deployed a contract and you want anyone to trust it, learning how to verify a smart contract on Etherscan is non-negotiable. Verification publishes the source code alongside your deployed bytecode, lets Etherscan decode function calls and events on every tx page, and enables the Read Contract and Write Contract tabs that most users expect. Unverified contracts look suspicious, break wallet simulations, and lose about half their potential integrations out of the gate.
This guide covers the four verification paths you will actually use in 2026: the hardhat verify plugin, Foundry's forge verify-contract, manual upload through the Etherscan UI, and Sourcify as the multi-chain alternative. It walks through the same flow on Arbiscan, Basescan, Polygonscan, and Optimism Etherscan — which all share Etherscan's API — plus Blockscout's auto-verification pathway via Sourcify. Troubleshooting compiler version mismatches, constructor args, and library linking gets its own section at the end, because these three issues cause roughly 90% of verification failures.
Why verification matters
A verified contract publishes three things alongside the deployed bytecode: the Solidity or Vyper source, the exact compiler version and settings, and any constructor arguments. Etherscan recompiles the source with those settings and compares the resulting bytecode to what is onchain. If they match, the contract is marked verified and the source becomes publicly browsable.
The downstream effects matter more than the green checkmark. Verified contracts get:
Decoded input data on every transaction — users see "transfer(to, value)" instead of a raw 4-byte selector plus hex.
Decoded event logs — the Logs tab shows human-readable event names and parameters.
A Read Contract tab that lets anyone call view and pure functions directly from the browser.
A Write Contract tab that lets users call state-changing functions through their connected wallet without a custom frontend.
Source-level indexing by downstream tools: Tenderly, Etherscan's API, block explorers' internal search, and a long tail of wallets that show decoded decoded tx previews.
The cost of skipping verification is high. Users treat unverified contracts as suspicious by default, wallet simulations fall back to raw hex warnings, and integrations with aggregators and indexers often require verified source. If your contract is going to interact with real money — and in stablecoin ecosystems that means any contract touching Routes CLI or the Routes API — verify it on day one.
Method 1: Hardhat verify
Hardhat's verification plugin is the most used path. It reads your deployment artifacts, packages the source with the correct compiler settings, submits to Etherscan's API, and polls until verified. Install:
npm install --save-dev @nomicfoundation/hardhat-toolbox(includes the verify plugin)or standalone:
npm install --save-dev @nomicfoundation/hardhat-verify
Configure hardhat.config.ts with your API keys. As of early 2026 Etherscan consolidated its multi-chain API into a single v2 key that works across every explorer it operates, so you usually only need one entry:
export default { solidity: "0.8.24", etherscan: { apiKey: process.env.ETHERSCAN_API_KEY }, networks: { base: { url: process.env.BASE_RPC, accounts: [process.env.PK] }, arbitrum: { url: process.env.ARBITRUM_RPC, accounts: [process.env.PK] } }}Then, after deploy, run:
npx hardhat verify --network base 0xDEPLOYED_ADDRESS "constructorArg1" "constructorArg2"
Constructor arguments are passed positionally. For complex args (arrays, structs), use the --constructor-args flag with a module that exports the arg array. The Hardhat verify plugin docs have the full reference for every edge case.
Hardhat will recompile your contracts, generate the flattened source, submit it, and poll Etherscan until verification completes or fails. On success you get a URL; on failure you get a reason that usually maps to one of the issues covered in the troubleshooting section below.
Method 2: Foundry's forge verify-contract
Foundry's built-in verifier has caught up to Hardhat and is often faster because Foundry already keeps the compiler settings you used. The quickest flow is to verify at deploy time:
forge script script/Deploy.s.sol --rpc-url $BASE_RPC --broadcast --verify --etherscan-api-key $ETHERSCAN_API_KEY
The --verify flag tells forge script to verify every newly deployed contract immediately after broadcast. If you need to verify a contract that was deployed separately, use the standalone forge verify-contract command:
forge verify-contract 0xDEPLOYED_ADDRESS src/MyContract.sol:MyContract --chain base --etherscan-api-key $ETHERSCAN_API_KEY --constructor-args $(cast abi-encode "constructor(address,uint256)" 0xDEAD 100)
Two Foundry-specific quirks. First, --constructor-args expects an ABI-encoded hex blob, which is why cast abi-encode is the common pattern for generating it. Second, Foundry uses the compiler version pinned in foundry.toml, so if you changed versions between deploy and verify you will need to pass --compiler-version explicitly. The Foundry Book deployment chapter covers these flags in depth.
Foundry also supports Sourcify and Blockscout as verification backends via --verifier sourcify or --verifier blockscout. On chains where Etherscan has no footprint (several newer L2s and app chains), this is the fastest path.
Method 3: Manual upload through the Etherscan UI
Sometimes you need to verify a contract whose deployment you did not script — an old contract, a contract deployed from a remix session, or one a collaborator sent you. Etherscan's Contract tab has a "Verify and Publish" link that walks through it by hand.
You will be asked for:
Compiler type: Solidity single file, multi-part, Standard JSON input, or Vyper. Standard JSON is the most reliable because it captures every compiler setting.
Compiler version: must match exactly the version that produced the deployed bytecode, including the commit hash. "0.8.24" is ambiguous; "0.8.24+commit.e11b9ed9" is unambiguous.
Open Source License Type: dropdown — MIT, GPL, Apache, etc.
Source code: either pasted flat file, multiple files, or a JSON input.
Optimization settings: enabled/disabled and runs count. Must match deploy settings exactly.
EVM version: paris, shanghai, cancun, etc. Newer contracts tend to be shanghai or cancun; older ones may be paris or london. Wrong EVM version is a common failure mode.
Constructor arguments: ABI-encoded hex (no 0x prefix). Etherscan has a utility to generate this from a function signature and values.
Libraries: if any library was linked at deploy time, its address on this chain must be provided.
Standard JSON input is the recommended format because it captures compiler settings, remappings, and metadata hash in one artifact — the same artifact Hardhat and Foundry generate internally. If you have your project's build output, find the standard-input JSON (usually under artifacts/build-info/ for Hardhat or out/ for Foundry) and paste it directly.
Method 4: Sourcify as the multi-chain alternative
Sourcify is the open-source, decentralized verification service maintained by the Ethereum Foundation. It works differently from Etherscan: rather than recompiling your source, it compares the Solidity metadata hash embedded in the bytecode against a recompile of the submitted source. If the metadata hashes match, the contract is verified.
Sourcify has three advantages worth knowing. First, it supports every EVM chain at once — submit once, verify everywhere. Second, it is free with no API key and no rate limits. Third, Blockscout (the open-source explorer used by Optimism, Gnosis Chain, Celo, and many others) auto-verifies contracts that are already verified on Sourcify, so you get multi-explorer coverage from a single submission.
To verify via Sourcify, use the CLI or UI at sourcify.dev. With Foundry, add --verifier sourcify to your deploy or verify command. With Hardhat, install @nomicfoundation/hardhat-verify and add a Sourcify entry to your config.
The main caveat is that Sourcify's "perfect match" verification requires the metadata hash to be preserved in the deployed bytecode, which means your contract must have been compiled with metadata inclusion (the default). If the metadata was stripped (some toolchains strip it for size), you get a "partial match" rather than a perfect match, and some tools treat partial matches as lesser-verified.
Multi-chain: Arbiscan, Basescan, and beyond
Etherscan operates block explorers for most major EVM chains: Ethereum, Arbitrum (Arbiscan), Optimism, Base (Basescan), Polygon (Polygonscan), BNB Smart Chain (BscScan), and more. All share the same UI and API, and since the 2024 v2 consolidation, a single API key works across all of them.
For chains Etherscan does not operate — Celo, Gnosis, newer app chains — you typically have two options. Blockscout via Sourcify handles most of them, and it is the pattern most open-source L2s default to. For chains with custom explorers, consult each chain's docs; every one of the 15 chains Eco supports (Ethereum, Optimism, Base, Arbitrum, HyperEVM, Plasma, Polygon, Ronin, Unichain, Ink, Celo, Solana, Sonic, BSC, Worldchain) has a documented verification path, and for multi-chain deployments the cleanest pattern is Foundry + Sourcify + per-chain Etherscan fallback.
Solana is the outlier because it is not EVM. Program verification on Solana uses verified builds via the Solana Verify CLI and relies on reproducible docker builds rather than source submission. If your stack spans EVM and Solana — as is typical for stablecoin deployments that use both — expect the two halves of your verification workflow to look different.
Troubleshooting: the three failures that cover 90% of cases
Compiler version mismatch
The most common failure. Your deployed bytecode was compiled with one version; you submitted source compiled with another. Etherscan compares bytecode strictly — a change in patch version often produces different output.
The fix: find the exact version (including commit hash) used at deploy. Hardhat stores this in artifacts/build-info/*.json; Foundry stores it in out/*/metadata.json. Submit that exact version. If you changed versions between deploy and verification attempt, pin the old version for the verify step.
Constructor arguments encoding
The second most common failure. Etherscan needs the constructor args ABI-encoded; you submitted them in the wrong format or missed one. The quickest fix is to pull the args directly from the deployment transaction: on the tx page, the Input Data field contains the contract bytecode followed by the ABI-encoded constructor args. Everything after the last byte of the runtime bytecode is your constructor args hex.
The cast abi-encode command in Foundry is the cleanest way to generate these from a function signature; Hardhat's verify plugin handles it automatically if you pass args to the CLI. For the manual UI path, use Etherscan's "ABI-Encoded Constructor Arguments" helper.
Library linking
The third most common failure. If your contract uses a library and the library was deployed separately (rather than inlined at compile time), the deployed bytecode contains placeholder slots that were filled with the library address at deploy time. Verification needs to know which library address belongs to which slot.
Hardhat and Foundry both handle this if the libraries are declared in config. For manual verification, the Etherscan UI shows a Libraries section where you paste each library name and address. The library address must match the one actually used at deploy, per chain.
Other recurring issues
Three more worth knowing:
Wrong EVM version: if you compiled for
cancunbut deployed to a chain that is still onshanghai, the bytecode may differ. Check your chain's current hardfork and match it.Optimizer runs mismatch: 200 is the default, but many teams bump it to 10000 or 1000000. If deploy used one value and verify uses another, the bytecode differs.
Immutables: Solidity immutables are stored in bytecode at deploy time. Etherscan handles this during verification, but some older toolchains can produce bytecode that differs from a clean recompile by just the immutable slots. Modern Etherscan verification is tolerant of this, but if you see a failure on a contract with immutables, try Sourcify, which has a different matching algorithm.
Verification for stablecoin and cross-chain contracts
If you are deploying contracts that interact with stablecoins across chains — settlement contracts, swap contracts, liquidity routers, compliance modules — verification should be part of your deployment script, not an afterthought. Two specific patterns are worth calling out.
Consistent deployment across chains. If you deploy the same contract to Ethereum, Base, Arbitrum, Optimism, and the other chains Eco supports, verify all of them in the same pass. Foundry's script + --verify flow is built for this; Hardhat users often script it with hardhat-deploy. Leaving some chains unverified creates a suspicious asymmetry and breaks wallet integrations on the unverified ones.
Settlement contracts that users sign against. Any contract users approve or permit against (ERC-2612, Permit2, bridge inboxes) should be verified before the first public interaction. Users who are paying attention check the verified source before signing; users who are not paying attention are the ones being phished. For teams building integrations on top of Eco's orchestration layer, the published Routes CLI and Routes API contracts are verified on every chain they deploy to, which is how the integrations the cross-chain stablecoin swap infra landscape describes actually become usable.
Related articles
FAQ
Why should I verify my smart contract on Etherscan?
Verification publishes your source code alongside the deployed bytecode, which enables Etherscan to decode every transaction, render event logs in human-readable form, and expose Read Contract and Write Contract tabs. Users, wallets, and indexers treat unverified contracts as untrustworthy by default, so verification is effectively a prerequisite for any contract intended for public use.
What is the difference between Etherscan verification and Sourcify?
Etherscan verifies by recompiling your source and comparing bytecode directly. Sourcify verifies by comparing the Solidity metadata hash embedded in the bytecode against a recompile. Sourcify is decentralized, free, supports every EVM chain at once, and feeds into Blockscout's auto-verification. Etherscan has broader name recognition and more downstream integrations.
Can I verify a contract after it has been deployed for months?
Yes. There is no time limit on verification. The only constraint is that you need the exact source code and compiler settings used at deploy. If you lost them, you may be able to reconstruct them from git history or CI artifacts; if not, you are out of luck. This is the strongest argument for verifying at deploy time and saving your build artifacts.
What is the Etherscan API v2 key and do I need it?
In 2024 Etherscan consolidated its per-chain API keys into a single multi-chain v2 key that works across Etherscan, Arbiscan, Basescan, Polygonscan, BscScan, and its other explorers. You still need to specify the chain ID in each request, but you only manage one key. Hardhat and Foundry both support it natively; single-key config is the norm in 2026.
How do I verify a contract on a chain Etherscan does not operate?
Use Sourcify, which is chain-agnostic and free, or the chain's own explorer's verification flow. Blockscout, the open-source explorer behind many L2s, auto-verifies from Sourcify. For a deployment across many chains, the Foundry pattern of forge script --verify --verifier sourcify gets you broad coverage in one pass.
Why did my verification fail even though my source looks correct?
The top three causes are compiler version mismatch (patch version or commit hash differs), wrong constructor argument encoding, and missing library address links. Less common but worth checking: wrong EVM version (cancun vs shanghai), wrong optimizer runs count, and stripped metadata hashes. Start by comparing the exact build settings in your artifacts to what you submitted.
Do I need to verify every deployment of the same contract on different chains?
Yes. Each chain's explorer maintains its own verification index. A contract verified on Etherscan is not automatically verified on Basescan or Arbiscan. The good news is that since Etherscan's v2 API unified keys across chains, and Sourcify publishes across all EVM chains simultaneously, you can automate the full multi-chain verification in one deployment script.
