Ethers.js & Hardhat: Subscribe To Events In Node.js
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 thesetValue
function is called. The event includes thesender
(the address that called the function) and thevalue
that was set. Theindexed
keyword on thesender
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 thestoredValue
and emits theValueSet
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