Skip to main content

Token Holders and Wallet Balances

Two tools on the Bitquery MCP server answer balance questions for a whole chain. They exist on nine chains under the chain's prefix: tron_, eth_, bsc_, base_, arbitrum_, optimism_, matic_ (Polygon), robinhood_ and arc_.

ToolUse it whenComes back as
<chain>_token_holdersYou need the addresses that hold an asset and do not have them yetOne row per holder with its current balance
<chain>_native_balancesYou already have up to 50 addresses and want each one's current native coin balanceOne row per address

Balances are in the asset's own units, never USD. Decimals gives the scale. Pass the holder addresses to labels_for_addresses to see which are exchanges, bridges or known entities.

Export the holders of an asset​

Ask for the asset by contract address, or by the native coin's name. The agent pages through the list and can write each page to a file.

"Export every Tron address holding at least 1 TRX. Use tron_token_holders with limit 10000, follow Next_Cursor until it is empty, and write each page to holders.csv."

Tron​

tron_token_holders takes token (a TRC-20 contract address starting with T, or TRX for the native coin), min_amount (default 1), limit (up to 10,000 per page) and cursor. Each row carries Holder, Balance, Decimals, Symbol, Status and Next_Cursor.

  • TRC-20 holders come back largest balance first.
  • Native TRX holders come back in address order, not ranked. The native holder set is too large to rank. min_amount is the filter that matters: the default 1 returns holders of 1 TRX or more, and 0 returns every funded address, which is very many pages.
  • Pass Next_Cursor from one page into cursor on the next call, keeping the same token, min_amount and limit. An empty page that still has a Next_Cursor means keep going. An empty Next_Cursor means the list is complete.
  • A holder never appears on two pages, so the pages joined together are the full list.
  • A row with an empty Holder is a status row. Read Status: OK, EMPTY_WINDOW, TOO_LARGE, NO_HOLDERS or BAD_CURSOR. A token with a very long balance history, such as USDT, returns TOO_LARGE.
  • TRC-10 assets are not supported.

A first page for native TRX with limit: 3 looks like this:

HolderBalanceSymbolStatusNext_Cursor
T9yD14Nj9j7xAB4dbGeiX9h8unkKLxmGkn541.821241TRXOKT9yD14Nj9j7xAB4dbGeiX9h8unkP29JXHW
T9yD14Nj9j7xAB4dbGeiX9h8unkKT76qbH3.915384TRXOKT9yD14Nj9j7xAB4dbGeiX9h8unkP29JXHW
T9yD14Nj9j7xAB4dbGeiX9h8unkP29JXHW88.11091TRXOKT9yD14Nj9j7xAB4dbGeiX9h8unkP29JXHW

EVM chains​

<chain>_token_holders takes a token contract address and ranks holders largest first, up to 1,000 per page. min_amount and max_amount bound the balances returned; max_amount is how you look past a burn address that holds most of the supply.

  • days: 0 (the default) ranks every holder over the token's whole history. A very widely held token, such as a major stablecoin, has too much history for that and answers with one TOO_LARGE status row instead of timing out.
  • Then pass days: 30 (or 7). The page ranks the holders whose balance changed in that window, with exact current balances. Holders who did not move the token in the window are absent, so the page is the top of the active holders.
  • Next_Cursor is a date. Pass it as cursor to get the next older window of the same length. No holder appears on two pages, so the top N of all pages merged is the global top N. Window_From and Window_To say which dates a page covers.
  • Holders with a negative recorded balance are dropped and counted in Negative_Balances_Excluded. A balance far above the token's supply is a data artifact, not a whale: check it with token_supply before reporting it.
  • Symbol_NonAscii = 1 flags a symbol with non-ASCII letters. That is normal for CJK or emoji names, and also how a scam token imitates a major one.

Check balances of wallets you already have​

"Here are 50 Tron addresses. Give me each one's current TRX balance and keep only those above 100 TRX."

Pass the addresses in one string separated by |, up to 50 per call. Addresses after the 50th distinct one are ignored, so compare Addresses_Requested with Addresses_Used and split a longer list into several calls. Each row carries Address, Native_Balance, Native_Balance_Raw (the exact integer, in sun or wei) and Balance_As_Of.

Tron​

tron_native_balances sums each address's whole balance history, so a funded wallet that has not moved in years still gets a row. Balance_Inconsistent = 1 marks a rare negative sum, usually a missing or doubled delta in the log; treat that balance as suspect. A set that includes a very busy wallet may be refused on the row budget; split it.

AddressNative_BalanceNative_Balance_RawBalance_As_Of
T9yD14Nj9j7xAB4dbGeiX9h8unkKLxmGkn541.8212415418212412026-08-05T13:57:24Z
T9yD14Nj9j7xAB4dbGeiX9h8unkP29JXHW88.11091881109102022-09-26T10:03:45Z

EVM chains​

<chain>_native_balances reads only balances updated in the last since_days days (default 2, up to 30). A wallet that has not moved its native coin in that window returns no row. Use the same window you used to find the wallets, for example the window of eth_token_senders: an active wallet's balance is always fresh there, and a wider window costs more for no gain.

Large exports​

  • For a file export, pass limit: 10000 on Tron and format: "columnar". Columnar returns the column names once and each row as a list of values, so the same data takes less room.
  • Run the paging loop from a script, or ask the agent to write each page to a file. A chat client may cut off a long result shown inline.
  • Where a GraphQL query is the better fit, for example the top 100 holders of one token with no paging, see the Tron balance API and the Ethereum token holders API.
Build with Bitquery

Ready to run this in production?

Get an API key and run these queries in minutes, or talk to us about plans and enterprise delivery.