How to Deploy Single and Multiple Smart Contracts using Hardhat.

How to Deploy Single and Multiple Smart Contracts using Hardhat.

In this article, I’ll show you how you can deploy a Smart Contract to any EVM chain using Hardhat.

This article assumes that you already know how to write Smart Contracts. For our example, we will deploy a Simple Storage Smart Contract and a message retrieval contract. This will aid in understanding how to interact with multiple contracts relying on each other.

This article requires that you have Hardhat installed.

  1. Create a Directory, cd into it and start a Hardhat project.

     mkdir SampleProject && cd SampleProject
    
     npm init hardhat -y
    
  2. Open the project in a Terminal, you will find a default TimeLock Contract. For our first scenario, we are deploying a single Smart Contract. Replace the TimeLock Smart Contract, with a Simple Storage Smart Contract:

     // SPDX-License-Identifier: GPL-3.0
     pragma solidity ^0.8.19;
    
     contract SimpleStorage {
         uint storedData;
    
         function set(uint x) public {
             storedData = x;
         }
    
         function get() public view returns (uint) {
             return storedData;
         }
     }
    

    It is a Simple Contract that stores a number and returns a number.

  3. Compile the Smart Contract to confirm that there are no errors. Run the following command:

     npm hardhat compile
    
  4. Given that the Smart Contract has successfully compiled, the next step is to write a script that will help us deploy the Smart Contract, and also to configure the network or networks where we want to deploy the Smart Contract. First the script.

     const hre = require("hardhat");
     async function main() {
         const Contract = await hre.ethers.getContractFactory("SimpleStorage");
         const contract = await Contract.deploy();
    
         await contract.deployed();
         console.log(`Contract deployed to ${contract.address}`);
     }
    
     main()
         .then(() => process.exit(0))
         .catch((error) => {
              console.error(error);
              process.exitCode = 1;
     });
    

    Hardhat library offers the ability to interact with the EthersJS Ethereum Libary, which allows developers to interact with the Ethereum blockchain in a simple way.

In this script, we are calling an instance of it, and making the methods available. You can see the various methods available here.

The Line hre.ethers.getContractFactory("SimpleStorage"); gives us access to the Smart Contract, and the hardhat wrapper is wrapped around the EthersJS ContractFactory Class

The ContractFactory is used to deploy a Contract to the blockchain. It gives access to the deploy() method. Once the contract is deployed, the console log statement prints the address to the console.

The error catch is implemented on the function, and it will throw any errors and fail to complete the process.

The next step is to specify the network where you want your Smart Contract to be deployed.

  1. To configure the networks or networks where we want the Smart Contract deployed, open the hardhat.config.js file, and you will find the module.export instance only contains the solidity version. We can add a network object to specify the list of networks where we want to deploy the Smart Contract.

    It is important to note the following:

  • You need the private keys of an EOA to deploy a Smart Contract and enough native token to pay for the transaction.

  • If you are deploying to a network other than localhost, you will need the service of a Node Provider, that will help you bundle your transaction into a Block. To use the services of a Node Provider, you have to sign up to use the services of the Node Provider, and get an API Key. Popular Node Providers are Alchemy and Infura.

  • You will also be required to parse your private keys to the Node Provider. To hide your keys, you can simply use the dotenv library.

For this next step, have a Private Key ready. In the hardhat.config.js file, add a new object called networks, in the first example, we will deploy to the Ganache Local Blockchain:

    module.exports = {
      solidity: "0.8.18",
      networks: {
        ganache: {
          url: "http://127.0.0.1:8545",
          chainId: 1337,
          accounts: [
                 "0x<your-private-key>",
          ],
        },
      },
    };

The networks typically contains the following object keys: network name, it’s url, your private private key which when pasting, you can precede with 0x. Go back to terminal, and deploy the Smart Contract, using the command:

    npx hardhat run scripts/deploy.js --network ganache

Your Smart Contract will successfully deploy to the local Ganache Blockchain.

To deploy to other networks, as mentioned earlier, you will need API Keys from a Node Provider. Just as the Ganache Network was specified (You do not need a Node Provider to interact with the Ganache Blockchain, as it is running on your Machine), you will specify the network information, and in the url, pass the Node Provider endpoint for interacting with the blockchain. For example to deploy to the Sepolia network:

    sepolia: {
          url: https://eth-sepolia.g.alchemy.com/v2/${ALCHEMY_KEY},
          accounts: [PRIVATE_KEY],
        },

Then run the command:

    npx hardhat run scripts/deploy.js --network sepolia
  1. To deploy multiple Smart Contracts, where one Smart Contract Address needs to be parsed as an argument to the next Smart Contract, you do not need multiple scripts. You can deploy the contract one before the other, and parse the address of an already deployed contract to another.

Given an example where you have 2 Smart Contracts: TokenContract.sol and StakingContract.sol, and you need to pass TokenContract address to StakingContract at deployment. Where StakingContract has the following constructor arguments:

     constructor(
       TokenContract _token,
       uint256 _tokenPerBlock,
       uint256 _startBlock
     )

Here is the Script to run the deployment:

    const hre = require("hardhat");

    async function main() {
        const TOKEN = await hre.ethers.getContractFactory("TokenContract");
        const token = await TOKEN.deploy(10000000);

        await token.deployed();
        console.log("Token deployed to:", token.address);

        const Contract = await hre.ethers.getContractFactory("StakingContract");
        const contract = await Contract.deploy(token.address, 10000, 1);

        await contract.deployed();
        console.log("Contract deployed to:", contract.address);
    }

    main()
         .then(() => process.exit(0))
         .catch((error) => {
            console.error(error);
            process.exit(1);
    });

You will observe that the code runs synchronously as a result, the success of the first request will return, and make the token.address of the first contract available for use in the second.

You can follow this guide, and implement deploying multiple Smart Contracts numbers over two.

In this article, I have walked you through how you can easily deploy a single contract, or multiple contracts to a local Ganache Blockchain for testing, or to a Testnet or Mainnet Blockchain using a Node Provider.