> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chainstack.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How to properly encode topics for eth_getLogs

> Encode event topics correctly for eth_getLogs queries using web3.js and ethers.js to filter smart contract events by indexed parameters on Chainstack.

<AccordionGroup>
  <Accordion title="Overview">
    When retrieving logs from an EVM-compatible blockchain, developers often use the `eth_getLogs` method. One of the key parameters of this method is the topics filter, which allows you to narrow down the search to specific event logs based on their encoded signature and parameters.

    This script will show you how to encode this data using web3.js and ethers.js.
  </Accordion>

  <Accordion title="Environment setup">
    Install [node.js](https://nodejs.org/en/) in case it is not installed.

    Create a new directory for your project, then Install the web3.js and ethers.js libraries.

    ## web3.js:

    `npm install web3`

    ## ethers.js:

    `npm install ethers`
  </Accordion>

  <Accordion title="Create a Web3 instance">
    ## web3.js:

    The first step is to create a `Web3` instance to be able to access the web3.js tools.

    This script uses two tools from the web.js library. The `keccak256 ` function and the `padLeft` util.

    ## ethers.js:

    The first step is to create a `utils` instance to be able to access the utils tools.

    This script uses three tools from the ethers.js library. The `keccak256 ` function, the `toUtf8Bytes`, and the `hexZeroPad` function.

    <CodeGroup>
      ```js web3.js theme={"system"}
      const Web3 = require('web3');
      ```

      ```js ethers.js theme={"system"}
      const { utils } = require('ethers');
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Create a function to encode the event signature">
    The event signature is generated by hashing the event's name and its parameter types using the Keccak-256 algorithm, also known as SHA-3. This produces a 32-byte hash value.

    The event signature is used in the topics filter of the `eth_getLogs` method to match the corresponding event logs on the blockchain.

    By using the web3.js or ethers.js libraries, developers can easily generate these event signatures and efficiently filter event logs to extract the data they need.

    <CodeGroup>
      ```js web3.js theme={"system"}
        // Generate event signature using keccak256 hash algorithm
      function encodeEvent(event) {
        const keccakHash = Web3.utils.keccak256(event);
        return keccakHash;
      }
      ```

      ```js ethers.js theme={"system"}
      // Generate event signature using keccak256 hash algorithm
      function encodeEvent(event) {
        const keccakHash = utils.keccak256(utils.toUtf8Bytes(event))
        return keccakHash;
      }
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Create a function to encode the parameters">
    Each topic in the topics filter must be a 32-bytes long string, even if the original parameter value is shorter.

    To achieve this, a developer can add zeros in front of the value until it becomes a 32-bytes long string, which is equal to 64 characters (starting with `0x`).

    The `padLeft` in web.js and `hexZeroPad` in ethers.js functions do exactly this.

    <CodeGroup>
      ```js web3.js theme={"system"}
        // Generate 32-bytes size specification
      function encodeTopic(parameter) {
        const encodedParameter = Web3.utils.padLeft(parameter, 64); // 64 characters = 32 bytes encoding
        return encodedParameter;
      }
      ```

      ```js ethers.js theme={"system"}
      // Generate 32-bytes size specification
      function encodeTopic(parameter) {
        const encodedParameter = utils.hexZeroPad(parameter, 32); // 32 bytes
        return encodedParameter;
      }
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Call the functions from a main function">
    Within the `main` function, define the event and parameters to encode, then call the functions with the event and parameter as input.

    You will also find an example of a `topics` array to use in the `eth_getLogs` filter.

    <CodeGroup>
      ```js web3.js theme={"system"}
        // Define the event to encode
        const eventToEncode = 'Transfer(address,address,uint256)';
        const signature = encodeEvent(eventToEncode);

        // Define the topic to encode, an Ethereum address in this case
        const topicToEncode = '0xf5d500B70bfca5987A05Fb4EfcCbfa5E660a81c0';
        const topic = encodeTopic(topicToEncode);

        // Topics array to use in eth_getLogs in the 'topics' field of the filter
        const topics = [signature, topic];
      ```

      ```js ethers.js theme={"system"}
      function main() {

        // Define the event to encode
        const eventToEncode = 'Transfer(address,address,uint256)';
        const signature = encodeEvent(eventToEncode);

        // Define the topic to encode, an Ethereum address in this case
        const topicToEncode = '0xf5d500B70bfca5987A05Fb4EfcCbfa5E660a81c0';
        const topic = encodeTopic(topicToEncode);

        // Topics array to use in eth_getLogs in the 'topics' field of the filter
        const topics = [signature, topic];

        console.log('===== Topics Encoder =====');
        console.log(`Event to track: ${eventToEncode}`);
        console.log(`Event signature: ${signature}`);
        console.log(`Encoded topic: ${topic}\n`);
        console.log('This array filters ERC-20 Transfer events originating from a specific Ethereum address:');
        console.log(topics);
      }
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Log the results">
    The last part of the main function is to log the results.

    <CodeGroup>
      ```js web3.js theme={"system"}
        console.log('===== Topics Encoder =====');
        console.log(`Event to track: ${eventToEncode}`);
        console.log(`Event signature: ${signature}`);
        console.log(`Encoded topic: ${topic}\n`);
        console.log('This array filters ERC-20 Transfer events originating from a specific Ethereum address:');
        console.log(topics);
      }

      main();
      ```

      ```js ethers.js theme={"system"}
        console.log('===== Topics Encoder =====');
        console.log(`Event to track: ${eventToEncode}`);
        console.log(`Event signature: ${signature}`);
        console.log(`Encoded topic: ${topic}\n`);
        console.log('This array filters ERC-20 Transfer events originating from a specific Ethereum address:');
        console.log(topics);
      }

      main();
      ```
    </CodeGroup>
  </Accordion>
</AccordionGroup>

<RequestExample>
  ```js web3.js theme={"system"}
  const Web3 = require('web3');

    // Generate event signature using keccak256 hash algorithm
  function encodeEvent(event) {
    const keccakHash = Web3.utils.keccak256(event);
    return keccakHash;
  }

    // Generate 32-bytes size specification
  function encodeTopic(parameter) {
    const encodedParameter = Web3.utils.padLeft(parameter, 64); // 64 characters = 32 bytes encoding
    return encodedParameter;
  }

  function main() {

    // Define the event to encode
    const eventToEncode = 'Transfer(address,address,uint256)';
    const signature = encodeEvent(eventToEncode);

    // Define the topic to encode, an Ethereum address in this case
    const topicToEncode = '0xf5d500B70bfca5987A05Fb4EfcCbfa5E660a81c0';
    const topic = encodeTopic(topicToEncode);

    // Topics array to use in eth_getLogs in the 'topics' field of the filter
    const topics = [signature, topic];

    console.log('===== Topics Encoder =====');
    console.log(`Event to track: ${eventToEncode}`);
    console.log(`Event signature: ${signature}`);
    console.log(`Encoded topic: ${topic}\n`);
    console.log('This array filters ERC-20 Transfer events originating from a specific Ethereum address:');
    console.log(topics);
  }

  main();
  ```

  ```js ethers.js theme={"system"}
  const utils  = require('ethers');

  // Generate event signature using keccak256 hash algorithm
  function encodeEvent(event) {
    const keccakHash = utils.keccak256(utils.toUtf8Bytes(event))
    return keccakHash;
  }

  // Generate 32-bytes size specification
  function encodeTopic(parameter) {
    const encodedParameter = utils.hexZeroPad(parameter, 32); // 32 bytes
    return encodedParameter;
  }

  function main() {

    // Define the event to encode
    const eventToEncode = 'Transfer(address,address,uint256)';
    const signature = encodeEvent(eventToEncode);

    // Define the topic to encode, an Ethereum address in this case
    const topicToEncode = '0xf5d500B70bfca5987A05Fb4EfcCbfa5E660a81c0';
    const topic = encodeTopic(topicToEncode);

    // Topics array to use in eth_getLogs in the 'topics' field of the filter
    const topics = [signature, topic];

    console.log('===== Topics Encoder =====');
    console.log(`Event to track: ${eventToEncode}`);
    console.log(`Event signature: ${signature}`);
    console.log(`Encoded topic: ${topic}\n`);
    console.log('This array filters ERC-20 Transfer events originating from a specific Ethereum address:');
    console.log(topics);
  }

  main();
  ```
</RequestExample>

<ResponseExample>
  ```bash theme={"system"}
  $ node web3

  ===== Topics Encoder =====
  Event to track: Transfer(address,address,uint256)
  Event signature: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
  Encoded topic: 0x000000000000000000000000f5d500B70bfca5987A05Fb4EfcCbfa5E660a81c0

  This array filters ERC-20 Transfer events originating from a specific Ethereum address:
  [
    '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
    '0x000000000000000000000000f5d500B70bfca5987A05Fb4EfcCbfa5E660a81c0'
  ]
  ```
</ResponseExample>
