閱讀時間 8 分鐘
概覽
各位讀者大家好!為了迎接「Solana Summer」以及當前的白名單熱潮,我們認為透過`getParsedProgramAccounts` 方法深入分析您和您的使用者所擁有的所有代幣帳戶,將會有所幫助。此工具便於查詢 Solana 上的各種程式,包括 Solana SPL 代幣帳戶函式庫。
想看影片教學嗎?跟著諾亞一起學習,只需 13 分鐘,就能掌握如何取得 Solana 錢包中所有代幣。
本指南將引導您建立一個簡單的腳本,用以查詢 Solana 主網,並回傳該錢包所擁有的所有代幣帳戶及其帳戶餘額。
如果您比較喜歡看影片,這裡有一段影片:
您需要準備的物品
- Node.js(版本 16.15 或更高)
- Solana Web3
- Solana SPL 代幣函式庫
- 已具備 TypeScript 經驗,並已安裝ts-node
- 對 Solana 部分原則的基本理解:
程式:Solana 上的智慧合約。在此範例中,我們將使用SPL 代幣程式(SPL Token Program),該程式定義了 Solana 上可互換代幣(fungible)與不可互換代幣(non-fungible)的典型應用情境。
程式篩選器:許多鏈上程式查詢會擷取大量資料集,因此縮小搜尋範圍至關重要。我們將使用GetProgramAccountsFilter類型來協助縮小搜尋範圍。
設定您的執行環境
請在終端機中執行以下指令,建立一個新的專案目錄及名為index.ts 的檔案:
mkdir sol-get-accounts
cd sol-get-accounts
echo > index.ts
初始化您的專案:
毛線 初始化 --是
或
npm 初始化 --yes
安裝 Solana Web3 依賴項:
紗線 新增 @solana/web3.js@1 @solana/spl-token
或
npm 安裝 @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 倍,不妨將繁重的工作交給我們處理。
了解為何超過 50% 的 Solana 專案選擇 Quicknode,並點此免費註冊。
請務必在 Solana 主網下啟動您的節點,並複製 HTTP 連結:

const rpcEndpoint = 'https://example.solana-mainnet.quiknode.pro/000000/';
const solanaConnection = new Connection(rpcEndpoint);
將您要查詢的錢包定義為字串:
const walletToQuery = '您的_公鑰'; //範例:vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg
太好了!我們已經準備好要建立我們的代幣查詢了。
建立您的代幣帳戶查詢
建立一個新的非同步函式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, //size of account (bytes)
},
{
memcmp: {
offset: 32, //location of our query in the account (bytes)
bytes: wallet, //our search criteria, a base58 encoded string
}
}
];
這樣一來,我們的查詢範圍應能縮小至僅搜尋由我們的錢包持有的代幣帳戶。
取得程式帳戶
現在呼叫getParsedProgramAccounts方法,並傳入SPL 代幣計畫 ID以及我們的篩選條件。
const accounts = await solanaConnection.getParsedProgramAccounts(
TOKEN_PROGRAM_ID, //SPL Token Program, new PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
{filters: filters}
);
前一個呼叫會傳回一個包含所有符合條件的代幣帳戶的陣列,其結構如下:
{
pubkey: PublicKey, //Token Account Public Key
account: AccountInfo //Object including information about our token account
}[]
您可以記錄accounts.length,以查看使用者擁有多少個代幣帳戶:
console.log(`Found ${accounts.length} token account(s) for wallet ${wallet}.`);
解析結果
建立一個簡單的forEach迴圈,用來遍歷結果並將結果記錄出來。在您的getTokenAccounts函式中加入以下內容:
accounts.forEach((account, i) => {
//Parse the account data
const parsedAccountInfo:any = account.account.data;
const mintAddress:string = parsedAccountInfo["parsed"]["info"]["mint"];
const tokenBalance: number = parsedAccountInfo["parsed"]["info"]["tokenAmount"]["uiAmount"];
//Log results
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'; //example: vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg
async function getTokenAccounts(wallet: string, solanaConnection: Connection) {
const filters:GetProgramAccountsFilter[] = [
{
dataSize: 165, //size of account (bytes)
},
{
memcmp: {
offset: 32, //location of our query in the account (bytes)
bytes: wallet, //our search criteria, a base58 encoded string
},
}];
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) => {
//Parse the account data
const parsedAccountInfo:any = account.account.data;
const mintAddress:string = parsedAccountInfo["parsed"]["info"]["mint"];
const tokenBalance: number = parsedAccountInfo["parsed"]["info"]["tokenAmount"]["uiAmount"];
//Log results
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 迴圈中,但為了縮短搜尋時間,不妨考慮將其加入原始查詢中的 filters 變數中。以下是操作方法。
請在應用程式頂端的定義中,新增一個用於搜尋的 Mint 位址,例如:
const MINT_TO_SEARCH = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'; //USDC 鑄幣地址
現在回到我們的getTokenAccounts函式中,在filters 中新增一個篩選條件,用以搜尋位元組位置 0 處的MINT_TO_SEARCH(此程式中鑄幣公鑰的已知位置):
const filters:GetProgramAccountsFilter[] = [
{
dataSize: 165, //size of account (bytes)
},
{
memcmp: {
offset: 32, //location of our query in the account (bytes)
bytes: wallet, //our search criteria, a base58 encoded string
},
},
//Add this search parameter
{
memcmp: {
offset: 0, //number of bytes
bytes: MINT_TO_SEARCH, //base58 encoded string
},
}];
重新執行您的程式碼,您應該會發現結果現在僅限於您搜尋的薄荷:
結論
這樣就完成了!現在你應該已經了解如何查詢錢包中的所有代幣帳戶,並打下紮實的基礎,未來便能進一步查詢其他 Solana 程式。
覺得這篇文章有幫助嗎?點此查看我們其他關於 Solana 的教學文章。訂閱我們的電子報,獲取更多關於 Solana 的文章和指南。如有任何意見回饋,歡迎透過Twitter聯絡我們。您隨時都可以在我們的Discord社群伺服器上與我們聊天,那裡聚集了您見過最酷的開發者們 :)
我們 ❤️ 您的回饋!
如果您有任何意見回饋或對新主題的建議,請告訴我們。我們非常樂意聽取您的意見。
