理解 Solana 账户模型,获取 Token 所有持有者
在本指南中,我们将看看如何获取诸如 USDC 之类的同质化Token的所有持有者。这在你想要跟踪Token持有者或奖励持有者进行空投的情况下非常有用。
让我们首先看看Token,特别是在 Solana 上如何工作。当开发人员创建一个Token时,他们使用Token程序(Token Program)来创建一个铸造账户。这个铸造账户保存了关于特定 Token 的信息,比如名称、Token地址和图像。一旦铸造账户被创建,Token 就可以被铸造并存储在一个 Token 账户中。Token账户是一个账户,保存了关于特定Token的信息,由特定地址拥有。Token账户将包括铸造地址(对应下图的Token Address)、所有者地址以及账户中特定Token的数量等细节。例如,持有一些 USDC(一个 SPL Token )的地址将拥有一个 USDC 的Token账户。
账户分解图
现在我们了解了Token和Token账户的工作原理,我们可以看看如何获取给定Token的所有Token持有者。持有特定Token的每个钱包都将拥有该 Token的Token账户。这意味着 Token 与持有该Token 钱包的 Token账户 相关联。这就是我们将找出所有持有者的方式。如果我们能找到一种方法来获取与一个Token相关联的所有Token账户,然后获取这些账户的所有者,我们将得到一个所有持有者的列表!
译者备注:与以太坊不同,在以太坊中用户的Token余额保存在 Token合约中,在 Solana 中,每个钱包账号持有的余额单独保存的 Token 账户。在 Solana 中甚至没有单独的Token合约, 而是使用Token 的铸造地址来区分不同的 Token。
幸运的是,Helius getTokenAccounts API 方法允许我们精确地做到这一点。我们可以在 API 调用参数中包含任何Token的铸造地址,我们将得到一个包含为该Token创建的所有Token账户的列表。除此之外,API 还返回每个Token账户的所有者;这个所有者通常被我们称为Token持有者。需要注意的一件小事是,一个账户可以拥有同一个Token的多个Token账户。这不是一个大问题;我们只需要设置一些逻辑来处理共享所有者的Token账户。
现在让我们深入一些代码,看看我们实际上如何做到这一点。你需要一个 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");
接下来,我们将创建一个方法来获取与特定Token相关联的所有Token账户。我们可以通过创建一个名为 findHolders 的方法来开始,该方法将使用 getTokenAccounts 方法来获取所需的数据。你可以在这里了解更多关于getTokenAccounts方法的信息。需要注意的一件重要的事情是,每次对 API 的调用只能返回最多 1000 个Token账户。Solana 上的大多数大型Token都有超过 100,000 个Token账户。为了解决这个问题,我们将使用分页来浏览所有Token账户,并继续进行 API 调用,直到我们获取了所有现有Token账户的数据。在这个方法中,我们将在getTokenAccounts调用的参数中包含Token铸造账号。当我们遍历所有Token账户时,我们将把每个唯一的Token账户所有者添加到一个列表中。一旦方法运行完成,我们将把这个列表保存到一个包含所有Token持有者的JSON文件中。
const findHolders = async () => {
// Pagination logic
let page = 1;
// allOwners will store all the addresses that hold the token
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: {},
//我们关注的token 铸币地址
mint: "CKfatsPMUf8SkiURsDXs7eK6GWb4Jsd6UDbs7twMCWxo",
},
}),
});
const data = await response.json();
// Pagination logic.
if (!data.result || data.result.token_accounts.length === 0) {
console.log(`No more results. Total pages: ${page - 1}`);
break;
}
console.log(`Processing results from page ${page}`);
// Adding unique owners to a list of token owners.
data.result.token_accounts.forEach((account) =>
allOwners.add(account.owner)
);
page++;
}
fs.writeFileSync(
"output.json",
JSON.stringify(Array.from(allOwners), null, 2)
);
};
Copy
在上面的示例中,getTokenAccounts方法在分页浏览所有Token账户时被多次调用。API 响应将为每个Token账户提供以下数据:
{
"address": "CVMR1nbxTcQ7Jpa1p137t5TyKFii3Y7Vazt9fFct3tk9",
"mint": "SHDWyBxihqiCj6YekG2GUr7wqKLeLAMK1gHZck9pL6y",
"owner": "CckxW6C1CjsxYcXSiDbk7NYfPLhfqAm3kSB5LEZunnSE",
"amount": 100000000,
"delegated_amount": 0,
"frozen": false
},
我们从这些 Token 账户中提取了所有者,并将其添加到我们的列表中。如果我们愿意,我们还可以存储每个Token账户持有的Token数量,以找出最大的持有者。
现在一旦这个操作完成,我们需要做的就是调用这个方法:
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",
},
}),
});
const data = await response.json();
if (!data.result || data.result.token_accounts.length === 0) {
console.log(`No more results. Total pages: ${page - 1}`);
break;
}
console.log(`Processing results from page ${page}`);
data.result.token_accounts.forEach((account) =>
allOwners.add(account.owner)
);
page++;
}
fs.writeFileSync(
"output.json",
JSON.stringify(Array.from(allOwners), null, 2)
);
};
findHolders();
我们代码的输出将是所有持有者的列表,看起来类似于这样:
[
"111An9SVxuPpgjnuXW9Ub7hcVmZpYNrYZF4edsGwJEW",
"11Mmng3DoMsq2Roq8LBcqdz6d4kw9oSD8oka9Pwfbj",
"112uNfcC8iwX9P2TkRdJKyPatg6a4GNcr9NC5mTc2z3",
"113uswn5HNgEfBUKfK4gVBmd2GpZYbxd1N6h1uUWReg",
"11CyvpdYTqFmCVWbJJeKFNX8F8RSjNSYW5VVUi8eX4P",
"11MANeaiHEy9S9pRQNu3nqKa2gpajzX2wrRJqWrf8dQ",
…
]
你可以通过我们的 replit 示例来测试这一点。
总结以下,我们成功地介绍了通过 Helius getTokenAccounts API 来识别 Solana Token持有者的过程。这个步骤应该为你提供必要的技能,直接与你的Token社区进行互动。
原文:https://www.helius.dev/blog/how-to-get-token-holders-on-solana
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!