Using HardHat with Quai Network

Introduction

This article shows how to deploy and interact with smart contracts using Hardhat on any of Quai Network's 13 chains.
Hardhat is an Ethereum development environment for professionals written in TypeScript. It is useful for performing frequent tasks such as running tests, automatically checking code for mistakes, or interacting with a smart contract.
Hardhat also supports combined Solidity and JavaScript stack traces, which allows for a streamlined deployment and debugging process.

Prerequisites

NodeJS

First, install the LTS version of nodejs. NodeJS bundles npm and npx.
Hardhat also supports yarn usage. To install yarn use:
npm install -g yarn

Quai Network and Solidity

It is useful to have basic knowledge of both Quai Network and Solidity.
Deployment of your smart contract on a Quai Network chain requires:
  • An active instance of a Quai Network full node.
  • An instance of the Quai Manager (if you are deploying locally).
  • Sufficient balance in the address that you are deploying with.

Initialize Hardhat

Hardhat is utilized through a local installation within individual project directories. Start by creating an npm project.
cd path/to/directory
npm init
Install Hardhat by running:
npm install --save-dev hardhat
Initialize the Hardhat development process using:
npx hardhat
After running this command, Hardhat will output a number of options below:
$ npx hardhat
888 888 888 888 888
888 888 888 888 888
888 888 888 888 888
8888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888
888 888 "88b 888P" d88" 888 888 "88b "88b 888
888 888 .d888888 888 888 888 888 888 .d888888 888
888 888 888 888 888 Y88b 888 888 888 888 888 Y88b.
888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888
Welcome to Hardhat v2.0.8
? What do you want to do? …
❯ Create a sample project
Create an advanced sample project
Create an advanced sample project that uses TypeScript
Create an empty hardhat.config.js
Quit
For this article, we will select the Create a basic sample project option. This will provide you with a preset basic Hardhat project structure with simple smart contracts, tests, and example scripts.
Note that selecting this option allows you to automatically install @nomiclabs/hardhat-waffle and @nomiclabs/hardhat-ethers. Both of these packages are useful during development and should be installed.

Project Configuration

Smart Contracts

The sample project setup option installs a sample contract named Greeter.sol which can be seen below.
Greeter.sol
//SPDX-License-Identifier: Unlicense
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 {
console.log("Changing greeting from '%s' to '%s'", greeting, _greeting);
greeting = _greeting;
}
}
The Greeter.sol contract allows the deployer to set a greeting string, deploy the contract, and later either change or return the set greeting. You can also add your own contracts.

Hardhat Config

Similar to Truffle, Hardhat uses hardhat.config.js as the configuration file. The config file allows you to define deployment networks, tasks, compilers, etc.
Paste the following code into your hardhat.config.js file to configure deployments to either the quaitestnet or a local instance of Quai ropsten.
hardhat.config.js
const privKey = "0x..."; // <-- add your private key(s) here
module.exports = {
defaultNetwork: "quaitestnet",
networks: {
quaitestnet: { // quaitestnet is the default quai network during the entire development phase.
url: "Node endpoint URL",
accounts: [privKey],
chainId: 9101, // chainId of the Cyprus1
websocket: true,
gas: 2001306 // gas limit used for deploys. This is an arbitrary value, accurate gas estimates must be obtained for deployments.
},
ropsten: { // ropsten is a locally ran testnet of all 13 of the quai network blockchains.
url: "http://127.0.0.1:8610/",
accounts: [privKey],
chainId: 12101, // chainId of the ropsten Cyprus1
websocket: true,
gas: 2001306 // gas limit used for deploys. This is an arbitrary value, accurate gas estimates must be obtained for deployments.
}
},
solidity: {
version: "0.8.14",
settings: {
optimizer: {
enabled: true,
runs: 200
}
}
},
paths: {
sources: "./contracts",
cache: "./cache",
artifacts: "./artifacts",
},
mocha: {
timeout: 20000,
},
};
The url and chainId variables should be set based on the chain you plan on deploying to. The corresponding port and chainId for each chain can be found at here.

Private Key Decryption

You must also provide hardhat.config.js with your privKey to fund contract deployment.
  • To decrypt your private key from the Keystore, create a new javascript file and copy the content below. Provide your keystore and provider_url.Run the script using node getPrivateKey.js.
  • It is recommended that you import your privKey variable from a separate, private file rather than placing it directly into hardhat.config.js for best account safety practices.
getPrivateKey.js
async function main() {
// keystore - Paste the keystore associated with the account below
var keystore = ''
// provider_url - URL to the node in which you want to deploy along with the right port associated
var provider_url = "" // For Ex: http://localhost:8610 for a local cyprus1 node
var Web3 = require("@quainetwork/web3");
var web3 = new Web3(provider_url);
const PRIVATE_KEY = web3.eth.accounts.decrypt(keystore, "").privateKey;
console.log("Private Key", PRIVATE_KEY);
}
main();

Deploying Your Contract

Compile with Hardhat

Smart contract compilation with Hardhat is simple and can be done using npx in the CLI. Support for older solc compilers can be found here.
$ npx hardhat compile
Compiling...
Compiled 1 contract successfully

Add Deployment Script

The Hardhat sample project has a premade deployment script named sample-script in the scripts directory.
sample-script.js
async function main() {
// We get the contract to deploy
const Greeter = await ethers.getContractFactory("Greeter");
const greeter = await Greeter.deploy("Hello, Hardhat!");
await greeter.deployed();
console.log("Greeter deployed to:", greeter.address);
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
Using sample-script.js, we can set the initial greeting and log out the contract address upon deployment. Scripts can be used to automate many different functions other than deployment.

Deploy Your Contract

To deploy Greeter.sol to the network of your choice, run:
$ npx hardhat run scripts/sample-script.js
Which should output:
Greeter deployed to: 0xFFbD605Ef5E637E056C0C2650D6FA05AAdB3652e

Interact with Smart Contract

Hardhat has a developer console to interact with contracts and the network. For more information about Hardhat's console see here. Hardhat console is a NodeJS-REPL, and you can use different tools in it. ethers is the library that we'll use to interact with our network.
You can access the console using:
$ npx hardhat console --network ropsten
Welcome to Node.js v16.2.0.
Type ".help" for more information.
>
Define the deployed contract:
> let Greeter = await hre.ethers.getContractFactory("Greeter")
undefined
Specify the contract address:
> const greeter = await Greeter.attach("0xFFbD605Ef5E637E056C0C2650D6FA05AAdB3652e")
undefined
Print the greeting set upon deployment:
> (await greeter.greet()).toString()
'Hello, Hardhat!'

Summary

Now you have all the tools you need to launch a local Quai Network, create a simple Hardhat project, deploy, and interact with your own smart contracts.
Join our Discord Server to learn more and ask any questions!