Reacting to Ethereum Events (Log) – Subscribe and Topics

Published by Mario Oettler on

Another way to react to events is to use the subscribe method of the web3.js library. The documentation of this method is here: https://web3js.readthedocs.io/en/v1.8.0/web3-eth-subscribe.html.

Take a look at the following JavaScript code:

const Web3 = require("web3");
var web3   = new Web3("ADD INFURA WEBSOCKET ENDPOINT + PROJECT ID HERE");

contractAddress = "ADD CONTRACT ADDRESS HERE";

listenForEvent();
async function listenForEvent(){
	console.log("Waiting for event");
	var subscription = web3.eth.subscribe('logs', {
		address: contractAddress,
	}, function(error, result){
		if (!error)
			console.log(result);
	});
}

With this method, we receive all events that happen in the smart contract.

Now, we want to receive only certain events. For that purpose, we need to define a topic.

We provide the topic in the field “topics”. However, it is not possible to simply give the name of the event. Instead, we need to provide the signature of this topic. There are two ways of how to obtain the topic’s signature.

Taking the topic from the console

Take the following smart contract and deploy it on the Goerli testnet. You can use the online Remix IDE for that purpose.

pragma solidity 0.8.17;

contract Events2{
    
    event Sale(
        address indexed _to,
        uint256 indexed _amount
    );
    
    event Register(
        address indexed _address,
        string indexed _name
    );
    
    function sell() public payable{
        emit Sale(msg.sender, msg.value);
    }
    
    function register(string memory _name) public{
        emit Register(msg.sender, _name);
    }
}

This smart contract defines two events, Sale and Register. They are emitted in the functions sell() and register(). Both functions are dummy functions that do nothing else but emitting an event.

Now, take the following JavaScript code, enter the api key and the contract address and execute it via nodejs.

const Web3 = require("web3");
var web3   = new Web3("wss://goerli.infura.io/ws/v3/<Enter your API Key here>");

contractAddress = "<Enter your contract address here>";

listenForEvent();
async function listenForEvent(){
	console.log("Waiting for event");
	var subscription = web3.eth.subscribe('logs', {
		address: contractAddress,
	}, function(error, result){
		if (!error)
			console.log(result);
	});
}

Now, go to your deployed contract, execute the function sell() and wait until the event is printed in your console. This should look like the following screen shot.

Now, we extend our JavaScript file with the line 8

topics: [“topic-Hash here”]

You can find the complete source code here:

const Web3 = require('web3');
const web3 = new Web3("wss://goerli.infura.io/ws/v3/<Enter api key here>");

web3.eth.subscribe(
    'logs',
    {
        address: '<enter contract address here>',
        topics: ['0xc6851889326b4ff916523ef06f539b4cf0b81d78fc6e0f97c30e6223d1831990']
    },
    function (error, result) {
        console.log("sell: " + JSON.stringify(result));    
    });

Execute the JavaScript file and call the functions sell() and register() in your smart contract. The event should only be printed to the console, if the function sell() is called.

The result should look like this:

Calculating the topic signature

The second way how to obitain the topic signature is to calculate it ourselves.

The signature is derived from the event declaration by removing all key words, colons, variable names and spaces.

So, from

    event Sale(
        address indexed _to,
        uint256 indexed _amount
    );

we get

Sale(address,uint256)

Then, we hash this string with keccak 256.

You can use the following tools:

This should produce the same hash like in the console print out from above.

Categories: