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

# Measuring token holder concentration (Gini & HHI)

> Compute Gini and HHI concentration metrics for any token's holders with the GoldRush token_holders_v2 endpoint, and how it compares to Etherscan's token holder API.

## The use case

Two questions come up constantly in token research, risk scoring, and airdrop design:

* **How concentrated is this token?** A handful of wallets controlling most of the supply is a governance and liquidity risk.
* **Is it getting more or less concentrated over time?** Concentration trending up after an unlock or an airdrop is a red flag.

Two standard metrics answer this:

* **Gini coefficient**: inequality across all holders. `0` means every holder owns an equal amount; `1` means a single wallet owns everything.
* **HHI (Herfindahl-Hirschman Index)**: the sum of squared ownership shares. It ranges from `1/N` (perfectly even across `N` holders) to `1` (one holder owns everything), and it is dominated by the largest holders, so it is the sharper "whale detector" of the two.

Both metrics need the same raw inputs, for **every** holder of the token:

* the holder's **balance**,
* the token's **total supply** (to turn balances into ownership shares),
* the **holder count** (`N`),
* and, ideally, the ability to pull all of the above **as of a past block** so you can chart the trend.

This guide computes both metrics with the GoldRush [Get token holders (v2)](/api-reference/foundational-api/balances/get-token-holders-as-of-any-block-height-v2) endpoint, then compares the approach to Etherscan's token holder API.

## The formulas

With holder balances `bᵢ` and shares `sᵢ = bᵢ / Σ bⱼ`:

* **HHI** `= Σ sᵢ²`
* **Gini** `= Σᵢ (2i − N − 1) · b₍ᵢ₎ / (N · Σ b₍ⱼ₎)`, where `b₍ᵢ₎` are balances sorted ascending and `i` runs from `1` to `N`.

Worked sanity check for three holders owning `[20, 30, 50]`: shares are `[0.2, 0.3, 0.5]`, so **HHI = 0.04 + 0.09 + 0.25 = 0.38** and **Gini = 0.20**.

## What you need from an API

| Requirement            | Why it matters                                                                         |
| ---------------------- | -------------------------------------------------------------------------------------- |
| Every holder's balance | Both metrics are sums over all holders, so a truncated list understates concentration. |
| Total supply           | Converts raw balances into ownership shares.                                           |
| Holder count (`N`)     | Sets the HHI floor (`1/N`) and normalizes the Gini.                                    |
| Point-in-time holders  | Required to chart concentration over time, not just today.                             |

## Fetching holders and computing Gini & HHI with GoldRush

The [GoldRush TypeScript SDK](/goldrush-sdks) exposes `getTokenHoldersV2ForTokenAddress` as an async iterator that pages through **all** holders for you. Each item carries `balance`, `total_supply`, and `contract_decimals` inline, so you never need a second request to normalize the data.

<CodeGroup>
  ```typescript Gini & HHI theme={null}
  import { GoldRushClient } from "@covalenthq/client-sdk";

  const client = new GoldRushClient("<GOLDRUSH_API_KEY>");

  // Pull every holder. The SDK auto-paginates via the async iterator;
  // page-size 1000 (the max) keeps the number of round-trips low.
  async function getAllBalances(chain: string, token: string) {
    const balances: number[] = [];
    let totalSupply = 0;
    let decimals = 0;

    for await (const page of client.BalanceService.getTokenHoldersV2ForTokenAddress(
      chain,
      token,
      { pageSize: 1000 },
    )) {
      if (page.error) throw new Error(page.error_message);
      for (const holder of page.data.items ?? []) {
        decimals = holder.contract_decimals ?? 0;
        totalSupply = Number(holder.total_supply);          // returned inline
        balances.push(Number(holder.balance) / 10 ** decimals);
      }
    }
    return { balances, totalSupply: totalSupply / 10 ** decimals };
  }

  function hhi(values: number[]): number {
    const sum = values.reduce((a, b) => a + b, 0);
    if (sum === 0) return 0;
    return values.reduce((acc, v) => acc + (v / sum) ** 2, 0);
  }

  function gini(values: number[]): number {
    const xs = [...values].sort((a, b) => a - b);
    const n = xs.length;
    const sum = xs.reduce((a, b) => a + b, 0);
    if (n === 0 || sum === 0) return 0;
    let weighted = 0;
    for (let i = 0; i < n; i++) weighted += (2 * (i + 1) - n - 1) * xs[i];
    return weighted / (n * sum);
  }

  const { balances, totalSupply } = await getAllBalances(
    "eth-mainnet",
    "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", // USDC
  );

  // Optional: share of total supply held by the top 10 holders.
  const top10 =
    [...balances].sort((a, b) => b - a).slice(0, 10).reduce((a, b) => a + b, 0) /
    totalSupply;

  console.log({
    holders: balances.length,
    gini: gini(balances).toFixed(4),
    hhi: hhi(balances).toFixed(6),
    top10ShareOfSupply: (top10 * 100).toFixed(2) + "%",
  });
  ```

  ```typescript Concentration over time theme={null}
  // Pass block-height (or date) to snapshot holders in the past, then
  // recompute the same metrics to build a time series. Historical holders
  // are supported on Foundational Chains.
  async function giniAtBlock(chain: string, token: string, blockHeight: number) {
    const balances: number[] = [];
    for await (const page of client.BalanceService.getTokenHoldersV2ForTokenAddress(
      chain,
      token,
      { pageSize: 1000, blockHeight },
    )) {
      if (page.error) throw new Error(page.error_message);
      for (const holder of page.data.items ?? []) {
        const decimals = holder.contract_decimals ?? 0;
        balances.push(Number(holder.balance) / 10 ** decimals);
      }
    }
    return gini(balances);
  }

  const blocks = [18_000_000, 19_000_000, 20_000_000];
  const series = await Promise.all(
    blocks.map(async (b) => ({ block: b, gini: await giniAtBlock("eth-mainnet", "0xa0b8...eb48", b) })),
  );
  console.table(series);
  ```
