đŸĒ™Multiple ERC20s or NFTs

Learn how to fetch the list of common token holders of multiple ERC20 tokens or NFTs (ERC721s & ERC1155s).

Airstack provides easy-to-use APIs for enriching dapps and integrating on-chain and off-chain data from various blockchains.

Table Of Contents

In this guide you will learn how to use Airstack to:

Pre-requisites

  • An Airstack account

  • Basic knowledge of GraphQL

Get Started

JavaScript/TypeScript/Python

If you are using JavaScript/TypeScript or Python, Install the Airstack SDK:

React

npm install @airstack/airstack-react

Node

npm install @airstack/node

Then, add the following snippets to your code:

import { init, useQuery } from "@airstack/airstack-react";

init("YOUR_AIRSTACK_API_KEY");

const query = "YOUR_QUERY"; // Replace with GraphQL Query

const Component = () => {
  const { data, loading, error } = useQuery(query);

  if (loading) {
    return <p>Loading...</p>;
  }

  if (error) {
    return <p>Error: {error.message}</p>;
  }
};

Other Programming Languages

To access the Airstack APIs in other languages, you can use https://api.airstack.xyz/gql as your GraphQL endpoint.

Best Practices

With nested queries, Airstack finds the intersection of common token holders of multiple ERC20 tokens or NFTs in the following order:

  1. Filtering token holders on the 1st outermost query

  2. Comparing token holders of 1st outermost query against the token holders on 2nd outermost query

  3. Comparing token holders of the 1st and 2nd outermost query against the token holders on the 3rd outermost query

  4. Comparing token holders of 1st, 2nd, ..., nth outermost query against the token holders on (n + 1)-th outermost query

Since the number of objects returned in the responses will be dependent on the number of token holders on the 1st outermost query, it's most efficient that you have the token with the least amount of holders on the 1st outermost query.

Suppose there are two tokens:

  • Token A: 100,000 holders

  • Token B: 1,000 holders.

If Token A is the input on the 1st outermost query, then the end result will be 100,000 objects in the response array.

On the other hand, if Token B is the input on the 1st outermost query, then the end result will be instead ONLY 1,000 objects in the response array.

The latter approach will be more efficient and easier for further formatting.

Common Holders of 2 ERC20 Tokens

Fetching

You can fetch the common holders of two given ERC20, e.g. USDT and USDC:

Try Demo

Code

