
3 ways to subscribe to events with Web3.js
Most Smart contracts will emit events whenever an action or a function is invoked in the smart contract. These events can also return interesting data. For example, ERC20 tokens will always emit a Transfer event whenever a transfer occurs between two addresses. When this event gets emitted the event will attach who the sender is, the recipient, and the value transferred.
There are multiple ways to listen for events, in this post we will be showing you 3 ways to do it.
First off, you will need to connect to a full node by creating a new Web3 provider. You will also have to find a contract you want to listen to events from. Get the contract address & its ABI from a block explorer or whatever way you prefer, then prepare the code for listening to events from it by doing something like this:
import Web3 from 'web3';
const web3 = new Web3('YOUR_RPC_ENDPOINT_HERE');
const ABI = 'YOUR ABI HERE';
const CONTRACT_ADDRESS = 'YOUR CONTRACT ADDRESS HERE';
const myContract = new Web3.Contract(ABI, CONTRACT_ADDRESS);
1. Getting past events
It’s actually wrong to say that we listen for events with the method we are about to show. Rather you query a blockchain node for events that have happened in the past. The node will then go through the blockchain and scan for the event you are querying for and return the results. The method is called getPastEvents and is attached to a contract’s instance. For the sake of it let’s pretend that the contract we are working with is an ERC20 token and we want to get all past Transfer events.
let options = {
filter: {
value: ['1000', '1337'] //Only get events where transfer value was 1000 or 1337
},
fromBlock: 0, //Number || "earliest" || "pending" || "latest"
toBlock: 'latest'
};
myContract.getPastEvents('Transfer', options)
.then(results => console.log(results))
.catch(err => throw err);
You can filter what data you want to be returned. Since the Transfer event returns from, to, and value we can filter on these properties. Keep in mind that this is not as quick as your common database, querying a blockchain node is slow AF. If you need to analyze thousands of transactions you should probably consider creating your own indexing solution.
2. Contract instance event method
The second way to subscribe to events from a contract is to use the event methods that have been automatically generated by web3.js on your contract instance. Keep in mind though, if you do not provide a correct ABI for the contract these methods will not be automatically generated for you.
let options = {
filter: {
value: [],
},
fromBlock: 0
};
myContract.events.Transfer(options)
.on('data', event => console.log(event))
.on('changed', changed => console.log(changed))
.on('error', err => throw err)
.on('connected', str => console.log(str))
Each events method will return an EventEmitter. The events that you can listen to are the ones we are listening to in the example code above. Where:
- data – Will fire each time an event of the type you are listening for has been emitted
- changed – Will fire for each event of the type you are listening for that has been removed from the blockchain.
- error – Will fire if an error in the event subscription occurs.
- connected – Will fire when the subscription has successfully established a connection. It will return a subscription id. This event only fires once.
3. The eth subscribe method
This method of subscribing to events is like a “catch-all” method. If you want you can listen to all event logs emitted from the blockchain with this method. Method 1 and 2 are probably the easiest to use in most cases.
let options = {
fromBlock: 0,
address: ['address-1', 'address-2'], //Only get events from specific addresses
topics: [] //What topics to subscribe to
};
let subscription = web3.eth.subscribe('logs', options,(err,event) => {
if (!err)
console.log(event)
});
subscription.on('data', event => console.log(event))
subscription.on('changed', changed => console.log(changed))
subscription.on('error', err => { throw err })
subscription.on('connected', nr => console.log(nr))
The subscribe method will return a Subscription instance which is also an EventEmitter. The events are the same as the ones for method 2. Besides the events the subscription instance has these properties and methods:
- id – This is the subscription id
- unsubscribe(callback) – This method can be used to unsubscribe from the subscription
- subscribe(callback) – This method can be used to re-subscribe with the same parameters as the initial subscription had
- arguments – The subscription arguments that are used when re-subscribing.
An example of an event response from methods 1 & 2
The response below is a response from a “Transfer” event from an ERC20 contract on the Polygon blockchain.
[{
"address": "0xe381C25de995d62b453aF8B931aAc84fcCaa7A62",
"blockNumber": 15048427,
"transactionHash": "0xf81d8bd942ba647cc44c398befe5a15537e3a91ad579a78b567dd94df6c41049",
"transactionIndex": 129,
"blockHash": "0xe314c8962e9c80b13081ef4cdc5f32db3b44d9cb2df7532df603713c71f28b30",
"logIndex": 209,
"removed": false,
"id": "log_c493edef",
"returnValues": {
"0": "0xF9F613BDec2703ede176cC98A2276fA1F618A1b1",
"1": "0x0000000000000000000000000000000000000000",
"2": "100000000000000000000000",
"from": "0xF9F613BDec2703ede176cC98A2276fA1F618A1b1",
"to": "0x0000000000000000000000000000000000000000",
"value": "100000000000000000000000"
},
"event": "Transfer",
"signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"raw": {
"data": "0x00000000000000000000000000000000000000000000152d02c7e14af6800000",
"topics": [
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"0x000000000000000000000000f9f613bdec2703ede176cc98a2276fa1f618a1b1",
"0x0000000000000000000000000000000000000000000000000000000000000000"
]
}
}]
An example of an event response from method 3
{
address: '0x0000000000000000000000000000000000001010',
topics: [
'0x4dfe1bbbcf077ddc3e01291eea2d5c70c2b422b415d95645b9adcfd678cb1d63',
'0x0000000000000000000000000000000000000000000000000000000000001010',
'0x00000000000000000000000032708b58c82bc076aa4ec83e4af16fc203adcb2c',
'0x0000000000000000000000001ca971963bdb4ba2bf337c90660674acff5beb3f'
],
data: '0x000000000000000000000000000000000000000000000000001088ecbd7b3c000000000000000000000000000000000000000000000000000c877b32146eecbf00000000000000000000000000000000000000000000017c447c156116deb1d60000000000000000000000000000000000000000000000000c76f24556f3b0bf00000000000000000000000000000000000000000000017c448c9e4dd459edd6',
blockNumber: 0,
transactionHash: '0xae884ba7e7f6e56dee4e45d6eeae00bf688de7ca3d672d2a7f5b06a27a22b34e',
transactionIndex: 6,
blockHash: '0x279ccf819050d18eb1938774faa6d1734eeef08b855d0489d91bd805c7a0d827',
logIndex: 6,
removed: false,
id: 'log_7cff1a97'
}