如何在Solana中获取钱包持有的所有代币

  • QuickNode
  • 发布于 2024-11-21 15:53
  • 阅读 237

本文介绍了如何使用 Solana 的 getParsedProgramAccounts 方法来查询钱包中所有的代币账户及其余额,提供了详细的代码示例和步骤指南,适合有一定 Solana 基础的开发者使用。

概述

你好,读者们!为了开启 Solana 夏季和当前的白名单元,我们认为深入了解你和你的用户使用 getParsedProgramAccounts 方法的所有Token账户将会很有帮助。该工具方便用于查询 Solana 上的不同程序,包括 Solana SPL Token Account 库。

更喜欢视频讲解?跟随 Noah 学习 如何通过钱包地址获取 Solana Token账户 | QuickCodes

本指南将指导你创建一个简单的脚本,该脚本将查询 Solana 的主网,并返回该钱包拥有的所有Token账户及其账户余额。

你需要的工具

程序:Solana 上的智能合约。在本示例中,我们将使用 SPL Token Program,它定义了 Solana 上可替代和不可替代代币的典型用例。

程序过滤器:许多链上程序查询都会拉取大量数据集,因此,缩小搜索范围非常重要。我们将使用 GetProgramAccountsFilter 类型来帮助我们缩小搜索范围。

设置你的环境

在终端中创建一个新的项目目录和文件,index.ts,命令如下:

mkdir sol-get-accounts
cd sol-get-accounts
echo > index.ts

初始化你的项目:

yarn init --yes

npm init --yes

安装 Solana Web3 依赖:

yarn add @solana/web3.js@1 @solana/spl-token

npm install @solana/web3.js@1 @solana/spl-token

在代码编辑器中打开 index.ts 并添加以下依赖:

import { Connection, GetProgramAccountsFilter } from "@solana/web3.js";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";

建立与 Solana 主网的连接

为了在 Solana 上构建,你需要一个 API 端点来连接网络。你可以使用公共节点或部署和管理自己的基础设施,不过如果你希望获得 8 倍的响应速度,你可以把繁重的工作交给我们。

获取 Solana 主网端点

const rpcEndpoint = 'https://example.solana-mainnet.quiknode.pro/000000/';
const solanaConnection = new Connection(rpcEndpoint);

将你想要查询的钱包定义为字符串:

const walletToQuery = 'YOUR_PUBLIC_KEY'; //示例: vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg

太棒了!我们准备构建我们的代币查询。

创建你的代币账户查询

创建一个新的 async 函数,getTokenAccounts,并要求接受参数 walletsolanaConnection

async function getTokenAccounts(wallet: string, solanaConnection: Connection) {
}

建立过滤器

首先,让我们定义我们的过滤器。我们将使用的过滤器为:

  • dataSize 是用于查找特定大小账户的过滤器。对于代币账户,这个已知的数量是 165。

  • memcmp,或“内存比较”过滤器,用于在账户内缩小我们的搜索范围。具体而言,我们将使用 offset 来确定搜索我们账户的 165 字节中的哪个位置(这是该程序的另一个已知值:拥有者的公钥从 32 开始)和 bytes 来设置我们要查找的内容:在本例中是用户的钱包地址。

  • 关于 SPL 代币账户数据的来源信息可以在 这里 找到。

getTokenAccounts 内部,定义一个名为 filters 的变量。

    const filters:GetProgramAccountsFilter[] = [\
        {\
          dataSize: 165,    //账户的大小(字节)\
        },\
        {\
          memcmp: {\
            offset: 32,     //我们在账户中的查询位置(字节)\
            bytes: wallet,  //我们的搜索标准,一个 base58 编码的字符串\
          }\
        }\
     ];

这应该将我们的查询减少到只搜索由我们的钱包拥有的代币账户。

获取程序账户

现在调用 getParsedProgramAccounts 方法,传入 SPL Token Program ID 和我们的 filters

    const accounts = await solanaConnection.getParsedProgramAccounts(
        TOKEN_PROGRAM_ID,   //SPL Token 程序,new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
        {filters: filters}
    );

之前的调用返回一个包含所有匹配的代币账户的数组,结构如下:

{
    pubkey: PublicKey,      //代币账户公钥
    account: AccountInfo    //包括有关我们的代币账户的信息的对象
}[]

你可以记录 accounts.length 来查看用户拥有多少个代币账户:

console.log(`Found ${accounts.length} token account(s) for wallet ${wallet}.`);

解析结果

