Create And Deploy Smart Contracts With Hardhat Ethereum

Tokenguard Team
October 10, 2022

6 Steps To Create And Deploy Smart Contracts With Hardhat Ethereum Development Environment

Ethereum represents a multi-functional open-source platform. With its help, developers may easily create smart contracts for their blockchain-based projects. Such contracts enable the automation of many activities and may serve as a cheap, secure, and efficient alternative to centralized entities. 

If you are new to blockchain and want to create your first smart contract, this guide is for you. We will show how to create a simple smart contract with the help of the Hardhat Ethereum ecosystem for developers.

What Do You Need To Know Before You Begin

You don’t have to be a PRO developer with years of experience to start. Yes, if you have zero coding experience with creating a smart contract it may seem a difficult task. Yet, it’s not as complicated if you have clear guidance at hand. With our step-by-step instructions, even a total newbie will be able to create and deploy a smart contract. 

Programming does not consist of pure coding. One should deploy many other elements of an ecosystem in order to be able to create a decent piece of code. Luckily, you don’t have to create it all from scratch. Developers rely on numerous libraries and environments with items available out of the box. 

When it comes to coding on Ethereum, Hardhat is a good option. This Ethereum development environment offers various tools, plugins, and helpful documentation. In this tutorial, we will use mostly this platform.

Let’s get started!

Step 1. Set up the environment for smart contract creation

Ethereum tools and libraries mostly utilize the programing language JavaScript. Hardhat is not an exception to this rule. Besides, you don’t need to write the whole code from scratch since there are many frameworks created to facilitate your life.

One of the most popular Javascript frameworks is Node.js which works best with Chrome’s V8 Javascript engine. Paste the following command into your command line interface in order to install Node.js.


sudo apt update
sudo apt install curl git
curl -fsSL | sudo -E bash -
sudo apt-get install -y nodejs


If you use macOS in your daily work, make sure that you have git installed on it first. If you don’t have it, check this guide from Atlassian

With macOS, it is possible to install Node.js in many different ways. For the sake of simplicity, we will rely on Node Version Manager. Paste the following commands to your CLI:

curl -o- | bash
nvm install 18
nvm use 18
nvm alias default 18
npm install npm --global # Upgrade npm to the latest version


This operating system fits end-users best and doesn’t offer much help to developers. Yet, if this is the OS of your choice, we recommend using Windows Subsystem for Linux (WSL).

First, follow this guide from Microsoft to install git on WSL.

Next, check one more guide on how to install Node.js.

Step 2. Create a new project

Once the environment is ready, you can install Hardhat in it. There are many ways to do that. The most simple approach is to use a Node.js package manager (npm). It also serves as an online repository where you may store and view your code.

If you have successfully completed the previous step, you must already have npm 7 at hand. You can use this version or higher for your future reference. Create a new folder via the CLI:

mkdir hardhat-tutorial
cd hardhat-tutorial

After that, initialize an npm project by typing npm init.

To install Hardhat use the following command: npm install –save-dev hardhat.

Next, enter the directory where you’ve installed Hardhat. Type this line: npx hardhat.

Finally, select Create an empty hardhat.config.js in the menu and click enter. 

Congrats, your first project on Hardhat is ready! Note that the file hardhat.config.js is what Hardhat looks for in the first place upon the launch. This file contains all your work and is usually accessible in the root of your project.

Step 3. Write and compile a smart contract

Now let’s create a simple smart contract operating with tokens. No worries, we won’t dive into the depths of Solidity programming so as not to complicate things further. Yet, there are some aspects of the code that you should be aware of.

The maximum token supply will be limited to 1 million items. All of them will be minted within a single address that deploys the contract. Also, the tokens will not be divisible. This means that you will be able to transfer 1, 2, or 10, but not 3.5 tokens at a time. Finally, for the sake of simplicity, these tokens will not comply with the ERC-20 standard.

//SPDX-License-Identifier: UNLICENSED
// Solidity files have to start with this pragma.
// It will be used by the Solidity compiler to validate its version.
pragma solidity ^0.8.9;