</CodeGroup>

<Note>
  `balance` and `total_supply` are returned as raw strings in the token's base units. The examples divide by `10 ^ contract_decimals` for readability; for tokens whose supply exceeds JavaScript's safe-integer range, sum the raw values with `BigInt` before taking ratios if you need exact precision.
</Note>

## The Etherscan approach

Etherscan exposes the equivalent data through `tokenholderlist` (module `token`, action `tokenholderlist`), paginated with `page` and `offset`:

```bash theme={null}
curl "https://api.etherscan.io/api?module=token&action=tokenholderlist\
&contractaddress=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48\
&page=1&offset=1000&apikey=<KEY>"
```

Each row returns only `TokenHolderAddress` and `TokenHolderQuantity`. To compute Gini or HHI you then have to:

* fetch the **total supply separately** (the `stats/tokensupply` endpoint), since it is not in the holder response;
* apply the token's **decimals separately** (also not in the holder response);
* accept that the list is **current holders only**, with no way to snapshot holders at a past block, so a concentration-over-time chart is not possible from this endpoint.

Note also that `tokenholderlist` and `tokenholdercount` are **PRO endpoints**, available only on Etherscan's paid Standard plan and above.

## Side-by-side

| For a Gini/HHI pipeline            | GoldRush `token_holders_v2`    | Etherscan `tokenholderlist`      |
| ---------------------------------- | ------------------------------ | -------------------------------- |
| Total supply in the same response  | ✅ `total_supply` on every item | ❌ separate `tokensupply` call    |
| Decimals in the same response      | ✅ `contract_decimals`          | ❌ separate lookup                |
| Holder count (`N`)                 | ✅ `pagination.total_count`     | Separate `tokenholdercount` call |
| Point-in-time (historical) holders | ✅ `block-height` / `date`      | ❌ current only                   |
| Max page size                      | 1000                           | 1000                             |
| Auto-pagination in the SDK         | ✅ async iterator               | ❌ manual `page`/`offset` loop    |
| Multichain under one key           | ✅ 100+ chains                  | Per-chain access                 |
| Access tier                        | Included (0.02 credits/item)   | PRO (paid) endpoint              |

## Where GoldRush pulls ahead

1. **One response has everything the math needs.** `balance`, `total_supply`, and `contract_decimals` arrive together, so shares are a one-line calculation, with no second request and no separate supply/decimals bookkeeping.
2. **Concentration over time, not just a snapshot.** `block-height` and `date` let you recompute Gini/HHI at any historical point on [Foundational Chains](https://goldrush.dev/chains/) and chart the trend across unlocks, airdrops, and listings.
3. **`N` comes for free.** `pagination.total_count` gives the holder count in the same call, so the HHI floor (`1/N`) and Gini normalization need no extra request.
4. **Fewer round-trips.** A page size of 1000 plus SDK auto-pagination enumerates every holder with minimal code.
5. **Same shape across 100+ chains.** One API key and one code path cover Ethereum, Polygon, BSC, Base, Arbitrum, and more.

## Where to start

<CardGroup cols={2}>
  <Card title="Get token holders (v2)" href="/api-reference/foundational-api/balances/get-token-holders-as-of-any-block-height-v2">
    Full parameter and response reference for the endpoint used above, including historical `block-height` and `date` queries.
  </Card>

  <Card title="Foundational API quickstart" href="/goldrush-foundational-api/quickstart">
    Install the TypeScript SDK and make your first authenticated call in minutes.
  </Card>

  <Card title="Estimate your cost" href="/pricing-calculator?endpoint=%2Fapi-reference%2Ffoundational-api%2Fbalances%2Fget-token-holders-as-of-any-block-height-v2">
    Project the monthly cost of pulling full holder lists at 0.02 credits per item.
  </Card>

  <Card title="Supported chains" href="/goldrush-foundational-api/supported-chains">
    See which chains support the latest snapshot and which support historical holder queries.
  </Card>
</CardGroup>
