This guide provides a complete procedure for initializing a new Hardhat v3 project, deploying a smart contract, and achieving an "Exact Match" verification on Routescan.
We will use the default files generated by the Hardhat wizard. It presents two methods for securely providing your private key and RPC URL:
Option A: Using terminal
exportcommands (temporary, for a single session).Option B: Using a
.envfile (persistent, stays in your project).
You only need to follow one of these options.
Project Initialization
First, we will create our project folder and initialize it with Hardhat.
Open your Terminal
Create a new project directory
mkdir my-hardhat-project
and navigate into itcd my-hardhat-project
Initialize a project.
npm init -y
Install Hardhat.
npm install --save-dev hardhat
Run the Hardhat wizard.
npx hardhat --init
Answer the wizard prompts exactly as follows.
Which version of Hardhat would you like to use?→hardhat-3Where would you like to initialize the project?→.(Press Enter)What type of project would you like to initialize?→node-test-runner-viemWould you like to change ".\package.json" to turn your project into ESM?→trueYou need to install the necessary dependencies... Do you want to run it now?→true
Configure hardhat.config.ts
This is the most important step. We will configure Hardhat to read your secret keys and set up the v3 verification method for Routescan.
Open the hardhat.config.ts file in your code editor and choose one of the two options below.
ℹ️ Custom Network Setup: This guide uses the Sepolia Testnet configuration as a reference. To deploy on your own ecosystem chain, you must replace the example values in hardhat.config.ts and .env with your specific network details:
Chain IDs
RPC URLs
Explorer URLs
Network Type (change accordingly to either
testnetormainnetinapiUrlrow)
Option A: Configure for Terminal Exports (process.env)
Choose this option if you plan to use export commands in your terminal.
Replace the entire contents of hardhat.config.ts with this code:
import hardhatToolboxViemPlugin from "@nomicfoundation/hardhat-toolbox-viem";
import { configVariable, defineConfig } from "hardhat/config";
import hardhatVerify from "@nomicfoundation/hardhat-verify";
export default defineConfig({
plugins: [
hardhatToolboxViemPlugin,
hardhatVerify,
],
solidity: {
profiles: {
default: {
version: "0.8.28",
},
production: {
version: "0.8.28",
settings: {
optimizer: {
enabled: true,
runs: 200,
},
},
},
},
},
networks: {
routescan: {
type: "http",
chainType: "l1",
url: configVariable("SEPOLIA_RPC_URL"),
accounts: [configVariable("SEPOLIA_PRIVATE_KEY")],
chainId: 11155111,
},
},
verify: {
etherscan: {
apiKey: "ANY_STRING_WORKS",
},
},
chainDescriptors: {
11155111: {
name: "Routescan Sepolia",
blockExplorers: {
etherscan: {
name: "Routescan",
url: "https://11155111.testnet.routescan.io/",
apiUrl: "https://api.routescan.io/v2/network/testnet/evm/11155111/etherscan",
},
},
},
},
});
Save the file.
Option B: Configure for a .env File (configVariable)
Install dotenv. To load the .env file, we first need to install the dotenv package. In your terminal, run the following command from your project's root folder.
npm install dotenv
Replace the entire contents of hardhat.config.ts with this code:
import { HardhatUserConfig } from "hardhat/config";
import hardhatToolboxViemPlugin from "@nomicfoundation/hardhat-toolbox-viem";
import { defineConfig } from "hardhat/config";
import hardhatVerify from "@nomicfoundation/hardhat-verify";
import "dotenv/config";
const SEPOLIA_RPC_URL = process.env.SEPOLIA_RPC_URL || "";
const SEPOLIA_PRIVATE_KEY = process.env.SEPOLIA_PRIVATE_KEY || "";
export default defineConfig({
plugins: [
hardhatToolboxViemPlugin,
hardhatVerify,
],
solidity: {
profiles: {
default: {
version: "0.8.28",
},
production: {
version: "0.8.28",
settings: {
optimizer: {
enabled: true,
runs: 200,
},
},
},
},
},
networks: {
routescan: {
type: "http",
chainType: "l1",
url: SEPOLIA_RPC_URL,
accounts: SEPOLIA_PRIVATE_KEY ? [SEPOLIA_PRIVATE_KEY] : [],
chainId: 11155111,
},
},
ignition: {
explorerUrl: "https://11155111.testnet.routescan.io/address/",
},
verify: {
etherscan: {
apiKey: "ANY_STRING_WORKS",
},
},
chainDescriptors: {
11155111: {
name: "Routescan Sepolia",
blockExplorers: {
etherscan: {
name: "Routescan",
url: "https://11155111.testnet.routescan.io/",
apiUrl: "https://api.routescan.io/v2/network/testnet/evm/11155111/etherscan",
},
},
},
},
});Save the file.
Set Your Environment Variables
You must now provide your secret keys using the method you just configured.
Option A: Set Terminal Exports
If you chose Option A in Step 2, run these commands in your terminal. They will only be valid for your current session.
export SEPOLIA_RPC_URL="YOUR_SEPOLIA_RPC_URL_HERE"
export SEPOLIA_PRIVATE_KEY="YOUR_WALLET_PRIVATE_KEY_HERE"
Option B: Create a .env File
If you chose Option B in Step 2, create a .env file in your project root.
Create the file in your terminal:
touch .env
(Or create it manually in your code editor).
Open the
.envfile and add your keys:SEPOLIA_RPC_URL="YOUR_SEPOLIA_RPC_URL_HERE" SEPOLIA_PRIVATE_KEY="YOUR_WALLET_PRIVATE_KEY_HERE"
Save the file. Hardhat will now automatically load these variables.
Deploy and Verify
Now that your configuration and keys are ready, these final steps are the same for both options.
Deploy the Contract
We will use the network name (
routescan_sepolia) from our config file and theCounter.tsmodule file that the Hardhat wizard created.
npx hardhat ignition deploy ./ignition/modules/Counter.ts --network routescan --verify
At this stage, we included the
--verifyflag to tell Hardhat to automatically attempt verification on Routescan immediately after the deployment finishes. This simplifies your workflow by handling both deployment and source code verification in one single command, rather than requiring you to run a separate manual verification step later.Confirm the Deployment
Terminal will ask you to confirm:
Confirm deploy to network routescan_sepolia (11155111)?Type
yesand pressEnter.
Copy the Contract Address
After a moment, the deployment will succeed. Copy the address from the output:
CounterModule#Counter - 0x...
If the automatic verification fails (often due to network latency where the explorer hasn't indexed the new block yet), you can always manually verify it later using below command.
To Verify the Contract
Use the address you just copied.
(Replace
<YOUR_DEPLOYED_ADDRESS>with the address you copied)
npx hardhat verify etherscan --network routescan --force <YOUR_DEPLOYED_ADDRESS>
After a successful run, the status on Routescan Contracts Tab will update to Contract Source Code Verified.
Submitted source code for verification on Routescan: contracts/Counter.sol:Counter Address: <YOUR_DEPLOYED_ADDRESS> Waiting for verification result... Contract verified successfully on Routescan! contracts/Counter.sol:Counter Explorer: https://11155111.testnet.routescan.io//address/<YOUR_DEPLOYED_ADDRESS>#cod
