> For the complete documentation index, see [llms.txt](https://thehemera.gitbook.io/explorer-api/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://thehemera.gitbook.io/explorer-api/verify-smart-contract/verify-smart-contract/verify-through-hardhat.md).

# Verify through Hardhat

This guide covers Hardhat 2.x for deploying and verifying smart contracts on SocialScan-supported chains (Monad, Pharos, etc.).&#x20;

Hardhat is a smart contracts development tool, perfect if you're familiar with Javascript/Typescript.

{% hint style="info" %}
SocialScan doesn't require an API key for contract verification.
{% endhint %}

### Quick Start

#### Option 1: Use This Example Project

Clone this repository:

```bash
git clone https://github.com/HemeraProtocol/hardhat-verify-example.git                                                                                     
cd hardhat-verify-example                                                                                                                            
npm install      
```

Copy `.env.example` to `.env` and add your settings:

```bash
cp .env.example .env
# Edit .env with your private key and RPC URLs
```

#### Option 2: Add to Your Existing Project

If you already have a Hardhat 2.x project, follow the installation and configuration steps below.

### Install

Via npm:

```bash
npm install --save-dev @nomicfoundation/hardhat-verify
npm install --save-dev @nomicfoundation/hardhat-ignition
npm install --save-dev dotenv
```

For upgradeable contracts (optional):

```bash
npm install --save-dev @openzeppelin/hardhat-upgrades
npm install @openzeppelin/contracts-upgradeable
```

### Config

In `hardhat.config.ts`, import the plugins:

```typescript
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-ethers";
import "@nomicfoundation/hardhat-verify";
import "@nomicfoundation/hardhat-ignition";
import "@openzeppelin/hardhat-upgrades";
import "dotenv/config";

const config: HardhatUserConfig = {
  solidity: {
    version: "0.8.28",
    settings: {
      optimizer: {
        enabled: true,
        runs: 200,
      },
    },
  },
  networks: {
    sepolia: {
      url: process.env.SEPOLIA_RPC_URL || "",
      accounts: process.env.SEPOLIA_PRIVATE_KEY && process.env.SEPOLIA_PRIVATE_KEY.length >= 64
        ? [process.env.SEPOLIA_PRIVATE_KEY]
        : [],
    },
    monadTestnet: {
      url: process.env.MONAD_TESTNET_RPC_URL || "https://testnet-rpc.monad.xyz",
      accounts: process.env.PRIVATE_KEY && process.env.PRIVATE_KEY.length >= 64
        ? [process.env.PRIVATE_KEY]
        : [],
      chainId: 10143,
    },
    pharosTestnet: {
      url: process.env.PHAROS_TESTNET_RPC_URL || "",
      accounts: process.env.PRIVATE_KEY && process.env.PRIVATE_KEY.length >= 64
        ? [process.env.PRIVATE_KEY]
        : [],
      chainId: 688689,
    },
  },
  etherscan: {
    apiKey: {
      monadTestnet: process.env.ETHERSCAN_API_KEY || "test",
      pharosTestnet: process.env.ETHERSCAN_API_KEY || "test",
    },
    customChains: [
      {
        network: "monadTestnet",
        chainId: 10143,
        urls: {
          apiURL: "https://api.socialscan.io/monad-testnet/v1/explorer/command_api/contract",
          browserURL: "https://monad-testnet.socialscan.io",
        },
      },
      {
        network: "pharosTestnet",
        chainId: 688689,
        urls: {
          apiURL: "https://api.socialscan.io/pharos-atlantic-testnet/v1/explorer/command_api/contract",
          browserURL: "https://pharos-testnet.socialscan.io",
        },
      },
    ],
  },
};


export default config;
```

Create `.env`:

```bash
PRIVATE_KEY=0xYourPrivateKey
MONAD_TESTNET_RPC_URL=https://testnet-rpc.monad.xyz/
PHAROS_TESTNET_RPC_URL=https://atlantic.dplabs-internal.com
```

### Deploy and Verify (using Hardhat Ignition)

Deploy to Monad Testnet:

```bash
# NOTE: Must change --deployment-id value before each deployment
# Use unique identifiers (deployment-1, deployment-2, deployment-3, etc.)
# This guarantees each deployment gets a unique address without conflicts
npx hardhat ignition deploy ignition/modules/Counter.ts --network monadTestnet --verify --deployment-id deployment-1
```

Deploy to Pharos Testnet:

<pre class="language-bash"><code class="lang-bash"># NOTE: Must change --deployment-id value before each deployment
# Use unique identifiers (deployment-1, deployment-2, deployment-3, etc.)
# This guarantees each deployment gets a unique address without conflicts
<strong>npx hardhat ignition deploy ignition/modules/Counter.ts --network pharosTestnet --verify --deployment-id deployment-1
</strong></code></pre>

### Verify an Existing Contract

```bash
npx hardhat verify --network monadTestnet 0x8A751D07341f7C22c4D131CF23eaA6fdD6e5D89f
```

With constructor arguments:

```bash
npx hardhat verify --network monadTestnet 0x8A751D07341f7C22c4D131CF23eaA6fdD6e5D89f 100
```

### Upgradeable Contracts (UUPS)

First, add the upgrades plugin to your config:

```typescript
import "@openzeppelin/hardhat-upgrades";
```

#### Deploy Proxy

Create `scripts/deploy-proxy.ts`:

```typescript
import { ethers, upgrades, run } from "hardhat";

async function main() {
  const BoxV1 = await ethers.getContractFactory("BoxV1");
  const proxy = await upgrades.deployProxy(BoxV1, [], {
    initializer: "initialize",
    kind: "uups",
  });

  await proxy.waitForDeployment();
  const proxyAddress = await proxy.getAddress();
  const implementationAddress = await upgrades.erc1967.getImplementationAddress(proxyAddress);

  console.log("Proxy:", proxyAddress);
  console.log("Implementation:", implementationAddress);

  // Verify implementation
  await new Promise(resolve => setTimeout(resolve, 30000)); // Wait for indexing

  await run("verify:verify", {
    address: implementationAddress,
    constructorArguments: [],
  });
}

main();
```

Deploy:

```bash
npx hardhat run scripts/deploy-proxy.ts --network monadTestnet
```

#### Upgrade Proxy

Create `scripts/upgrade-proxy.ts`:

```typescript
import { ethers, upgrades, run } from "hardhat";

async function main() {
  const proxyAddress = process.env.PROXY_ADDRESS;
  const BoxV2 = await ethers.getContractFactory("BoxV2");

  await upgrades.upgradeProxy(proxyAddress, BoxV2);

  const newImplAddress = await upgrades.erc1967.getImplementationAddress(proxyAddress);
  console.log("New Implementation:", newImplAddress);

  // Verify new implementation
  await new Promise(resolve => setTimeout(resolve, 30000));

  await run("verify:verify", {
    address: newImplAddress,
    constructorArguments: [],
  });
}

main();
```

Upgrade:

```bash
PROXY_ADDRESS=0xYourProxyAddress npx hardhat run scripts/upgrade-proxy.ts --network monadTestnet
```

### Proxy Verification Limitations

**Important:** The proxy contract itself (ERC1967Proxy from OpenZeppelin) cannot be automatically verified using the Hardhat verify plugin.

**What gets verified:**

* ✅ Implementation contracts (BoxV1, BoxV2, etc.) - Automatically verified
* ✅ All your business logic is visible to users

**What doesn't get verified:**

* ⚠️ The proxy contract (ERC1967Proxy)

**Why this happens:**

* The proxy contract is in `node_modules/@openzeppelin/contracts/`
* Hardhat verify plugin doesn't handle library contracts well
* This is a plugin limitation, not SocialScan-specific

**Why this is acceptable:**

* Users can see all source code via the verified implementation
* The proxy is a standard, audited OpenZeppelin contract
* Functionality is completely unaffected

### Live Examples

Monad Testnet:

* Simple contract: [0x8A751D07...](https://monad-testnet.socialscan.io/address/0x8A751D07341f7C22c4D131CF23eaA6fdD6e5D89f#code) ✅ Verified
* Proxy implementation: [0x846e12dD...](https://monad-testnet.socialscan.io/address/0x846e12dD4cc81BB8da9CF5cc6c1D8b03C3179973#code) ✅ Verified

Pharos Atlantic Testnet:

* Proxy: 0xE86E25D18F9C3f41Ef123f29aD29165a7F3c7F43
* Implementation V1: [0xf9018fB7...](https://pharos-testnet.socialscan.io/address/0xf9018fB711B2dd641DC55CFE2c60787c4C243F2D#code) ✅ Verified
* Implementation V2: [0x43503c53...](https://pharos-testnet.socialscan.io/address/0x43503c53501C0497E803235679F1ed34F0d43771#code) ✅ Verified
