Ethers.js & Hardhat: Subscribe To Events In Node.js

by Lucas 52 views

Hey guys! Ever wondered how to make your Node.js app react in real-time to blockchain events using Ethers.js and Hardhat? You've come to the right place! In this guide, we'll dive deep into setting up a Node.js Express application that connects to a local Hardhat network via Ethers.js and WebSockets. We'll tackle the common challenge of subscribing to smart contract events, ensuring your application stays in sync with the blockchain's heartbeat. Let's get started!

Setting Up Your Node.js and Hardhat Environment

Before we jump into the code, let's get our environment prepped and ready. This part is crucial, so pay close attention! First, make sure you have Node.js and npm (Node Package Manager) installed. If not, head over to the official Node.js website and grab the latest version. Once you've got that sorted, we can start building our project.

Let's kick things off by creating a new directory for our project. Open up your terminal and type these commands:

mkdir ethers-hardhat-events
cd ethers-hardhat-events
npm init -y

This creates a new folder named ethers-hardhat-events, navigates into it, and initializes a new Node.js project with a default package.json file. Now, let's install the necessary dependencies. We'll need ethers, hardhat, and express for our project.

npm install --save ethers hardhat express
npm install --save-dev @nomicfoundation/hardhat-toolbox

Here, ethers will be our trusty sidekick for interacting with the Ethereum blockchain, hardhat will serve as our local development environment and deployment tool, and express will help us create a simple Node.js server. The @nomicfoundation/hardhat-toolbox package is a suite of helpful plugins for Hardhat, making our development process smoother. With these dependencies installed, we're one step closer to blockchain event mastery!

Next up, let's set up Hardhat. Run the following command in your project directory:

npx hardhat

You'll be prompted to select an option. Choose “Create a basic sample project”. Hardhat will then generate a basic project structure for you, including a hardhat.config.js file, a contracts folder, and a scripts folder. The hardhat.config.js file is where we configure our Hardhat environment, and the contracts folder is where we'll store our smart contracts. The scripts folder will hold scripts for deploying and interacting with our contracts.

Now, open your hardhat.config.js file and make sure it's configured correctly. A basic configuration might look something like this:

require("@nomicfoundation/hardhat-toolbox");

/** @type import('hardhat/config").HardhatUserConfig */
module.exports = {
 solidity: "0.8.19",
 networks: {
 hardhat: {
 // If you want to do some forking, uncomment this
 // forking: {
 // url: process.env.ALCHEMY_MAINNET_RPC_URL,
 // }
 },
 },
};

This configuration tells Hardhat to use Solidity version 0.8.19 and sets up a hardhat network, which is Hardhat's local development network. With our environment set up, we're ready to start writing some smart contracts!

Crafting Your Smart Contract

Now for the fun part – writing the smart contract that will emit the events we want to subscribe to! We'll create a simple contract that emits an event whenever a value is set. This will give us a clear example to work with when we dive into subscribing to events using Ethers.js.

Navigate to the contracts folder in your project and create a new file called EventContract.sol. Open this file in your favorite code editor and paste in the following code:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract EventContract {
 event ValueSet(address indexed sender, uint256 value);

 uint256 public storedValue;

 function setValue(uint256 _value) public {
 storedValue = _value;
 emit ValueSet(msg.sender, _value);
 }

 function getValue() public view returns (uint256) {
 return storedValue;
 }
}

Let's break down this contract:

  • We declare an event called ValueSet. This event will be emitted whenever the setValue function is called. The event includes the sender (the address that called the function) and the value that was set. The indexed keyword on the sender parameter tells Ethereum to make it easier to filter events by this address.
  • We have a state variable called storedValue, which will hold our value.
  • The setValue function sets the storedValue and emits the ValueSet event.
  • The getValue function allows us to read the current value.

With our contract written, we need to compile and deploy it to our Hardhat network. To compile the contract, run the following command in your terminal:

npx hardhat compile

This will compile your contract and generate the necessary artifacts (ABI and bytecode) in the artifacts folder. These artifacts are crucial for interacting with your contract using Ethers.js. Next, we'll write a deployment script to deploy our contract to the Hardhat network. Create a new file called deploy.js in the scripts folder and add the following code:

async function main() {
 // Get the contract factory
 const EventContract = await ethers.getContractFactory("EventContract");

 // Deploy the contract
 const eventContract = await EventContract.deploy();
 await eventContract.deployed();

 console.log("EventContract deployed to:", eventContract.address);
}

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

This script uses Ethers.js to deploy our EventContract to the Hardhat network. It first gets the contract factory, then deploys the contract, and finally logs the contract's address to the console. To run this script, use the following command:

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

This command tells Hardhat to run the deploy.js script on the hardhat network. You should see output similar to this:

EventContract deployed to: 0x5fbdb2315678afecb367f032d93f642f64180aa3

Make a note of the deployed contract address – we'll need it later when we set up our event subscription. Our contract is now live and ready to emit events! Let's move on to setting up our Node.js Express application to listen for these events.

Building Your Node.js Express App

Now, let's switch gears and focus on building the Node.js Express application that will listen for our smart contract events. This app will connect to our Hardhat network, subscribe to the ValueSet event, and log the event data to the console. This is where the magic happens!

First, let's create a basic Express server. Create a new file called index.js in your project root and add the following code:

const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
 res.send('Hello World!');
});

app.listen(port, () => {
 console.log(`Example app listening at http://localhost:${port}`)
});

This code sets up a simple Express server that listens on port 3000 and responds with