43

I need to listen to the specific contract events and do some task once the event is emitted. I didn't find proper docs on ethers.js documentation.

Can anybody tell me how can I keep listening to my contract events using ethers.js?

5 Answers 5

39

This answer assumes that you understand how to connect to a contract using Ethers.

Your question specifies listening for an event to be emitted, and to do a task based on that.

Here is the link to the Ethers v5 documentation, which we'll expand on a bit below: https://docs.ethers.io/v5/api/providers/provider/#Provider--events

(Ethers v4 is here and here)

Basically, the on function is what you're looking for. Using a provider, you can set up an on to trigger something whenever a particular event is emitted. This will trigger the callback (the second argument in the on, a function) anytime that event is emitted on the blockchain. If you are looking for the on to be triggered only when the events of a particular contract are called, you'll need to use a filter - the provider will trigger the callback anytime this event is emitted from any contract.

If you look at the example in the link above to the v5 docs (at least right now 22/09/2020), towards the bottom there are examples of how to use filters (either a general filter or a topic filter - we'll discuss the first). Basically:

filter = {
    address: THE_ADDRESS_OF_YOUR_CONTRACT,
    topics: [
        // the name of the event, parnetheses containing the data type of each event, no spaces
        utils.id("Transfer(address,address,uint256)")
    ]
}
provider.on(filter, () => {
    // do whatever you want here
    // I'm pretty sure this returns a promise, so don't forget to resolve it
})

There are many more details about how and what you can filter in the links above, but this is the fundamental building block. I hope this helps!

Update: Based on a comment, I thought I should add that on can also be used with a contract object. If you have a variable representing a contract (which we'll call contract), you can also hook an on onto it. Here's a link to a section in the v4 docs which has an example (which at least as of now isn't in the v5 docs yet) - scroll down to the "listening to an Event" code example. It has the same format where you pass in an event name or filter for the first arg, and then can write a function callback as the second. This will only return events from contract.

8
  • I need WebSocket Provider for that right? I get this error when i tried websocket with ganache ``` Error: VM Exception while processing transaction: revert at WebSocketProvider._this._websocket.onmessage (/home/manzik/esatya/rahat/hapi/server/node_modules/@ethersproject/providers/lib/websocket-provider.js:115:37) ``` Commented Sep 23, 2020 at 3:23
  • Also, Can you help me with this - docs.ethers.io/v5/api/contract/contract How can i use "contract.on(event,listener)" - what should I put in event there Commented Sep 23, 2020 at 3:26
  • 4
    Pro tip: If you find the v5 docs hard to read on anything, look at the v4 docs, and try to figure out if it's still the same: docs.ethers.io/v4/… Scroll down a bit, look at the code example of "Listening to Events" - you'll see it works the same way as the provider example here. Commented Sep 23, 2020 at 10:19
  • 1
    The signature of .on() is very surprising; I'd expect it to have at least one argument that contains information about the event that was omitted. Commented Oct 25, 2021 at 23:56
  • 1
    @GuidoWalterPettinari no, the values emitted depend on what block the tx is mined into in many cases (the tx is only executed once it's mined, and that when the logs "happen") Commented May 1, 2022 at 5:22
26

// event in ERC-20: Transfer(address indexed src, address indexed dst, uint val)

    contract.on("Transfer", (to, amount, from) => {
        console.log(to, amount, from);
    });

You can read here: https://docs.ethers.io/v5/api/contract/contract/#Contract--events

Also good examples here: https://docs.ethers.io/v5/concepts/events/

And discussion topic with more info: https://github.com/ethers-io/ethers.js/issues/492

2

dev advocate at Chainstack here.

Here is how to do it using Ethers V6 and WebSocket in case anyone needs a complete and updated version.

This example shows how to listen for the Transfer event on an ERC-20 contract, WETH in this specific example:

import { WebSocketProvider, Contract } from 'ethers';

// WebSocket provider configuration
const providerUrl = 'YOUR_WSS_URL';

// Contract configuration
const contractAddress = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'; // WETH contract address

// ABI portion for the Transfer event
const contractABI = [
  {
    anonymous: false,
    inputs: [
      {
        indexed: true,
        internalType: 'address',
        name: 'from',
        type: 'address'
      },
      {
        indexed: true,
        internalType: 'address',
        name: 'to',
        type: 'address'
      },
      {
        indexed: false,
        internalType: 'uint256',
        name: 'value',
        type: 'uint256'
      }
    ],
    name: 'Transfer',
    type: 'event'
  }
];

const main = async () => {
  try {
    // Create WebSocket provider
    const provider = new WebSocketProvider(providerUrl);

    // Create contract instance
    const contract = new Contract(contractAddress, contractABI, provider);

    console.log(`Listening for Transfer events on ${contractAddress}...`);


    // Listen for events
    contract.on('Transfer', (from, to, value, event) => {
        console.log('Transfer event triggered:', {
        from: from,
        to: to,
        value: value.toString(),
        data: event,
        });
    });


  } catch (error) {
    console.error('Error:', error);
  }
};

main();

You'll need to add "type": "module", to your package.json to run it.

1
  • hi can u guide me how to get providerUrl
    – famfamfam
    Commented Aug 22 at 7:44
1
try {
          const tokenObject = {
            ImageIPFS: data.eventcard.picture_ipfs,
            metaData: {
              EventName: data.eventcard.name,
              Description: data.eventcard.description,
              Date: data.eventcard.date,
              Location: data.eventcard.location,
              Price: getEventPrice(data.eventcard),
              Collection: data.eventcard.collection,
            },
          };

      const added = await client.add(JSON.stringify(tokenObject));
      const ipfs_url = `https://ipfs.infura.io/ipfs/${added.path}`;

      // const ipfs_url = `https://ipfs.infura.io/ipfs/test`; // #placeholder
      console.log("IPFS ulr:", ipfs_url);

      // const provider = new ethers.providers.Web3Provider(
      //   (window as any).ethereum
      // );
      // const contract = new ethers.Contract(myNFTAddress_mainnet, myNFTABI, provider.getSigner());
      const contract = new ethers.Contract(
        chainId === 97
          ? myNFTAddress_testnet
          : chainId === 56
          ? myNFTAddress_mainnet
          : "",
        myNFTABI,
        provider.getSigner()
      );
    
      contract.on("Minted", (tokenId, tokenURI) => {
        console.log("First parameter :", tokenId);
        console.log("Second parameter :", tokenURI);
        data.tokenURL = `${tokenURL_testnet}${tokenId}`;
        data.ipfsURL = data.eventcard.picture_ipfs;
        data.is_minted = 1; // BSC
        console.log(data);
        updateUserTickets(data).then((res) => {
          if (res.success) {
            addToast("Successfully Minted", {
              appearance: "success",
              autoDismiss: true,
            });
            userTickets().then((res) => {
              if (res.success) {
                setTickets(res.tickets);
              }
            });
          } else {
            addToast("Failed save database", {
              appearance: "error",
              autoDismiss: true,
            });
          }
        });
        setLoading(false);
        setTickets(updateTicketProgressStatus(tickets, data.id, false));
      });
    } catch (error) {
      console.log("Error: ", error);
      setLoading(false);
      setTickets(updateTicketProgressStatus(tickets, data.id, false));
    }
0

In addition to using Ethers.js, you can use Bitquery streams.

This makes programming easier, and data parsing is already done on Bitquery's end.

Here is an example of a PairCreated Event on the Uniswap Factory contract.

https://ide.bitquery.io/Uniswap-Pair-Created-Contract-Events

Learn more on their docs. https://docs.bitquery.io/docs/examples/events/events-api/

Disclosure - I work for Bitquery

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.