Subscribe to Events¶
Introduction¶
Moonbeam supports event subscriptions for Ethereum-style events, which allows you to wait for events and handle them accordingly instead of polling for them.
It works by subscribing to particular events; an ID is returned for each subscription. For each event that matches the subscription, a notification with relevant data is sent together with the subscription ID.
In this guide, you will learn how to subscribe to event logs, incoming pending transactions, and incoming block headers on Moonbase Alpha. This guide can also be adapted for Moonbeam or Moonriver.
Supported Pubsub JSON-RPC Methods¶
Please note that the examples in this section require installing wscat.
eth_subscribe
Creates a subscription for a given subscription name.
subscription_namestring - the type of the event to subscribe to. The supported subscription types are:newHeads— triggers a notification each time a new header is appended to the chainlogs— returns logs that are included in new imported blocks and match a given filter criterianewPendingTransactions— returns the hash for all transactions that are added to the pending statesyncing— indicates when the node starts or stops synchronizing with the network
The result returns the subscription ID.
wscat -c wss://wss.api.moonbase.moonbeam.network -x '
{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_subscribe",
"params": ["INSERT_SUBSCRIPTION_NAME"]
}'
eth_unsubscribe
Cancels an existing subscription given its subscription ID.
subscription_idstring - the subscription ID
The result returns a boolean indicating whether or not the subscription was successfully canceled.
wscat -c wss://wss.api.moonbase.moonbeam.network -x '
{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_unsubscribe",
"params": ["INSERT_SUBSCRIPTION_ID"]
}'
Subscribe to Events Using Ethereum Libraries¶
This section will show you how to use Ethereum libraries, like Ethers.js, to programmatically subscribe to events on Moonbeam.
Checking Prerequisites¶
The examples in this guide are based on an Ubuntu 22.04 environment. You will also need the following:
- MetaMask installed and connected to Moonbase Alpha
- An account with funds. You can get DEV tokens for testing on Moonbase Alpha once every 24 hours from the Moonbase Alpha Faucet
- To deploy your own ERC-20 token on Moonbase Alpha. You can do this by following our Remix tutorial while first pointing MetaMask to Moonbase Alpha
-
Ethers.js or the Ethereum library of your choice installed. You can install Ethers.js via npm:
npm install ethers
Subscribe to Event Logs¶
Any contract that follows the ERC-20 token standard emits an event related to a token transfer, that is, event Transfer(address indexed from, address indexed to, uint256 value). In this section, you'll learn how to subscribe to these events using the Ethers.js library.
Use the following code snippet to set up a subscription to listen for token transfer events:
const { ethers } = require('ethers');
const provider = new ethers.WebSocketProvider(
'wss://wss.api.moonbase.moonbeam.network'
);
const tokenAddress = 'INSERT_CONTRACT_ADDRESS';
const abi = [
'event Transfer(address indexed from, address indexed to, uint256 value)',
];
const iface = new ethers.Interface(abi);
const transferTopic = ethers.id('Transfer(address,address,uint256)');
const filter = {
address: tokenAddress,
topics: [transferTopic],
};
const main = async () => {
console.log('🕔 Subscription set up. Waiting for new logs');
provider.on(filter, (log) => {
const parsed = iface.parseLog(log);
console.log({
from: parsed.args.from,
to: parsed.args.to,
value: parsed.args.value.toString(),
blockNumber: log.blockNumber,
txHash: log.transactionHash,
});
});
};
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
Note
Make sure to replace 'INSERT_CONTRACT_ADDRESS' with the actual address of the ERC-20 token contract that you should have already deployed (as a prerequisite).
In the provided code:
- A WebSocket provider is used to listen for the
Transferevent and parse the log with the contract ABI -
The listener filters for the
Transferevent by signature, which can be calculated as follows:EventSignature = keccak256(Transfer(address,address,uint256))This translates to
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efand is used as the first topic in the subscription filter.
If you do not provide any topics, you subscribe to all events emitted by the contract. More information about topics can be found in the Understanding event logs on the Ethereum blockchain Medium post.
By executing this code, you'll establish a subscription to monitor ERC-20 token transfer events on Moonbeam. New events will be logged to the terminal as they occur.
Understanding Event Logs¶
To illustrate the process, assume that an ERC-20 token transfer has been sent with the following parameters:
- From address -
0x44236223aB4291b93EEd10E4B511B37a398DEE55 - To address -
0x8841701Dba3639B254D9CEe712E49D188A1e941e - Value (tokens) -
1000000000000000000(1 DEV in Wei)
The event logs emitted by the transaction are as follows:
If you look at the topics array, there are a total of three topics present (in this order):
- The event signature of the
Transferevent - The
fromaddress - The
toaddress
As there are a total of three topics (the maximum is four), this corresponds to the LOG3 opcode:
Indexed topics, such as the from and to addresses, are typically represented by 256-bit (64 hexadecimal character) values. If necessary, they are padded with zeros to reach the full length.
Unindexed data, such as the value of tokens transferred, is not included in the topics array. Instead, it is returned within the logs' data field, encoded in bytes32/hex format. To decode it, you can use, for example, this Web3 Type Converter tool and verify that the data is 1 DEV token formatted in Wei.
If the event returns multiple unindexed values, they will be appended one after the other in the same order the event emits them. Therefore, each value is obtained by deconstructing data into separate 32-byte (or 64-hex-character-long) pieces.
Use Wildcards and Conditional Formatting¶
Using the same example as in the previous section, you can subscribe to Transfer events while filtering by specific senders with the following code:
const { ethers } = require('ethers');
const provider = new ethers.WebSocketProvider(
'wss://wss.api.moonbase.moonbeam.network'
);
const tokenAddress = 'INSERT_CONTRACT_ADDRESS';
const abi = [
'event Transfer(address indexed from, address indexed to, uint256 value)',
];
const contract = new ethers.Contract(tokenAddress, abi, provider);
// Listen for Transfer events where the "from" address matches either entry below
const fromAddresses = [
'0x44236223aB4291b93EEd10E4B511B37a398DEE55',
'0x8841701Dba3639B254D9CEe712E49D188A1e941e',
];
const filter = contract.filters.Transfer(fromAddresses, null);
const main = async () => {
console.log('🕔 Subscription set up. Waiting for new logs');
contract.on(filter, (from, to, value, event) => {
console.log({
from,
to,
value: value.toString(),
blockNumber: event.blockNumber,
txHash: event.transactionHash,
});
});
};
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
Here, the first indexed parameter (from) is filtered to the provided address list, while to is set to null to act as a wildcard. The contract filter handles topic formatting for you, so you don't need to manually pad the addresses.
As shown, after you provided the two addresses with conditional formatting, you should have received two logs with the same subscription. Events emitted by transactions from different addresses will not throw any logs to this subscription.
This example showed how you could subscribe to just the event logs of a specific contract, but the same approach applies to other subscription types covered in the following sections.
Subscribe to Incoming Pending Transactions¶
To subscribe to pending transactions with Ethers.js, you can use a WebSocket provider and the provider.on('pending') event. The transaction hash of the pending transactions is returned, and you can optionally fetch full transaction details with provider.getTransaction(hash).
You can try this by sending a transaction and verifying that the transaction hash returned by the subscription is the same one returned by the development tool or wallet you are using.
Subscribe to Incoming Block Headers¶
You can also subscribe to new block headers using provider.on('block'), then fetch the block with provider.getBlock(blockNumber). This subscription provides incoming block headers and can be used to track changes in the blockchain.
Note that only one block header is shown in the image. These messages are displayed for every block produced so they can quickly fill up the terminal.
Check If a Node Is Synchronized with the Network¶
With pubsub, checking whether a particular node is currently synchronizing with the network is also possible. You can call the eth_subscribe RPC with syncing using your preferred library's low-level WebSocket request helper. This subscription will either return a boolean when syncing is false or an object describing the syncing progress when syncing is true, as seen below.
Note
The pubsub implementation in Frontier is still in active development. This current version allows users to subscribe to specific event types, but there may still be some limitations.
| Created: April 17, 2024