构建一个简单的 forEach 循环来迭代我们的结果并记录我们的结果。在你的 getTokenAccounts 函数中添加:

    accounts.forEach((account, i) => {
        //解析账户数据
        const parsedAccountInfo:any = account.account.data;
        const mintAddress:string = parsedAccountInfo["parsed"]["info"]["mint"];
        const tokenBalance: number = parsedAccountInfo["parsed"]["info"]["tokenAmount"]["uiAmount"];
        //记录结果
        console.log(`Token Account No. ${i + 1}: ${account.pubkey.toString()}`);
        console.log(`--Token Mint: ${mintAddress}`);
        console.log(`--Token Balance: ${tokenBalance}`);
    });

运行你的代码

最后,调用 getTokenAccounts(walletToQuery,solanaConnection)。你的最终脚本应如下所示:

import { Connection, GetProgramAccountsFilter } from "@solana/web3.js";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";

const rpcEndpoint = 'https://example.solana-mainnet.quiknode.pro/000000/';
const solanaConnection = new Connection(rpcEndpoint);

const walletToQuery = 'YOUR_PUBLIC_KEY'; //示例: vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg

async function getTokenAccounts(wallet: string, solanaConnection: Connection) {
    const filters:GetProgramAccountsFilter[] = [\
        {\
          dataSize: 165,    //账户的大小(字节)\
        },\
        {\
          memcmp: {\
            offset: 32,     //我们在账户中的查询位置(字节)\
            bytes: wallet,  //我们的搜索标准,一个 base58 编码的字符串\
          },\
        }];
    const accounts = await solanaConnection.getParsedProgramAccounts(
        TOKEN_PROGRAM_ID, //new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
        {filters: filters}
    );
    console.log(`Found ${accounts.length} token account(s) for wallet ${wallet}.`);
    accounts.forEach((account, i) => {
        //解析账户数据
        const parsedAccountInfo:any = account.account.data;
        const mintAddress:string = parsedAccountInfo["parsed"]["info"]["mint"];
        const tokenBalance: number = parsedAccountInfo["parsed"]["info"]["tokenAmount"]["uiAmount"];
        //记录结果
        console.log(`Token Account No. ${i + 1}: ${account.pubkey.toString()}`);
        console.log(`--Token Mint: ${mintAddress}`);
        console.log(`--Token Balance: ${tokenBalance}`);
    });
}
getTokenAccounts(walletToQuery,solanaConnection);

运行 ts-node index.ts,你应该会在终端上看到如下日志:

示例输出:终端中的代币日志

奖励:添加更多过滤器

玩得开心吗?想尝试更多过滤器吗?比如,你想查看一个钱包是否包含特定铸造的代币。你可以在上面的 forEach 循环中包含该过滤器,但你可能考虑将其添加到原始查询中的过滤器变量中,以减少搜索时间。如下所示。

在你应用程序顶部的定义中,添加一个铸造地址进行搜索,例如:

    const MINT_TO_SEARCH = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'; //USDC 铸造地址

现在,回到我们的 getTokenAccounts 函数中,向 filters 添加一个额外的过滤器,寻找 _MINT_TOSEARCH 在第 0 字节位置(已知该程序中铸币公钥的位置):

    const filters:GetProgramAccountsFilter[] = [\
        {\
          dataSize: 165,    //账户的大小(字节)\
        },\
        {\
          memcmp: {\
            offset: 32,     //我们在账户中的查询位置(字节)\
            bytes: wallet,  //我们的搜索标准,一个 base58 编码的字符串\
          },\
        },\
        //添加此搜索参数\
        {\
            memcmp: {\
            offset: 0, //字节数\
            bytes: MINT_TO_SEARCH, //base58 编码字符串\
            },\
        }];

重新运行你的代码,你应该会看到结果现在限制为你搜索的铸造:

示例输出:单一铸造搜索结果

结论

完成了!你现在应该了解如何查询一个钱包的所有Token账户,并具备坚实的基础,使你能够在未来查询其他 Solana 程序。

觉得对你有用吗?请查看我们其他的一些 Solana 教程 这里。注册我们的 通讯 获取更多关于 Solana 的文章和指南。如果你有任何反馈,随时通过 Twitter 与我们联系。你也可以在我们的 Discord 社区服务器上与我们聊天,遇见一些你见过的最酷的开发者 :)

我们 ❤️ 反馈!

让我们知道 如果你有任何反馈或对新主题的请求。我们乐意倾听你的声音。

  • 原文链接: quicknode.com/guides/sol...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
QuickNode
QuickNode
江湖只有他的大名,没有他的介绍。