query GetCommonHoldersOfUSDTAndUSDC {
  TokenBalances(input: {filter: {tokenAddress: {_eq: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"}}, blockchain: ethereum, limit: 200}) {
    TokenBalance {
      owner {
        tokenBalances(input: {filter: {tokenAddress: {_eq: "0xdAC17F958D2ee523a2206206994597C13D831ec7"}}, limit: 200}) {
          owner {
            addresses
          }
        }
      }
    }
  }
}

All the common holders' addresses will be returned inside the innermost owner.addresses field.

Formatting

To get the list of all holders in a flat array, use the following format function:

const formatFunction = (data) =>
  data?.TokenBalances?.TokenBalance?.map(
    ({ owner }) => owner?.tokenBalances?.[0]?.owner?.addresses
  )
    .filter(Boolean)
    .flat(1)
    .filter((address, index, array) => array.indexOf(address) === index) ?? [];

The final result will the the list of all common holders in an array:

[
  "0xc77d249809ae5a118eef66227d1a01a3d62c82d4",
  "0x3291e96b3bff7ed56e3ca8364273c5b4654b2b37",
  "0xe348c7959e47646031cea7ed30266a6702d011cc",
  // ...other token holders
  "0xa69babef1ca67a37ffaf7a485dfff3382056e78c",
  "0x46340b20830761efd32832a74d7169b29feb9758",
  "0x2008b6c3d07b061a84f790c035c2f6dc11a0be70"
]

Common Holders of 2 NFTs

Fetching

You can fetch the common holders of two given NFTs, e.g. BAYC and Moonbirds:

Try Demo

Code

query GetCommonHoldersOfBAYCAndMoonBirds {
  TokenBalances(
    input: {
      filter: {
        tokenAddress: { _eq: "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D" }
      }
      blockchain: ethereum
      limit: 200
    }
  ) {
    TokenBalance {
      owner {
        tokenBalances(
          input: {
            filter: {
              tokenAddress: {
                _eq: "0x23581767a106ae21c074b2276D25e5C3e136a68b"
              }
            }
            limit: 200
          }
        ) {
          owner {
            addresses
          }
          tokenAddress
          tokenId
        }
      }
    }
  }
}

All the common holders' addresses will be returned inside the innermost owner.addresses field and tokenId is optional for determining which NFT is specifically held by the user as there can be multiple NFTs held by a single user.

Formatting

To get the list of all holders in a flat array, use the following format function:

const formatFunction = (data) =>
  data?.TokenBalances?.TokenBalance?.map(
    ({ owner }) => owner?.tokenBalances?.[0]?.owner?.addresses
  )
    .filter(Boolean)
    .flat(1)
    .filter((address, index, array) => array.indexOf(address) === index) ?? [];

The final result will the the list of all common holders in an array:

[
  "0xc77d249809ae5a118eef66227d1a01a3d62c82d4",
  "0x3291e96b3bff7ed56e3ca8364273c5b4654b2b37",
  "0xe348c7959e47646031cea7ed30266a6702d011cc",
  // ...other token holders
  "0xa69babef1ca67a37ffaf7a485dfff3382056e78c",
  "0x46340b20830761efd32832a74d7169b29feb9758",
  "0x2008b6c3d07b061a84f790c035c2f6dc11a0be70"
]

Common Holders of NFT That Held A Minimum Amount of ERC20 Token

Fetching

You can fetch common holders of an NFT with a specific amount held for the ERC20, e.g. Moonbirds holders with more than 10 USDT:

Try Demo

Code

query GetCommonHoldersOfMoonbirdsAndMoreThanTenUSDT {
  TokenBalances(input: {filter: {tokenAddress: {_eq: "0x23581767a106ae21c074b2276D25e5C3e136a68b"}}, blockchain: ethereum, limit: 200}) {
    TokenBalance {
      owner {
        tokenBalances(
          input: {
            filter: {
              tokenAddress: {_eq: "0xdAC17F958D2ee523a2206206994597C13D831ec7"},
              formattedAmount: {_gt: 10}
            },
            limit: 200
          }
        ) {
          owner {
            addresses
          }
        }
      }
    }
  }
}

All the common holders' addresses will be returned inside the innermost owner.addresses field.

Formatting

To get the list of all holders in a flat array, use the following format function:

const formatFunction = (data) =>
  data?.TokenBalances?.TokenBalance?.map(
    ({ owner }) => owner?.tokenBalances?.[0]?.owner?.addresses
  )
    .filter(Boolean)
    .flat(1)
    .filter((address, index, array) => array.indexOf(address) === index) ?? [];

The final result will the the list of all common holders in an array:

[
  "0xc77d249809ae5a118eef66227d1a01a3d62c82d4",
  "0x3291e96b3bff7ed56e3ca8364273c5b4654b2b37",
  "0xe348c7959e47646031cea7ed30266a6702d011cc",
  // ...other token holders
  "0xa69babef1ca67a37ffaf7a485dfff3382056e78c",
  "0x46340b20830761efd32832a74d7169b29feb9758",
  "0x2008b6c3d07b061a84f790c035c2f6dc11a0be70"
]

Common Holders of A Token on Ethereum and A Token on Base (Cross-Chain)

Fetching

You can fetch common holders of NFT from different chains, e.g. BAYC on Ethereum and BasePaint on Base:

Try Demo

Code

query GetCommonHoldersOfBAYCAndCuddleVerse {
  TokenBalances(input: {filter: {tokenAddress: {_eq: "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D"}}, blockchain: ethereum, limit: 200}) {
    TokenBalance {
      owner {
        tokenBalances(input: {filter: {tokenAddress: {_eq: "0xba5e05cb26b78eda3a2f8e3b3814726305dcac83"}}, blockchain: base, limit: 200}) {
          owner {
            addresses
          }
          tokenId
        }
      }
    }
  }
}

All the common holders' addresses will be returned inside the innermost owner.addresses field.

Formatting

To get the list of all holders in a flat array, use the following format function:

const formatFunction = (data) =>
  data?.TokenBalances?.TokenBalance?.map(
    ({ owner }) => owner?.tokenBalances?.[0]?.owner?.addresses
  )
    .filter(Boolean)
    .flat(1)
    .filter((address, index, array) => array.indexOf(address) === index) ?? [];

The final result will the the list of all common holders in an array:

[
  "0x81b55fbe66c5ffbb8468328e924af96a84438f14",
  "0xb45cde30c957939fe6c06a6e14570f01e8b9b8cf",
  "0x001fd093d89b24f7de35bc47b6d01c750f398707",
  "0x0c1e99991dd2f7d374bff13f9f52284ce6cfdae5",
  "0xe53ebe8ded621a3e5a1789bbd2605378f8591c87"
  // ...other token holders
]

Common Holders of More Than 2 ERC20 Tokens or NFTs

Fetching

Fetching common holders for more than 2 ERC20 tokens or NFTs works the same way as fetching only 2 ERC20 tokens or NFTs with the addition of more token address parameters and nesting:

Try Demo

Code

query GetCommonHoldersOfMoreThanTwoTokensOrNfts {
  TokenBalances(
    input: {filter: {tokenAddress: {_eq: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"}}, blockchain: ethereum, limit: 200}
  ) {
    TokenBalance {
      owner {
        tokenBalances(
          input: {filter: {tokenAddress: {_eq: "0xdAC17F958D2ee523a2206206994597C13D831ec7"}}, limit: 200}
        ) {
          owner {
            tokenBalances(
              input: {filter: {tokenAddress: {_eq: "0x2791bca1f2de4661ed88a30c99a7a9449aa84174"}}, limit: 200, blockchain: base}
            ) {
              owner {
                addresses
              }
            }
          }
        }
      }
    }
  }
}

All the common holders' addresses will be returned inside the innermost owner.addresses field.

Formatting

To get the list of all holders in a flat array, use the following format function:

const formatFunction = (data) =>
  data?.TokenBalances?.TokenBalance?.map(
    ({ owner }) =>
      owner?.tokenBalances?.[0]?.owner?.tokenBalances?.[0]?.owner?.addresses
  )
    .filter(Boolean)
    .flat(1)
    .filter((address, index, array) => array.indexOf(address) === index) ?? [];

The final result will the the list of all common holders in an array:

[
  "0xc77d249809ae5a118eef66227d1a01a3d62c82d4",
  "0x3291e96b3bff7ed56e3ca8364273c5b4654b2b37",
  "0xe348c7959e47646031cea7ed30266a6702d011cc",
  // ...other token holders
  "0xa69babef1ca67a37ffaf7a485dfff3382056e78c",
  "0x46340b20830761efd32832a74d7169b29feb9758",
  "0x2008b6c3d07b061a84f790c035c2f6dc11a0be70"
]

Developer Support

If you have any questions or need help regarding fetching token holders of multiple ERC20s or NFTs, please join our Airstack's Telegram group.

More Resources

Last updated

Was this helpful?