How to verify contracts with Hardhat

Learn how to verify smart contracts deployed to ZKsync using Hardhat

This how-to guide explains how to verify a smart contract on ZKsync using Hardhat.

What you'll learn:

  • How to compile smart contracts.
  • How to verify contracts.
  • How to verify contracts with constructor arguments.
GitHub

Tools:

  • - hardhat-zksync-deploy
  • - hardhat-zksync-verify
hardhatcontract verificationhow-to
Last Updated: May 09, 2024

Contract source-code verification ensures that the code running on-chain matches your published code.

The verification process validates and authenticates contracts running on a blockchain network, and enhances transparency, security, and trust in your smart contracts.

This document shows you how to verify your contracts with the hardhat-zksync plugin.

Common use cases

  • Transparent contract deployment: using the plugin, developers can deploy their contracts on the ZKsync Era network with transparency so that users and other developers can independently verify the contract's source code, and ensure it behaves as expected.
  • Cross-chain interoperability: for contracts operating across multiple chains, verifying contracts on each network assures users of the contract's consistency across different networks.
  • Open source projects: for open-source projects, verifying contracts enhances trust and encourages more developers to contribute. It assures contributors that the deployed contracts match the source code.

Verifying contracts using hardhat-zksync

Project setup

  1. Scaffold a new project by running the command:
    npx zksync-cli create verify-greeter-contract --template hardhat_solidity
    

    This creates a new ZKsync Era project called verify-greeter-contract with a basic Greeter contract and all the ZKsync plugins and configurations.
  2. Proceed by moving into the project directory:
    cd verify-greeter-contract
    

Configuration of hardhat.config.ts

The provided hardhat.config.ts configuration already contains the verifyURL for the zkSyncSepoliaTestnet and zkSyncMainnet networks:

zkSyncSepoliaTestnet: {
  url: "https://sepolia.era.zksync.dev",
  ethNetwork: "sepolia",
  zksync: true,
  verifyURL: "https://explorer.sepolia.era.zksync.dev/contract_verification",
},
zkSyncMainnet: {
  url: "https://mainnet.era.zksync.io",
  ethNetwork: "mainnet",
  zksync: true,
  verifyURL: "https://zksync2-mainnet-explorer.zksync.io/contract_verification",
},
  • Feel free to assign an arbitrary ZKsync Era network name utilizing the defaultNetwork property.
  • The verifyURL attribute directs to the verification endpoint specific to the ZKsync network.
  • If you want to verify a smart contract in other supported block explorer you can set verifyURL to point to it's verification API URL. For example for L2scan on mainnet set verifyURL to https://zksync-era.l2scan.co/api/zksync_contract_verification.
  • If you intend to validate a smart contract on Ethereum within the same project, don't forget to include your Etherscan API key.

Greeter.sol contract compilation

The ZKsync CLI provides a Greeter.sol contract we will verify on ZKsync Era.

Compile the contract using this command:

npm hardhat compile

Deploy the Greeter.sol contract

The ZKsync CLI provides a deploy/deploy-greeter.ts script that we will use to deploy the Greeter contract.

To configure your private key, copy the .env.example file, rename the copy to .env, and add your wallet private key.

WALLET_PRIVATE_KEY=YourPrivateKeyHere....

Your private key will be used for paying the costs of deploying the smart contract.

Initiate contract deployment using this command:

npm hardhat deploy-zksync --script deploy-greeter.ts

Expect an output similar to this:

Running the deployment function for the Greeter contract
The deployment is estimated to cost 0.0265726735 ETH
constructor args:0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000094869207468657265210000000000000000000000000000000000000000000000
The Greeter contract got deployed at 0xE84774C41F096Ba5BafA1439cEE787D9dD1A6b72

Remember, you need the contract address to verify the contract on ZKsync Era.

Verify the contract

Run the following command to verify your contract on the specified network, replacing <contract address> with your deployed contract's address.

npm hardhat verify --network <network> <contract address>

For example, to verify our Greeter contract on the zkSyncTestnet network and our contract address is 0xE84774C41F096Ba5BafA1439cEE787D9dD1A6b72, use:

npm hardhat verify --network zkSyncTestnet 0xE84774C41F096Ba5BafA1439cEE787D9dD1A6b72 'Hi there!'

The verification task attempts to compare the compiled bytecode of all the contracts in your local environment with the deployed bytecode of the deployed contract you are seeking to verify. If there is no match, it reports an error.

Verify the contract with fully qualified name

Specify which contract from your local setup you want to verify using the --contract parameter and providing its fully qualified name.

