Skip to content

feat: dynamic eventFilters for wildcard handlers (cross-contract address sharing) #1201

Description

@cristianizzo

Summary

For wildcard handlers (e.g. ERC20.Transfer, ERC721.Transfer), allow eventFilters to be a function whose addresses argument comes from a different contract's dynamically-registered set — so HyperSync can pre-filter at the source instead of every event reaching the handler.

Use case

Indexing every Aragon DAO across Ethereum mainnet plus tracking each DAO's treasury (every ERC-20 / ERC-721 transfer where from or to is a DAO).

DAOs are discovered dynamically via DAORegistered and registered with:

indexer.onEvent({ contract: "DAORegistry", event: "DAORegistered" }, async ({ event, context }) => {
  context.chain.DAO.add(event.params.dao);
});

Treasury currently uses a wildcard ERC20.Transfer handler that filters at handler-time:

indexer.onEvent(
  { contract: "ERC20", event: "Transfer", wildcard: true },
  async ({ event, context }) => {
    const [fromDao, toDao] = await Promise.all([
      context.Dao.get(daoId(event.chainId, event.params.from)),
      context.Dao.get(daoId(event.chainId, event.params.to)),
    ]);
    if (!fromDao && !toDao) return;
    // ...record Transaction + update Asset balance
  },
);

Every Transfer on every ERC-20 in Ethereum history reaches this handler just to drop the vast majority via the Dao.get early-return.

Desired API

eventFilters as a function on a wildcard handler, with addresses populated from the dynamically-registered set of another contract:

indexer.onEvent(
  {
    contract: "ERC20",
    event: "Transfer",
    wildcard: true,
    eventFilters: ({ addresses }) => [
      { from: addresses },   // transfers FROM a DAO
      { to:   addresses },   // OR to a DAO
    ],
    // optional: name the contract whose registered addresses feed `addresses`
    eventFiltersAddressSource: "DAO",
  },
  async ({ event, context }) => { /* same as today, but only DAO-touching transfers reach here */ },
);

ERC20.Transfer.eventFilters already accepts { from?, to? } in the typed surface (.envio/types.d.ts); the missing piece is letting the function form work on wildcard handlers and pointing it at another contract's address registry.

Open questions

  1. How should the cross-contract address source be expressed? An explicit field like eventFiltersAddressSource: "DAO", or a different mechanism?
  2. Any preview / alpha branch we can test against with a real Ethereum-mainnet workload?

Happy to validate a preview build against our indexer if useful.

Activity

  1. DZakh commented on May 14, 2026

    @DZakh
    Member

    Thanks for the issue. No eta for this, but here's a tip:

    You can get all contract addresses for the contract in the following way, instead of reading the DAO entity from the database.

    indexer.chains[event.chainId].DAO.addresses
    
  2. added theissue type on May 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions