如何查询Solana代币持有者

如何查询Solana代币持有者
一键发币: SUI | SOL | BNB | ETH | BASE | ARB | OP | POLYGON | AVAX | FTM | OK

在这份指南中,我们将探讨如何获取一种可替代代币(例如USDC)的所有持有者。这在你希望跟踪代币持有者或通过空投奖励持有者时非常有用。

1、概览

首先,让我们了解一下Solana上的代币,特别是非同质化代币的工作原理。

当开发者创建一个代币时,他们使用代币程序来创建一个铸币账户。这个铸币账户包含了特定代币的信息,如名称、代币地址和图像。一旦铸币账户被创建,代币就可以被铸造并存储在一个代币账户中。

代币账户是一个包含特定代币信息的账户,这些信息由特定地址拥有。这将包括铸币地址、所有者地址以及账户中的特定代币数量。例如,一个持有某些USDC(一个SPL代币)的地址将有一个USDC的代币账户。

账户分解图
账户分解图

现在我们已经了解了代币和代币账户的工作原理,我们可以查看给定代币的所有代币持有者。每个持有特定代币的钱包都会有一个该代币的代币账户。这意味着这个代币将与所有持有该代币的钱包的代币账户相关联。这就是我们将如何找出所有持有者的方式。如果我们能找到一种方法来获取与某个代币相关的所有代币账户,然后获取这些账户的所有者,我们就能得到一份所有持有者的列表!

2、getTokenAccounts 方法

幸运的是,Helius getTokenAccounts API 方法允许我们精确地做到这一点。我们可以将任何代币的铸币地址包含在API调用的参数中,并将返回一个包含为该代币创建的所有代币账户的列表。

除此之外,API还会返回每个代币账户的所有者;这个所有者就是我们通常所说的代币持有者。需要注意的一点是,一个账户可以有多个相同代币的代币账户。这不是大问题;我们需要设置一些逻辑来处理共享所有者的代币账户。

3、代码实现

现在让我们深入代码,看看如何实际做到这一点。你需要一个Helius API密钥才能继续。你可以访问https://dev.helius.xyz并注册一个帐户以免费获得一个。首先,我们需要创建一个名为getTokenHolders.js的JavaScript文件。我们可以通过添加Helius URL并导入fs库来保存结果到一个JSON文件开始。

const url = `https://mainnet.helius-rpc.com/?api-key=`;
const fs = require("fs");

接下来,我们将创建一个方法来获取与特定代币关联的所有代币账户。我们可以通过创建一个名为findHolders的方法开始,该方法将使用getTokenAccounts方法来获取所需的数据。您可以在此处了解更多关于getTokenAccounts方法的信息这里

需要注意的重要一点是,每次调用API只能返回最多1000个代币账户。Solana上大多数大型代币都有超过100,000个代币账户。为了绕过这个问题,我们将使用分页来遍历所有代币账户,并继续进行API调用直到获取到所有现有代币账户的相关数据。

在方法中,我们将把代币铸币地址包含在getTokenAccounts调用的参数中。当我们遍历所有代币账户时,我们将每个唯一的代币账户所有者添加到一个列表中。一旦方法运行完毕,我们将把这个列表保存到一个JSON文件中,其中包含所有代币的持有者。

const findHolders = async () => {
  // 分页逻辑
  let page = 1;
  // allOwners 将存储持有代币的所有地址
  let allOwners = new Set();

  while (true) {
    const response = await fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        jsonrpc: "2.0",
        method: "getTokenAccounts",
        id: "helius-test",
        params: {
          page: page,
          limit: 1000,
          displayOptions: {},
          // 我们感兴趣的代币的铸币地址
          mint: "CKfatsPMUf8SkiURsDXs7eK6GWb4Jsd6UDbs7twMCWxo",
        },
      }),
    });

    // 检查响应是否有错误
    if (!response.ok) {
      console.log(
        `Error: ${response.status}, ${response.statusText}`
      );
      break;
    }

    const data = await response.json();
    // 分页逻辑。
    if (!data.result || data.result.token_accounts.length === 0) {
      console.log(`没有更多结果。总页数:${page - 1}`);
      break;
    }
    console.log(`处理第 ${page} 页的结果`);
    // 添加唯一的代币持有者到列表中。
    data.result.token_accounts.forEach((account) =>
      allOwners.add(account.owner)
    );
    page++;
  }

  fs.writeFileSync(
    "output.json",
    JSON.stringify(Array.from(allOwners), null, 2)
  );
};

在上面的例子中,getTokenAccounts方法将在遍历所有代币账户的过程中被多次调用。API响应将为每个代币账户提供以下数据:

{
  "address": "CVMR1nbxTcQ7Jpa1p137t5TyKFii3Y7Vazt9fFct3tk9",
  "mint": "SHDWyBxihqiCj6YekG2GUr7wqKLeLAMK1gHZck9pL6y",
  "owner": "CckxW6C1CjsxYcXSiDbk7NYfPLhfqAm3kSB5LEZunnSE",
  "amount": 100000000,
  "delegated_amount": 0,
  "frozen": false
},

我们从这些代币账户中提取了所有者,并将其添加到了我们的列表中。如果需要,我们还可以存储每个代币账户持有的代币数量,以便确定最大的持有者。

现在完成这些操作后,我们只需调用该方法:

findHolders();

在我们的getTokenHolders.js文件中的完整代码应该如下所示:

const url = `https://mainnet.helius-rpc.com/?api-key=`;
const fs = require("fs");

const findHolders = async () => {
  let page = 1;
  let allOwners = new Set();

  while (true) {
    const response = await fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        jsonrpc: "2.0",
        method: "getTokenAccounts",
        id: "helius-test",
        params: {
          page: page,
          limit: 1000,
          displayOptions: {},
          mint: "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263",
        },
      }),
    });

    // 检查响应是否有错误
    if (!response.ok) {
      console.log(
        `Error: ${response.status}, ${response.statusText}`
      );
      break;
    }

    const data = await response.json();

    if (!data.result || data.result.token_accounts.length === 0) {
      console.log(`没有更多结果。总页数:${page - 1}`);
      break;
    }
    console.log(`处理第 ${page} 页的结果`);
    data.result.token_accounts.forEach((account) =>
      allOwners.add(account.owner)
    );
    page++;
  }

  fs.writeFileSync(
    "output.json",
    JSON.stringify(Array.from(allOwners), null, 2)
  );
};

findHolders();

4、输出

我们代码的输出将是一个持有者的列表,类似于以下内容:

[
  "111An9SVxuPpgjnuXW9Ub7hcVmZpYNrYZF4edsGwJEW",
  "11Mmng3DoMsq2Roq8LBcqdz6d4kw9oSD8oka9Pwfbj",
  "112uNfcC8iwX9P2TkRdJKyPatg6a4GNcr9NC5mTc2z3",
  "113uswn5HNgEfBUKfK4gVBmd2GpZYbxd1N6h1uUWReg",
  "11CyvpdYTqFmCVWbJJeKFNX8F8RSjNSYW5VVUi8eX4P",
  "11MANeaiHEy9S9pRQNu3nqKa2gpajzX2wrRJqWrf8dQ",
...
]

你可以通过我们的replit示例自行测试此功能。


原文链接:How to Get Token Holders on Solana

DefiPlot翻译整理,转载请标明出处

免责声明:本站资源仅用于学习目的,也不应被视为投资建议,读者在采取任何行动之前应自行研究并对自己的决定承担全部责任。
通过 NowPayments 打赏