Deploy and Verify smart contracts using Hardhat
Tags: hardhat, etherscan, openzeppelin, verify
Published: 2021-09-13 08:17:14

For this tutorial we are going to deploy 3 smart contracts: 
1. basic contract
2. erc20 contract
3. erc721 contract


## Setup project
### Install hardhat
```bash
npm init -y     
npm install hardhat   
```

### start hardhat project
1. Start project with `npx hardhat`. 
2. Choose 'Create a basic sample project' from options
3. Download dependencies asked for download, if you missed them, then download them by running `npm install @nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers ethers`


## Add contracts to deploy
Inside `contracts` directory put the the contracts you want to deploy.
I am putting 3 contracts as:

### 1. Basic contract  (contracts/Greeter.sol)
```sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "hardhat/console.sol";

contract Greeter {
    string private greeting;

    constructor(string memory _greeting) {
        console.log("Deploying a Greeter with greeting:", _greeting);
        greeting = _greeting;
    }

    function greet() public view returns (string memory) {
        return greeting;
    }

    function setGreeting(string memory _greeting) public {
        greeting = _greeting;
    }
}
```

### 2. erc20 contract (contracts/PopatToken.sol)
```sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract Popat is ERC20, ERC20Burnable, Ownable {
    constructor() ERC20("Popat", "PT") {}

    function mint(address to, uint256 amount) public onlyOwner {
        _mint(to, amount);
    }
}
```
As we are importing openzepplin files in our contract, hence we are going to install the [OpenZepplin](https://openzeppelin.com/contracts/) npm package in our project as:
```bash
npm install @openzeppelin/contracts
```

### 3. erc721 contract (contract/PikachuNFT.sol)
```sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract Pikachu is ERC721, ERC721Burnable, Ownable {
    using Counters for Counters.Counter;

    Counters.Counter private _tokenIdCounter;

    constructor() ERC721("Pikachu", "PK") {}

    function safeMint(address to) public onlyOwner {
        _safeMint(to, _tokenIdCounter.current());
        _tokenIdCounter.increment();
    }
}
```



## Modify hardhat configuration (`hardhat.confi.js`):
### 1. Configure solidity versions
Hardhat supports projects that use different, incompatible versions of solc. You can configure Hardhat to use compiler versions compatible with those files like this:
```js
module.exports = {
  solidity: {
    compilers: [
      {
        version: "0.8.4",
      },
      {
        version: "0.6.7",
      }
    ]
  }
}
```
This setup means that a file with a pragma solidity ^0.8.0, ^0.8.1, ..., ^0.8.4 will be compiled with solc 0.8.4 and a file with a pragma solidity ^0.6.0, ..., ^0.6.7 will be compiled with solc 0.6.7

### 2. Define network configuration
```js
module.exports = {
defaultNetwork: 'rinkeby',
  networks: {
    rinkeby: {
      url: // NETWORK_ENDPOINT_RINKEBY,
      accounts: // [ACCOUNT_0_PRIVATE_KEY, ACCOUNT_1_PRIVATE_KEY]
    }
    namedAccounts: {
      account0: 0,
      account1: 1
    }
  }
```
In each network you define, put node-endpoint-url through which you are going to connect with the network as the value of `url` field, the most popular endpoint provider is: https://infura.io/ 
Get the private keys of the accounts from which you want to deploy the contract and put them as array as value of `accounts` field
In `namedAccounts` field, you have to define name of account, which you will use while writing deploy code. Value of each account-name is the index-of-account's private-key inside `<network-name>.accounts: []` array


### 3. Define ethereum-api key
```js
module.exports = {
  solidity: {
  etherscan: {
    apiKey: // ETHERSCAN_API_KEY
  }
}
```

### 4. Import npm packages required in config file
```js
require("@nomiclabs/hardhat-waffle");
require('hardhat-deploy');
```

The final configuration file on is look like this:
```js
// hardhat.config.js
require("@nomiclabs/hardhat-waffle");
require('hardhat-deploy');
require('dotenv').config()

module.exports = {
  solidity: {
    compilers: [
      {
        version: "0.8.4"
      }
    ]
  },
  defaultNetwork: 'rinkeby',
  networks: {
    rinkeby: {
      url: process.env.NETWORK_ENDPOINT_RINKEBY,
      accounts: [process.env.ACCOUNT_0_PRIVATE_KEY, process.env.ACCOUNT_1_PRIVATE_KEY]
    }
  },
  namedAccounts: {
    account0: 0,
    account1: 1
  },
  etherscan: {
    apiKey: process.env.ETHERSCAN_API_KEY
  }
};
```

You have to install [dotenv](https://www.npmjs.com/package/dotenv) package to use environment variables as used in above file, else you can also put values directly if your repository is not public.


## Deploy Contracts

Install [hardhat-deploy](https://github.com/wighawag/hardhat-deploy) plugin as `npm install hardhat-deploy` and import it inside 'hardhat.config.js' file as: 
```js
require('hardhat-deploy')
```

Put all deploy scripts under 'deploy' folder so deploy-plugin can detect and execute them
### 1. Deploy script for Basic contract
```js
// deploy/0_greeter.js
module.exports = async ({getNamedAccounts, deployments}) => {
    const {deploy} = deployments;
    const {account0, account1} = await getNamedAccounts();

    await deploy('Greeter', {
      from: account0,
      args: ['Mahesh is Learning HardHat!'],
      log: true,
    });
  };
```

### 2. Deploy script for erc20 cotract
```js
// deploy/1_popatToken.js
module.exports = async({getNamedAccounts, deployments}) => {
    const { deploy } = deployments
    const { account0 } = await getNamedAccounts()
    await deploy('Popat', {
        from: account0,
        args: [],
        log: true
    })
}
```

### 3. Deploy script for erc721 contract
```js
// deploy/2_pikchuNFT.js
module.exports = async ({deployments, getNamedAccounts}) => {
    const {deploy} = deployments
    const {account0} = await getNamedAccounts()
    await deploy('Pikachu', {
        from: account0,
        args: [],
        log: true
    })
}
```

As you can see deploy scripts are same for all type of cotracts, the deploy scripts finds the contract by looking at the name of cotract defined inside `.sol` file. 
E.g. In Greeter.sol file we defined contract name as `contract Greeter {`, hence we are using that same contract name inside deploy script as `await deploy('Greeter', {`


Now, we are ready for the deployment and verification :+1: 

Deploy contracts
```
npx hardhat deploy    # deploy contracts to defaulNetwork
# OR
npx hardhat --network rinkeby deploy   # deploy contrats to a specific network
```

# Vefify Contracts
```
npx hardhat etherscan-verify
```

You can see the progress and contract-addresses in the console when you execute above deploy and vefication commands.

My simple tutorial ends here. Happy Coding ! :blush: