Skip to content

Building with Hardhat on Moonbeam

Hardhat Create Project

Introduction

Hardhat is an Ethereum development environment that helps developers manage and automate the recurring tasks inherent to building smart contracts and DApps. Hardhat can directly interact with Moonbeam's Ethereum API so it can also be used to deploy smart contracts into Moonbeam

This guide will cover how to use Hardhat to compile, deploy, and debug Ethereum smart contracts on the Moonbase Alpha TestNet.

Checking Prerequisites

As always, check that Node.js has been installed on your machine (we'll go for v15.x) and npm. You can do this by running in your terminal:

curl -sL https://deb.nodesource.com/setup_15.x | sudo -E bash -

sudo apt install -y nodejs
#Install Homebrew https://docs.brew.sh/Installation). Run:

brew install node

We can verify that everything is installed correctly by querying the version for each package:

node -v
npm -v

As of writing of this guide, the versions used were 15.7.0 and 7.4.3, respectively.

Also, you will need the following:

Once all requirements have been met, you are ready to build with Hardhat.

Starting a Hardhat Project

To start a new project, create a directory for it:

mkdir hardhat && cd hardhat

Then, initialize the project by running:

npm init -y

You will notice a newly created package.json, which will continue to grow as you install project dependencies.

To get started with Hardhat, we will install it in our newly created project directory:

npm install hardhat

Once installed, run:

npx hardhat

This will create a Hardhat config file (hardhat.config.js) in our project directory.

Note

npx is used to run executables installed locally in your project. Although Hardhat can be installed globally, we recommend installing locally in each project so that you can control the version on a project by project basis.

After running the command, choose Create an empty hardhat.config.js:

Hardhat Create Project

The Contract File

We are going to store our contract in the contracts directory. Create it:

mkdir contracts && cd contracts

The smart contract that we'll deploy as an example will be called Box: it will let people store a value that can be later retrieved.

We will save this file as contracts/Box.sol:

// contracts/Box.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;

contract Box {
    uint256 private value;

    // Emitted when the stored value changes
    event ValueChanged(uint256 newValue);

    // Stores a new value in the contract
    function store(uint256 newValue) public {
        value = newValue;
        emit ValueChanged(newValue);
    }

    // Reads the last stored value
    function retrieve() public view returns (uint256) {
        return value;
    }
}

Hardhat Configuration File

Let's modify our Hardhat configuration file so we can compile and deploy this contract to Moonbase Alpha.

If you have not yet done so, create a MetaMask Account, connect to Moonbase Alpha, and fund it through Mission Control. We will use the private key of the account created to deploy the contract.

We start by requiring the ethers plugin, which brings the [ethers.js][/integrations/ethers/] library that allows you to interact with the blockchain in a simple way. We can install ethers plugin by running:

npm install @nomiclabs/hardhat-ethers ethers 

Next, we import the private key that we've retrieved from MetaMask and store it in a .json file.

Note

Please, always manage your private keys with a designated secret manager or similar service. Never save or commit your private keys inside your repositories.

Inside the module.exports, we need to provide the Solidity version (0.8.1 according to our contract file), and the network details:

  • Network name: moonbase
  • URL: https://rpc.testnet.moonbeam.network
  • ChainID: 1287

If you want to deploy to a local Moonbeam standalone node, you can use the following network details:

  • Network name: dev
  • URL: http://127.0.0.1:9933
  • ChainID: 1281

The Hardhat configuration file should look like this:

// ethers plugin required to interact with the contract
require('@nomiclabs/hardhat-ethers');

// private key from the pre-funded Moonbase Alpha testing account
const { privateKey } = require('./secrets.json');

module.exports = {
  // latest Solidity version
  solidity: "0.8.1",

  networks: {
    // Moonbase Alpha network specification
    moonbase: {
      url: `https://rpc.testnet.moonbeam.network`,
      chainId: 1287,
      accounts: [privateKey]   
    }
  }
};

Next, let's create a secrets.json, where we will be storing the private key mentioned before. The file must contain a privateKey entry, for example:

{
    "privateKey": "YOUR-PRIVATE-KEY-HERE"
}

Congratulations!πŸ‘πŸΌ We are ready for deployment!πŸš€πŸŒ–

Compiling Solidity

Our contract, Box.sol, uses Solidity 0.8.1. Make sure the Hardhat configuration file is correctly set up with this solidity version. If so, we can compile the contract by running:

npx hardhat compile

Hardhat Contract Compile

After compilation, an artifacts directory is created: it holds the bytecode and metadata of the contract, which are .json files. It’s a good idea to add this directory to your .gitignore.

Deploying the contract

In order to deploy the Box smart contract, we will need to write a simple deployment script. First, let's create a new directory (scripts). Inside the newly created directory, add a new file deploy.js.

mkdir scripts && cd scripts
touch deploy.js

Next, we need to write our deployment script using ethers. Because we'll be running it with Hardhat, we don't need to import any libraries. The script is a simplified version of that used in this tutorial.

We start by creating a local instance of the contract with the getContractFactory() method. Next, let's use the deploy() method that exists within this instance to initiate the smart contract. Lastly, we wait for its deployment by using deployed(). Once deployed, we can fetch the address of the contract inside the box instantiation.

// scripts/deploy.js
async function main() {
  // We get the contract to deploy
  const Box = await ethers.getContractFactory("Box");
  console.log("Deploying Box...");

  // Instantiating a new Box smart contract
  const box = await Box.deploy();

  // Waiting for the deployment to resolve
  await box.deployed();
  console.log("Box deployed to:", box.address);
}

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

Using the run command, we can now deploy the Box contract to Moonbase Alpha:

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

Note

To deploy to a Moonbeam standalone node, replace moonbase for dev in the run command.

After a few seconds, the contract is deployed, and you should see the address in the terminal.

Hardhat Contract Deploy

Congratulations, your contract is live! Save the address, as we will use it to interact with this contract instance in the next step.

Interacting with the Contract

Let's use Hardhat to interact with our newly deployed contract in Moonbase Alpha. To do so, launch hardhat console by running:

npx hardhat console --network moonbase

Note

To deploy to a Moonbeam standalone node, replace moonbase for dev in the console command.

Then add the following lines of code, one line at a time. First, we create a local instance of the Box.solcontract once again. Don't worry about the undefined output you will get after each line is executed:

const Box = await ethers.getContractFactory("Box") 

Next, let's connect this instance to an existing one by passing in the address we obtained when deploying the contract:

const box = await Box.attach("0x425668350bD782D80D457d5F9bc7782A24B8c2ef")

After attaching to the contract, we are ready to interact with it. While the console is still in session, let's call the store method and store a simple value:

await box.store(5)

The transaction will be signed by your Moonbase account and broadcast to the network. The output should look similar to:

Transaction output

Notice your address labeled from, the address of the contract, and the data that is being passed. Now, let's retrieve the value by running:

(await box.retrieve()).toNumber() 
We should see 5 or the value you have stored initially.

Congratulations, you have completed the Hardhat tutorial! 🀯 πŸŽ‰

For more information on Hardhat, hardhat plugins, and other exciting functionality, please visit hardhat.org.

We Want to Hear From You

If you have any feedback regarding using Hardhat to deploy smart contracts on Moonbase Alpha or any other Moonbeam-related topic, feel free to reach out through our official development Discord channel.