A First Look at Ethers and Hardhat
Published:
This example uses Hardhat and Ethers to compile a smart contract written in Solidity and deploy that contract to an Ethereum test network with Alchemy.
Outline
- Introduction
- Create Project
- Deploy to Testnet
- Connect to MetaMask
- Create React App
- Deploy to Ropsten Testnet
- Discover Related Articles
All of this project’s code can be found in the First Look monorepo on my GitHub.
Introduction
ethers.js is a library that aims to be a complete and compact tool for interacting with the Ethereum Blockchain and its ecosystem. This example uses Hardhat, an Ethereum development environment, to compile a smart contract and deploy it to Ropsten, an Ethereum test network that allows for blockchain development testing.
The contract is written in Solidity, an object-oriented, high-level language for implementing smart contracts. After deploying the contract, we will generate a boilerplate React application with Vite and connect the application to our smart contract running on Ropsten. Alchemy provides a managed node that enables connecting to various tools in the blockchain ecosystem.
Create Project
This article is heavily based on Nader Dabit’s definitive article, The Complete Guide to Full Stack Ethereum Development. I’ve made a few alternations including using Vite instead of Create React App and the inclusion of dotenv
for environment variables but all credit due to Sensei Dabit.
Remove "type": "module"
from package.json
.
Install Dependencies
In addition to Ethers and Hardhat we will also install Waffle and Chai for testing our contracts.
Create a .env
file to store environment variables later in the tutorial.
The file will include the following three variables:
Initialize Hardhat Environment
Developing smart contracts requires the ability to deploy your contracts, run tests, and debug Solidity code. We will also need a way to compile Solidity code into code that can be run in a client-side application. Hardhat compiles your contracts and runs them on a development network. This lets you develop without having to deal with live environments.
We’ll create the following files/directories:
hardhat.config.js
- Entire Hardhat setup including config, plugins, and custom tasks.scripts
- Contains a script nameddeploy.js
that deploys your smart contract when executedcontracts
- Contains a file calledGreeter.sol
with an example Solidity smart contract
Sample Deployment Script
In deploy.js
we use getContractFactory
to create a ContractFactory
, an abstraction used to deploy new smart contracts. Greeter
is a factory for instances of our greeting contract. Calling deploy()
on a ContractFactory
will start the deployment, and return a Promise
that resolves to a Contract
. This is the object that has a method for each of your smart contract functions. Modify the text to send your own message.
I’ll also add a few more console logs to the main
function to log additional pieces of information including the signer
, hash
, and blockHash
.
Hardhat Configuration
When Hardhat is run, it searches for the closest hardhat.config.js
file starting from the current working directory. This file normally lives in the root of your project. The entirety of your Hardhat setup, including your config, plugins and custom tasks, is contained in this file.
We need to make a couple changes to our hardhat.config.js
file. Update the chain ID to 1337 and change the location for the artifacts of the compiled contracts to the src
directory of the React app.
Greeter Solidity Contract
Solidity files start with a pragma that is used by the Solidity compiler to validate its version. contract
specifies the main building block for the smart contract, which is named Greeter
.
The constructor
is executed only once when the contract is created. The Greeter
constructor will set a greeting
variable and expose a function (greet
) that can be called to return the greeting
. It also exposes a function called setGreeting
that allows a user to update the greeting.
These methods will be available for a user to interact with when deployed to the Ethereum blockchain. These methods represent the two ways of interacting with a smart contract:
greet
reads from the blockchain and does not require money for gas.setGreeting
writes to the blockchain and requires payment for the transaction if you want to deploy to mainnet and not a testnet.
Deploy to Testnet
To deploy to the local network, you first need to compile your contract and then start a local test node. Our React app will interact with the smart contract using a combination of the Ethers library, the contract address, and the ABI that will be created from the contract by hardhat
.
Compile Application Binary Interface
ABI stands for application binary interface. It is the interface between your client-side application and the Ethereum blockchain where the smart contract you are going to be interacting with is deployed.
ABIs are typically compiled from Solidity smart contracts by a development framework like Hardhat. You can also often find the ABIs for a smart contract on Etherscan.
Start Test Node
This will return a list of addresses and private keys.
We will need to pick an account and corresponding private key. I will use Account #11:
Leave this terminal running and open another for the next command.
Run Deployment Script
Run the deploy script and give a flag to the CLI to let it know that we would like to deploy to our local network:
This will result in the following output in your terminal:
The address returned on the first line (0x5FbDB2315678afecb367f032d93F642f64180aa3
) is what we will use in our client application to talk to the smart contract. Save this address somewhere that you can access later as we will need to use it when connecting to the contract from the client application.
Connect to MetaMask
To send transactions to the smart contract, we will need to connect our MetaMask wallet using one of the accounts created when we ran pnpm hardhat node
. In the terminal running our local node, you will see the following output verifying that the Greeter
contract was successfully deployed.
In the list of contracts that the CLI logs out, you should see both an Account number as well as a Private Key for the account you originally chose at the beginning of the tutorial. We can import this account into MetaMask in order to start using some of its fake Eth. To do so, first open MetaMask and check the available networks.
If you only see the Ethereum Mainnet, go to Settings > Advanced and make sure “Show test networks” is set to ON.
Update the network to Localhost 8545.
Import Account into MetaMask
Once you are connected to Localhost 8545, click the icon at the top right to see your accounts. Select “Import Account.”
Go back to the list of accounts printed by pnpm hardhat node
and copy the account’s private keys. I’ll be using Account #11.
After importing the account you will see ether in the account.
If you are using MetaMask for other purposes, it will be important to distinguish this account from an account that is actually holding funds. Go to “Account details.”
Click the pencil icon next to the account name to give it a more descriptive name.
Create React App
Set greeterAddress
to the contract address logged out to the CLI when it was deployed. I have created an environment variable named VITE_GREETER_ADDRESS
in a .env
file. Any environment variables that need to be exposed on the client must be prefixed with VITE_
.
We’ll import the useState
hook and set the state to greeting
with setGreetingValue
. fetchGreeting
will call the smart contract and read the current greeting value.
I’ll include Water.css in index.html
for some nice looking CSS defaults.
Start Development Server
Start the development server with pnpm dev
.
Open localhost:3000.
Click the “Fetch Greeting” button to display the greeting from the deployed contract.
setGreeting
calls the smart contract and sends an update.
Connect React App to MetaMask
Select account to connect with MetaMask.
Connect to the account.
Enter input and click Set Greeting. You will be asked to pay a gas fee.
The greeting value will be set to the new inputted greeting.
Deploy to Ropsten Testnet
Ethereum provides test networks like Ropsten, Rinkeby, or Kovan that we can use to deploy a publicly accessible version of our contract without having to deploy it to the mainnet.
Connect MetaMask to Ropsten
Update your MetaMask wallet to connect to the Ropsten network.
We can get access to Ropsten and other test networks by using a service like Infura, Alchemy, or QuickNode.
Create an Alchemy Account
Alchemy Supernode is a blockchain API that can connect to various tools in the blockchain ecosystem such as Ethereum, Polygon, Arbitrum, Optimism, and Flow. It provides common node functionality including JSON-RPC support with built in reliability, data correctness and scalability. After creating an account, you will see your dashboard.
Create an Alchemy Application
Click Create App and give your app a name and description. Select development for the environment, Ethereum for the chain, and Ropsten for the network.
After creating the app you will see it appear in your dashboard.
Get Alchemy Key
Click the name of the app to see more details.
Click View Key to see your endpoints.
The https endpoint will look something like this:
Click Edit App and add the account address from App.jsx
to the allowed accounts.
Add Alchemy Endpoint to Hardhat Configuration
Open hardhat.config.js
and add networks
property.
Deploy Contract to Ropsten
Send yourself test Ether by visiting a test faucet like faucet.ropsten.be
. Run the following script to deploy.
Once your contract is deployed you can view the live contract on Etherscan Ropsten Testnet Explorer.