[ad_1]
Step by step guide to verify your smart contract on Etherscan using Hardhat
VVerifying your smart contract is an important step in ensuring the transparency and trust of blockchain-based applications. Making contract code publicly accessible and providing proof of implementation on the blockchain allows independent verification of contract functionality. This not only builds trust among users but also increases the visibility and credibility of contracts.
Additionally, having a verified contract can make it easier for potential users to find and can help increase the visibility and credibility of the contract.
In this article, we will explore the smart contract verification process programmatically Etherscan use Today. By the end of this guide, you will have a thorough understanding of how to use Hardhat to automate the contract verification process on Etherscan, thereby streamlining the smart contract deployment process.
Let’s dive into the details and learn how to verify smart contracts on Etherscan using Hardhat.
The process of programmatically verifying smart contracts on Etherscan can be accomplished using a Hardhat in two different ways.
- Write a custom verification script using Hardhat, which can be run at any time to verify contracts on Etherscan.
- Implement a professional approach to verify smart contracts automatically after they are deployed to a testnet or mainnet.
As previously discussed in Learn to Implement Smart Contracts more Professionally with Hardhat articles, managing smart contract scripts can present challenges for developers as projects grow in size and complexity. As a project scales, the complexity of managing smart contract scripts also increases, giving developers the headache of tracking changes and maintaining project integrity.
In order to fully understand and apply the second approach to automate the verification process, it is recommended that you first read the article above.
Project Configuration for Verification
- Create a new Hardhat Project
- Remove default contracts, scripts and test files provided by Hardhat. These files can be found in the contract/, scripts/, and test/ folders, they should be removed to avoid confusion and potential errors.
- Get API Key from Etherscan https://etherscan.io/.
- For
.env
files in the root location. - Add
.env
files inside.gitignore
submit. Make sure you have to follow this step because later we will add PRIVATE_KEY in this file. - Create an Etherscan API key variable in it
.env
file and add your key as value for this variable like thisETHERSCAN_API_KEY=DR9...
. - Install
dotenv
a package so we can load the env file variables in our script. Run command in terminalnpm i --save-dev dotenv --force
. - Import the dotenv package inside
hardhat.config.js
orhardhat.config.ts
file like thisrequire(“dotenv”).config()
(JavaScript) orimport “dotenv/config”
(TypeScript).
Add Sample Smart Contract for Verification
This smart contract will be used for verification purposes.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;contract SimpleStorage {
uint private storedData;
function set(uint x) public {
storedData = x;
}
function get() public view returns (uint) {
return storedData;
}
}
- Create a file named
SimpleStorage.sol
inside the contracts folder and add this to it. - Compile the smart contract by executing commands
npx hardhat compile
Write Custom Verification Scripts
In order to verify the functionality of this smart contract, it must first be deployed on a specific network. Utilizing the applied contract address, the smart contract can then be verified on Etherscan.
To do this Create a file called verify-simple-storage.js
or verify-simple-storage.js
inside the scripts folder and add this code in it;
Note: Please note that JavaScript and TypeScript code will be provided throughout this article. Please select the appropriate code sample based on the language used in your implementation.
// JavaScript
import { ethers, network, run } from "hardhat";async function verifyContract() {
const chainId = network.config.chainId;
const simepleStorageFactory = await ethers.getContractFactory(
"SimpleStorage"
);
const args = [];
console.log(`Deploying...`);
const simpleStorage = await simepleStorageFactory.deploy(args);
await simpleStorage.deployed();
console.log(`Deployed!`);
console.log(`Simple Storage Address: ${simpleStorage.address}`);
console.log(`Waiting for blocks confirmations...`);
await simpleStorage.deployTransaction.wait(6);
console.log(`Confirmed!`);
// * only verify on testnets or mainnets.
if (chainId != 31337 && process.env.ETHERSCAN_API_KEY) {
await verify(simpleStorage.address, args);
}
}
const verify = async (contractAddress, args) => {
console.log("Verifying contract...");
try {
await run("verify:verify", {
address: contractAddress,
constructorArguments: args,
});
} catch (e) {
if (e.message.toLowerCase().includes("already verified")) {
console.log("Already verified!");
} else {
console.log(e);
}
}
};
verifyContract()
.then(() => process.exit(0))
.catch((error) => {
console.log(error);
process.exit(1);
});
// TypeScript
import { ethers, network, run } from "hardhat";async function verifyContract(): Promise<void> {
const chainId = network.config.chainId!;
const simepleStorageFactory = await ethers.getContractFactory(
"SimpleStorage"
);
const args: any[] = [];
console.log(`Deploying...`);
const simpleStorage = await simepleStorageFactory.deploy(args);
await simpleStorage.deployed();
console.log(`Deployed!`);
console.log(`Simple Storage Address: ${simpleStorage.address}`);
console.log(`Waiting for blocks confirmations...`);
await simpleStorage.deployTransaction.wait(6);
console.log(`Confirmed!`);
// * only verify on testnets or mainnets.
if (chainId != 31337 && process.env.ETHERSCAN_API_KEY) {
await verify(simpleStorage.address, args);
}
}
const verify = async (contractAddress: string, args: any[]) => {
console.log("Verifying contract...");
try {
await run("verify:verify", {
address: contractAddress,
constructorArguments: args,
});
} catch (e: any) {
if (e.message.toLowerCase().includes("already verified")) {
console.log("Already verified!");
} else {
console.log(e);
}
}
};
verifyContract()
.then(() => process.exit(0))
.catch((error) => {
console.log(error);
process.exit(1);
});
Let me explain what happened; (I’ll explain JavaScript but the Concept is the same for both).
async function verifyContract() {}
As simple as we make a verifyContract
JavaScript function.
verifyContract()
.then(() => process.exit(0))
.catch((error) => {
console.log(error);
process.exit(1);
});
Calling it inside the script so that the code gets executed when we run the script.
const chainId = network.config.chainId;
Inside the function, we use network
object provided by Hardhat to get chainId
from the network. The obtained ChainId is then used to verify the smart contract exclusively on the testnet or mainnet.
const simepleStorageFactory = await ethers.getContractFactory(
"SimpleStorage"
);
By using getContractFactory
function from the ethers.js library, we can instantiate a factory object for our smart contract.
That
getContractFactory
a function in the Ethereum JavaScript library ethers.js is used to create a contract factory object for a specific contract. This factory object can then be used to apply new contracts to the Ethereum blockchain. Factory pick up ABI (Application Binary Interface) and bytecode contract as input. The ABI is the JSON representation of the contract interface, which describes the functions and events exposed by the contract. Bytecode is the compiled code of contracts that is applied to the blockchain. Once the factory is created, it can be used to deploy a new contract instance by callingdeploy
method and pass in the required constructor arguments.
const args = [];console.log(`Deploying...`);
const simpleStorage = await simepleStorageFactory.deploy(args);
await simpleStorage.deployed();
console.log(`Deployed!`);
console.log(`Simple Storage Address: ${simpleStorage.address}`);
Variable args
represents the argument list for the smart contract constructor. However, in this case, it is left blank as SimpleStorage
contracts do not require arguments to be passed during instantiation.
We use deploy
function of the contractFactory to deploy the smart contract, passing in the required arguments as specified. This results in an instantiation of simpleStorage
object, representing the applied smart contract.
console.log(`Waiting for blocks confirmations...`);
await simpleStorage.deployTransaction.wait(6);
console.log(`Confirmed!`);
We use wait
function of deployTransaction
sample smart contract to wait for confirmation 6 blocks. Waiting for block confirmation before smart contract verification ensures that the contract is correctly recorded on the blockchain and its byte code is available for verification.
// * only verify on testnets or mainnets.
if (chainId != 31337 && process.env.ETHERSCAN_API_KEY) {
await verify(simpleStorage.address, args);
}
This code section specifies that verify
functions may only be called under certain conditions: the network may not hardhat
or localhost
and the Etherscan API key must be in the environment file. After these conditions are met, then verify
the function is called, passing the contract address and the appropriate arguments.
Why can’t we do Verification for Hardhat network?
As Hardhat
is a local network, runs exclusively on the user’s machine, does not have a suitable public blockchain for Etherscan to use for smart contract verification.
solidity: "0.8.17",
networks: {
hardhat: {
chainId: 31337,
},
localhost: {
chainId: 31337,
},
},
etherscan: {
apiKey: process.env.ETHERSCAN_API_KEY,
},
At this step, it is important to ensure that the network objects in the hardhat configuration file contain Hardhat
and Localhost
network with chainId from 31337
and that’s a etherscan
object is also present.
If you are using the latest version of Hardhat which includes @nomicfoundation/hardhat-toolbox
plugins later verify
tasks are included by default. However, if this is not the case, you need to install it hardhat-etherscan
plugin and configure it in the Hardhat configuration file so that the verification process can be carried out. Read more here Migrating from hardhat-waffle.
await run("verify:verify", {
address: contractAddress,
constructorArguments: args,
});
We use run
the functions provided by Hardhat to execute verify
task, passing the appropriate contract address and the smart contract constructor arguments. This step completes the smart contract verification process on Etherscan.
As seen in the code, we call verify:verify
subtasks, which are part of a larger one verify
Duty. This subtask deals specifically with verifying smart contracts in Etherscan. It is important to note that verify
task contains various other subtasks that are not called in this particular example.
try {
await run("verify:verify", {
address: contractAddress,
constructorArguments: args,
});
} catch (e) {
if (e.message.toLowerCase().includes("already verified")) {
console.log("Already verified!");
} else {
console.log(e);
}
}
We have completed the execution of run
function in a try catch block to handle errors that may occur. If the smart contract has been verified an error will appear and using an error message we inform the user that the contract has been verified.
// JavaScript
npx hardhat run scripts/verify-simple-storage.js --network goerli// TypeScript
npx hardhat run scripts/verify-simple-storage.ts --network goerli
By executing the above command, we will be able to deploy the smart contract and further verify it on Etherscan after waiting for 6 block confirmations. This enables easy verification of smart contracts on the Ethereum blockchain.
// JavaScript
goerli: {
chainId: 5,
url: process.env.GOERLI_RPC_URL,
accounts: [process.env.PRIVATE_KEY],
saveDeployments: true,
},// TypeScript
goerli: {
chainId: 5,
url: process.env.GOERLI_RPC_URL,
accounts: [process.env.PRIVATE_KEY!],
saveDeployments: true,
},
It is important to note that before running the above command, the Goerli network must be added to the network object in the configuration file. Besides that, GOERLI_RPC_URL and PRIVATE_KEY environment variable must be defined in env to ensure proper implementation and verification in the Goerli network.
That GOERLI_RPC_URLrequired to connect to the Goerli network, can be obtained from platforms such as Alchemy. That PRIVATE_KEYused to sign transactions, can be retrieved from wallet services such as MetaMask.
Note: It’s important to remember that the private key must be kept secure, and never shared with anyone. Also, it is important to ensure that the env file containing the private key is added to the .gitignore file before entering any code into the version control system, to prevent the private key from being accidentally exposed to the public.
Smart Contract Automatic Verification
Using the scripting approach above, implementing and verifying smart contracts can be a straightforward process when working with a small number of contracts. However, as the number of contracts increases, this manual approach can become difficult and time consuming for developers. The iterative nature of executing deployment and verification orders for each individual contract can pose a significant challenge for large-scale projects. A more efficient and scalable approach is needed to effectively manage and deploy large numbers of smart contracts.
It is important to note that in order to fully understand this approach, a basic understanding of smart contract deployment is required hardhat-deploy plugins required. If you are not familiar with this method, it is recommended that you read first Learn to Implement Smart Contracts more Professionally with Hardhat article before proceeding.
The best practice is to create a separate file for the verification function. This allows functions to be imported easily and reused across multiple files, making the deployment and verification process more streamlined and efficient.
Make utils
folder in the project root location. Inside this folder, create a file called verify.js
or verify.ts
. Add the verification function above inside this file and export it.
// JavaScript
const { verify } = require("../utils/verify");// TypeScript
import verify from "../utils/verify";
Import the verification function in your deployment file.
// JavaScript
const args = [];
const simpleStorage = await deploy("SimpleStorage", {
from: deployer,
log: true,
args: args,
waitConfirmations: chainId == 31337 ? 1 : 6,
});// * only verify on testnets or mainnets.
if (chainId != 31337 && process.env.ETHERSCAN_API_KEY) {
await verify(simpleStorage.address, args);
}
// TypeScript
const args: any[] = [];
const simpleStorage: DeployResult = await deploy("SimpleStorage", {
from: deployer,
log: true,
args: args,
waitConfirmations: chainId == 31337 ? 1 : 6,
});// * only verify on testnets or mainnets.
if (chainId != 31337 && process.env.ETHERSCAN_API_KEY) {
await verify(simpleStorage.address, args);
}
Run the verify function, supplying the address of the contract being applied to and any constructor arguments used during the deployment process.
npx hardhat deploy --network goerli
With this approach, a single command can be used to deploy and verify all smart contracts located within deploy
folder. This simplified process eliminates the need to manually apply and verify each contract, resulting in a more efficient and manageable development process.
Conclusion
In conclusion, verifying smart contracts on the Ethereum blockchain is an important aspect of building trust and transparency in blockchain-based applications. By making contract code publicly accessible and providing proof of implementation on the blockchain, developers can increase the visibility, credibility, and discoverability of their contracts. Verifying smart contracts is not only a good practice for blockchain-based application development, but also a way to increase user trust and application adoption.
This comprehensive guide aims to provide assistance to developers of all skill levels and is intended to benefit a wide range of developers. Regardless of length, the information provided is intended to be easy to understand and actionable for all readers.
If you found this content useful, please consider applauding and leaving feedback for future improvements. Your suggestions and comments are greatly appreciated and will help make this article more valuable to you and other readers.
Make sure to follow me to receive updates on my upcoming articles and stay informed about new content.
Thank you
Ali Murtaza Memon
New to trading? Try crypto trading bots or copy trade on the best crypto exchanges
[ad_2]
Source link