Verification & Etherscan

Difficulty: Advanced

Contract verification proves that deployed bytecode matches specific source code. When you deploy, only bytecode is stored on-chain. Verification uploads source code, compiler settings, and constructor arguments to Etherscan, which recompiles and confirms the match. This provides transparency, enabling anyone to read the logic, verify safety, and interact through Etherscan's UI.

The hardhat-verify plugin automates verification. After deployment, run the verify task with the address and constructor arguments. The plugin submits source code to Etherscan's API, waits for compilation, and confirms the match. For multi-file contracts, Hardhat handles import resolution automatically. Constructor arguments must exactly match deployment values.

Proxy contracts need special handling. Verify both the proxy and implementation separately, then link them on Etherscan. OpenZeppelin's hardhat-upgrades plugin handles this for deployProxy(). For manual proxies, use Etherscan's 'Is this a proxy?' feature to link proxy to implementation.

The ABI (Application Binary Interface) is the JSON description of a contract's functions, events, and errors. Verified contracts expose their ABI on Etherscan for frontends, scripts, and other contracts. ABIs are generated by the compiler and stored in Hardhat's artifacts directory.

Beyond Etherscan, verify on chain-specific explorers: Arbiscan (Arbitrum), BaseScan (Base), PolygonScan (Polygon). Each needs its own API key, configured in hardhat.config's etherscan section.

Code examples

Verification Commands and Configuration

// scripts/verify.ts
import { run, ethers } from "hardhat";

async function main() {
  // Simple contract
  await run("verify:verify", {
    address: "0x1234...abcd",
    constructorArguments: ["My Token", "MTK", ethers.parseEther("1000000")],
  });

  // Contract with naming conflict
  await run("verify:verify", {
    address: "0xabcd...1234",
    constructorArguments: ["0x1234...abcd", 500],
    contract: "contracts/vault/Vault.sol:Vault",
  });

  // Proxy implementation (no constructor args)
  await run("verify:verify", {
    address: "0xIMPL_ADDRESS",
    constructorArguments: [],
  });
}

main().catch(console.error);

// CLI:
// npx hardhat verify --network sepolia 0xADDR "arg1" "arg2"
// npx hardhat verify --network mainnet --constructor-args arguments.js 0xADDR

Verification scripts handle different contract types. For naming conflicts, specify the full contract path. Proxy implementations usually have no constructor args since they use initializers.

Multi-Chain Etherscan Configuration and ABI Export

// hardhat.config.ts
const config = {
  etherscan: {
    apiKey: {
      mainnet: process.env.ETHERSCAN_API_KEY!,
      sepolia: process.env.ETHERSCAN_API_KEY!,
      arbitrumOne: process.env.ARBISCAN_API_KEY!,
      optimisticEthereum: process.env.OPTIMISM_API_KEY!,
      polygon: process.env.POLYGONSCAN_API_KEY!,
      base: process.env.BASESCAN_API_KEY!,
    },
    customChains: [
      {
        network: "base",
        chainId: 8453,
        urls: {
          apiURL: "https://api.basescan.org/api",
          browserURL: "https://basescan.org",
        },
      },
    ],
  },
};

// scripts/export-abi.ts - Export clean ABIs for frontend
import * as fs from "fs";
import * as path from "path";

async function exportABIs() {
  const artifacts = path.join(__dirname, "..", "artifacts", "contracts");
  const output = path.join(__dirname, "..", "abi");
  fs.mkdirSync(output, { recursive: true });

  for (const name of ["Token", "Vault", "StakingRewards"]) {
    const artifact = JSON.parse(
      fs.readFileSync(path.join(artifacts, `${name}.sol`, `${name}.json`), "utf8")
    );
    fs.writeFileSync(
      path.join(output, `${name}.json`),
      JSON.stringify(artifact.abi, null, 2)
    );
    console.log(`Exported ${name} ABI (${artifact.abi.length} entries)`);
  }
}

exportABIs();

Configure verification for multiple chains with separate API keys. Custom chains need explicit URL configuration. The ABI export script extracts clean ABI files from Hardhat artifacts for frontend integration.

Key points

Concepts covered

Contract Verification, Etherscan, ABI, Proxy Verification, Block Explorer