Learn Ethereum programming #4. JSON-RPC with Node.js

João Paulo Morais
Coinmonks
Published in
4 min readDec 30, 2022

--

JSON-RPC is a remote call protocol whose data is encoded in JSON. Most blockchain clients serve requests sent via JSON-RPC. The protocol over which JSON-RPC is sent can be http, WebSocket, and in some cases gRPC. Practically every programming language has a module for sending requests via HTTP, so we can connect to the blockchain using any of these languages.

In this lesson we will use Node.js to send requests. In theory, that’s all we would need to write a decentralized application on Ethereum, along with some cryptographic libraries to sign our transactions. In real life (not in theory), we use libraries that have specialized methods to interact with the blockchain, in order to make our lives easier.

In any case, it is important to understand how things work under the hood, and also to know the methods accepted by the Ethereum execution client. Many web3 library methods are nothing more than a simple wrapper of methods that can be executed via JSON-RPC.

To start, I’m going to create a folder called jsonrpc in some directory and launch Visual Studio Code in it. After that, I’ll start a program with the npm init -y directive. We will then install 3 packages: axios, ws and dotenv.

npm i axios ws dotenv 

Axios is a library that creates an HTTP client. Ws is a library for using WebSocket. Dotenv is a module for using environment variables in Node.

Follow the code

The code to send a request to an Alchemy (or any other) node is pretty simple. Consider the code below.

require("dotenv").config();
const axios = require("axios");

const payload = {
jsonrpc: "2.0",
id: 0,
method: "eth_getBalance",
params: ["0x8303539291922EF29B518B5B93e8Ab07F22F2D1d","latest"]
};

(async () => {
const response = await axios.post(`https://eth-goerli.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}`, payload)
console.log(response.data)
})();

First we import the 2 libraries we need at this point, dotenv and axios. The payload is the javascript object that must be sent as JSON, which asks to execute the eth_getBalance method. I use it with 2 parameters, the address to recover the balance and the indication that I want the most recent balance (optional).

New to trading? Try crypto trading bots or copy trading on best crypto exchanges

Then I write an asynchronous function and execute it immediately, using the axios library to send the HTTP request. It needs 2 parameters: the node address and the JavaScript object to be sent as JSON.

Note that I use process.env.ALCHEMY_KEY as the key. For that, you need to create a .env file in the same directory and declare the Alchemy key, as below.

ALCHEMY_KEY=1P_1HHvUYb...nZhZ5DY

Finally, I write to the console only the data property of the response, as that is where the return data can be found. Notice how simple it really is to send HTTP (or HTTPS) requests using Node.js.

HTTP or WebSocket

Most Ethereum clients accept requests using both HTTP and WebSocket. They are different protocols and behave differently. With WebSocket, a communication channel is opened between the client and the server, and that channel remains open until it is explicitly closed.

When we only want specific information, using HTTP is enough. However, sometimes we want to receive information continuously, like when we subscribe to a request to keep receiving information about events emitted by smart contracts. In this case, it is necessary to use WebSocket.

Let’s modify our code to send a subscription request. In it, we will ask to receive all events issued by the DAI token, on Ethereum. Let’s see the code below.

require("dotenv").config();
const WebSocket = require("ws")

const payload = {
jsonrpc: "2.0",
id: 0,
method: "eth_subscribe",
params: [
"logs",
{
address: '0x6b175474e89094c44da98b954eedeac495271d0f',
topics: []
}
]
};

const ws = new WebSocket(`wss://eth-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_KEY}`)

ws.on('open', () => {
ws.send(JSON.stringify(payload))
})

ws.on('message', (data) => {
console.log(`received: ${data} \n`)
})

It’s a little longer than the previous one, but it’s not complicated either. First, we no longer use axios but a library called ws.

Our payload is also different, as we now ask to execute the eth_subscribe method. In the first parameter we indicate what we want to receive, logs, and in the second parameter we indicate the address of the contract that we want to receive the events. The field called Topics will not be seen in this lesson and we can leave it empty.

We create a new instance of the WebSocket object using new WebSocket with the address of the Alchemy node that supports WebSocket. Note that I changed the node address to the Mainnet, because the contract I’m going to monitor is on it.

In the created instance, we define the callback for 2 events.

In the open event, we send the payload we created, encoded as JSON. In the message event, we write the received data to the console. The message event is executed every time an event is emitted by the smart contract.

In the figure below, we can see the return of executing the above code. The connection will remain active, receiving messages from Alchemy, until terminated by one of the parties.

Subscribing to receive events.

I hope it’s clear how simple it is to interact with the blockchain using Node.js, without the need for any Ethereum-specific library.

Thanks for reading!

Comments and suggestions about this article are welcome.

Any contribution is welcome. www.buymeacoffee.com/jpmorais.

--

--

João Paulo Morais
Coinmonks

Astrophysicist, full-stack developer, blockchain enthusiast. Unraveling cosmos mysteries by day, crafting the next Latin American novel by night.