npm hardhat verify --network <network> <contract address> --contract <fully qualified name>

A fully qualified name is, for example, path/sourceName:contractName.

For instance, if the source name is Greeter.sol, the contract name is Greeter, and the contract lives in the contracts/ directory, the fully qualified contract name is: contracts/Greeter.sol:Greeter.

Here's an example of command using the --contract flag:

npm hardhat verify --network zkSyncTestnet 0xE84774C41F096Ba5BafA1439cEE787D9dD1A6b72 'Hi there!' --contract contracts/Greeter.sol:Greeter

Verify the contract with constructor arguments

If your contract was deployed with specific constructor arguments, you need to specify them when running the verify task.

npm hardhat verify --network testnet <contract address> '<constructor argument>'

For example, if you're verifying the Greeter contract on the zkSyncTestnet network, your contract address is 0xE84774C41F096Ba5BafA1439cEE787D9dD1A6b72, and your constructor argument was 'Hi there!', use:

npm hardhat verify --network zkSyncTestnet 0xE84774C41F096Ba5BafA1439cEE787D9dD1A6b72 'Hi there!'

Handle complex lists of constructor arguments

If your contract's constructor includes a complex list of arguments, create a separate JavaScript module to export these arguments. Here's how you can achieve this:

Prepare the JavaScript module with arguments

Start by creating an arguments.js file. This file should export an array of arguments that matches the order and types of the arguments in your contract's constructor.

For example, if your contract constructor has two string values, an address, and an integer, your arguments.js might look like this:

module.exports = [
  "string argument 1", // string
  "string argument 2", // string
  "0x1234abc...", // address
  42, // integer
];
Make sure the order of arguments in this array matches the order of arguments in your contract's constructor.

Verify the contract with the constructor arguments file

Once you have your arguments.js file prepared, you can reference it when verifying your contract. The --constructor-args parameter allows you to specify a JavaScript module that exports your constructor arguments.

Execute the verify command, substituting <contract address> with your actual contract address:

npm hardhat verify --network zkSyncTestnet <contract address> --constructor-args arguments.js

For instance, if your contract address was 0xE84774C41F096Ba5BafA1439cEE787D9dD1A6b72, you'd use:

npm hardhat verify --network zkSyncTestnet 0xE84774C41F096Ba5BafA1439cEE787D9dD1A6b72 --constructor-args arguments.js

This command verifies the contract on the zkSyncTestnet network, using the specific contract address and the constructor arguments defined in the arguments.js file. By following this procedure, you can handle contract verification for constructors with complex argument types and arrangements.

Check verification status

Once you've submitted your contract for verification, you may want to check the status of your request. This can be especially useful in cases where verification may take a long time, or if you wish to verify the successful receipt of your request.

Use the verify-status command to check the status of your verification request. Replace <your verification id> with the verification ID you received when you submitted your contract for verification.

npm hardhat verify-status --verification-id <your verification id>

For instance, if your verification ID is 12345, run the following:

npm hardhat verify-status --verification-id 12345

This command returns the current status of your verification request.

Depending on the network load and complexity of your contract, the verification process may take some time to complete.

Verify smart contract programmatically

There may be cases where you need to verify your contracts programmatically, for instance, as part of your project's build or deployment scripts.

To achieve this, use Hardhat's task runner to call the verify:verify task directly from your code. For example:

const contractAddress = "<your contract address>";
const contractFullyQualifiedName = "<your contract fully qualified name>";
const constructorArguments = [
  /* your decoded constructor arguments */
];

const verificationId = await hre.run("verify:verify", {
  address: contractAddress,
  contract: contractFullyQualifiedName,
  constructorArguments: constructorArguments,
});

console.log(`Verification ID: ${verificationId}`);

In this script:

  • contractAddress is the address of the deployed contract you wish to verify.
  • contractFullyQualifiedName is the fully qualified name of your contract (including the path to your Solidity file and contract name, separated by a colon e.g., "contracts/Greeter.sol:Greeter").
  • constructorArguments is an array containing the arguments used to deploy your contract (e.g. "Hi There").

Once this script runs, it prints the verification ID. If the verification request is successful, you can use this ID to check the status of your verification request. If the request was not successful, the return value and printed ID is -1.

UI block explorer alternative

Contract verification in ZKsync Era ensures the integrity and trustworthiness of your contracts. The Smart Contract Verification in ZKsync Era Block Explorer is a manual UI process for doing the same, ideal for occasional use, while the hardhat-zksync-verify plugin facilitates an automated, flexible approach for developers.


Made with ❤️ by the ZKsync Community