// This is the main building block for smart contracts.
contract Token {
    // Some string type variables to identify the token.
    string public name = "My Hardhat Token";
    string public symbol = "MHT";

    // The fixed amount of tokens, stored in an unsigned integer type variable.
    uint256 public totalSupply = 1000000;

    // An address type variable is used to store ethereum accounts.
    address public owner;

    // A mapping is a key/value map. Here we store each account's balance.
    mapping(address => uint256) balances;

    // The Transfer event helps off-chain applications understand
    // what happens within your contract.
    event Transfer(address indexed _from, address indexed _to, uint256 _value);

     * Contract initialization.
    constructor() {
        // The totalSupply is assigned to the transaction sender, which is the
        // account that is deploying the contract.
        balances[msg.sender] = totalSupply;
        owner = msg.sender;

     * A function to transfer tokens.
     * The `external` modifier makes a function *only* callable from *outside*
     * the contract.
    function transfer(address to, uint256 amount) external {
        // Check if the transaction sender has enough tokens.
        // If `require`'s first argument evaluates to `false` then the
        // transaction will revert.
        require(balances[msg.sender] >= amount, "Not enough tokens");

        // Transfer the amount.
        balances[msg.sender] -= amount;
        balances[to] += amount;

        // Notify off-chain applications of the transfer.
        emit Transfer(msg.sender, to, amount);

     * Read only function to retrieve the token balance of a given account.
     * The `view` modifier indicates that it doesn't modify the contract's
     * state, which allows us to call it without executing a transaction.
    function balanceOf(address account) external view returns (uint256) {
        return balances[account];

Once the code is ready, you will need to compile it by typing a simple command: npx hardhat compile. That’s it, the code is finished.

Step 4. Test contract

Testing the contract is an absolute ‘must’ to ensure its security. Make sure to prepare automated tests for your smart contract before its release so as to protect the funds of your customers. Hardhat comes with its own local Ethereum network created specifically for this purpose. It has built-in Hardhat functionality and doesn’t require any additional setup.

In our tests, we are going to use the Mocha framework as the test runner.

Also, we will rely on the library Ether.js. It will help us operate with the Ethereum contract that we created earlier.

First, create a new test directory inside the root of our project. Then, create a file there named Token.js. Move on with the following piece of code:

const { expect } = require("chai");
describe("Token contract", function () {
  it("Deployment should assign the total supply of tokens to the owner", async function () {
    const [owner] = await ethers.getSigners();
    const Token = await ethers.getContractFactory("Token");
    const hardhatToken = await Token.deploy();
    const ownerBalance = await hardhatToken.balanceOf(owner.address);
    expect(await hardhatToken.totalSupply()).to.equal(ownerBalance);

Launch the following command in the terminal: npx hardhat test. Here’s what you should get:

$ npx hardhat test
  Token contract
    ✓ Deployment should assign the total supply of tokens to the owner (654ms)
  1 passing (663ms)

This will mean that you have accomplished the test successfully. Now let’s take a closer look at each line of the code.

  1. const [owner] = await ethers.getSigners();

With ethers.js, a Signer is an Ethereum account that can send assets to other accounts and contracts. This line calls the list of accounts within the Hardhat Network. We will need only the first one of them. You can check additional documentation to learn more.

Next, ethers is a common variable used within the Ethereum network. For the sake of the code clarity, you may also add the following line at the beginning:

const { ethers } = require(“hardhat”);

  1. const Token = await ethers.getContractFactory(“Token”);

In ethers.js, ContractFactory represents an abstract object that helps to deploy smart contracts. Therefore, Token is a factory of instances of our contract.

  1. const hardhatToken = await Token.deploy();

This command serves to initiate the deployment. As a result, we get another object with Promise that refers to a Contract. This object comes with a method for each of the functions within your smart contract.

  1. const ownerBalance = await hardhatToken.balanceOf(owner.address);

Once the deployment is complete, we can call our contract methods on hardhatToken and get the balance of the account’s owner.

  1. expect(await hardhatToken.totalSupply()).to.equal(ownerBalance);

Here we call a smart contract function again with the help of the Contract instance. In return, we get the size of the total supply and make sure that it equals the ownerBalance.

Note that we rely on another JavaScript library Chai. In particular, we use the functions called “matchers” from the plugin @nomicfoundation/hardhat-chai-matchers. This plugin enriches Chai with various matchers that are handy in smart contract tests. 

Step 5. Debug with Hardhat Network

The Hardhat Network allows not only to write smart contracts. Also, it can help you debug your code. The process is just as simple as everything we’ve already discussed above.

There is another useful command console.log(). It helps to print logging messages and contract variables while running smart contracts. To make use of it, you will need to import it first:

pragma solidity ^0.8.9;
import "hardhat/console.sol";

contract Token {

Next, launch the transfer() function and add some console.log calls to it as you would do in JavaScript. Check the documentation to learn more about this function.

function transfer(address to, uint256 amount) external {
   require(balances[msg.sender] >= amount, "Not enough tokens");
        "Transferring from %s to %s %s tokens",
    balances[msg.sender] -= amount;
    balances[to] += amount;

    emit Transfer(msg.sender, to, amount);

Here’s the logging output you will get when you launch the tests:

$ npx hardhat test
  Token contract
    DeploymentShould set the right owner
      ✓ Should assign the total supply of tokens to the owner
Transferring from 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 to 0x70997970c51812dc3a010c7d01b50e0d17dc79c8 50 tokens
Transferring from 0x70997970c51812dc3a010c7d01b50e0d17dc79c8 to 0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc 50 tokens
     ✓ Should transfer tokens between accounts (373ms)Should fail if sender doesn’t have enough tokens
Transferring from 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 to 0x70997970c51812dc3a010c7d01b50e0d17dc79c8 50 tokens
Transferring from 0x70997970c51812dc3a010c7d01b50e0d17dc79c8 to 0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc 50 tokens
     ✓ Should update balances after transfers (187ms)
5 passing (2s)

Step 6. Deploy to a live network

Assume you have successfully completed the tests and debugged the code. Now your smart contract is ready to go live on the Ethereum network. If you want to launch it for testing purposes only, you don’t have to release it right on the mainnet. Ethereum provides its own subnetworks for the tests such as Goerli and Sepolia.

What’s more, you can get some dummy ethers there so as not to spend real money. We’ll be using the test network Goerli at this stage. Note that from the software perspective, there are no differences between deploying the code to the mainnet and to the testnet. Testnets offer the same functionality as the mainnet does. 

To deploy the code, create a new directory script within the root of your project. Next, create a file deploy.js in that directory. Open this file and paste the following:

async function main() {
  const [deployer] = await ethers.getSigners();
  console.log("Deploying contracts with the account:", deployer.address);
  console.log("Account balance:", (await deployer.getBalance()).toString());
  const Token = await ethers.getContractFactory("Token");
  const token = await Token.deploy();
  console.log("Token address:", token.address);
  .then(() => process.exit(0))
  .catch((error) => {

Use the –network parameter so as to tell Hardhat which network you need to launch the task:

npx hardhat run scripts/deploy.js --network <network-name>

In fact, using this parameter in our current configuration is crucial. Without it, the code will simply launch against an embedded instance of the Hardhat network. Still, it’s useful to run the test to make sure that the code works properly:

$ npx hardhat run scripts/deploy.js
Deploying contracts with the account: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
Account balance: 10000000000000000000000
Token address: 0x5FbDB2315678afecb367f032d93F642f64180aa3

How to deploy code to a remote network

Now let’s deploy the smart contract using the network parameter. This will help you to launch your code on any other remote network including the mainnet. In the example below, we will be deploying the Goerli network:

// Go to, sign up, create
// a new App in its dashboard, and replace "KEY" with its key

// Replace this private key with your Goerli account private key
// To export your private key from Metamask, open Metamask and
// go to Account Details > Export Private Key
// Beware: NEVER put real Ether into testing accounts

module.exports = {
  solidity: "0.8.9",
 networks: {

   goerli: {

     url: `${ALCHEMY_API_KEY}`,

     accounts: [GOERLI_PRIVATE_KEY]


As you may have noticed, the URL in the code above points to the Ethereum node Alchemy. Yet, you may use any other node.

For the Goerli network, you will also need to grab some dummy ethers before the deployment. There are many different faucets where you can obtain them. Below, you can find the link to those that work with Goerli in particular. Don’t forget to switch to the relevant network in Metamask before you do that.

Finish the deployment by running the following command. If you have done everything correctly you will see the address of the contract after that:

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

Closing thoughts

Congrats on submitting your first smart contract on Ethereum! As you may see, it is not as difficult as it may seem at the beginning. Of course, some prior knowledge of coding would be preferable. But it is not a disaster if you don’t have relevant experience.


Are smart contracts legal?

No, they are still not legal tender in any country. Although they have really made a splash a few years ago, their legalization is still questionable. Yet, they may be useful when it comes to the automation of payments.

How much does it cost to create a smart contract?

The price depends on the complexity of the contract. Developers charge $300-$500 for simple contracts similar to the one we created in this article. The price for those with the most complicated logic may reach $2,000 per contract.

What programming language is a smart contract written in?

Smart contracts on Ethereum are written in Solidity.

Do you have any questions?

Request a contact with our success specialist