本文介绍了如何使用 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 倍的响应速度,你可以把繁重的工作交给我们。
const rpcEndpoint = 'https://example.solana-mainnet.quiknode.pro/000000/';
const solanaConnection = new Connection(rpcEndpoint);
将你想要查询的钱包定义为字符串:
const walletToQuery = 'YOUR_PUBLIC_KEY'; //示例: vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg
太棒了!我们准备构建我们的代币查询。
创建一个新的 async 函数,getTokenAccounts,并要求接受参数 wallet 和 solanaConnection:
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 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!