推出 Solana 歷史代幣餘額查詢功能
作者:Alchemy

問一個 Solana 錢包今天持有什麼,任何節點一次呼叫就能回答。問它去年春天持有什麼,或是被盜前那一刻持有什麼,簡單的做法就行不通了。節點提供的是當前餘額,並不會保留誰在何時持有什麼的完整紀錄。所以「這個錢包當時持有什麼」這個問題,老實說,答案一直是:自己重建。
今天我們要改變這一點。getTokenAccountsByOwnerAtSlot 能在一次呼叫中,回傳一個錢包在過去任何時間點所持有的一切,包含精確餘額。
重建歷史紀錄的問題
標準的 getTokenAccountsByOwner 只回答一個問題:這個錢包現在持有什麼。這能滿足大多數即時應用流程的需求,但留下了一整類問題無法回答。
要自己重建過去的餘額,你得重演這個帳戶的整個生命歷程。用 getSignaturesForAddress 拉出錢包完整的簽章歷史,用 getTransaction 取得每一筆交易,再逐個 slot 重新推導餘額,直到你要的目標時間點。對於一個活躍的錢包,這意味著數千次呼叫、大量解析工作,以及算錯的高風險。歸檔節點(archival node)能幫你讀取舊狀態,但它們仍然無法直接回答「列出這個持有者在 slot X 時的代幣帳戶」這類問題。
運作方式
這個方法保留了你已經熟悉的 getTokenAccountsByOwner 語法,並加入了一項:slot。slot 是 Solana 的時鐘,大致相當於一個區塊,傳入 slot 代表「告訴我這個錢包在歷史上那個精確時間點的狀態」。
呼叫這個方法時,你會拿到錢包的代幣帳戶(token accounts),也就是持有錢包所擁有的每一種代幣的個別紀錄。在 Solana 上,錢包本身並不直接持有餘額,所以列出這些帳戶才是讀取持有狀況的方式。每個帳戶都會附帶其餘額與 lamports,也就是每個帳戶為了存在於鏈上必須攜帶的少量 SOL(一枚代幣的小數分割,1 SOL 等於 10 億 lamports)。這個方法涵蓋 Solana 的兩種代幣標準:SPL Token,這是最原始的標準,幾乎所有知名代幣(如 USDC)都基於它;以及 Token-2022,較新的版本,附加了轉帳手續費、機密餘額等功能。這兩種標準對應不同的 program ID,所以單一 programId 過濾條件只會回傳該 program 底下的帳戶。
在呼叫背後,是一個持續建置的歷史索引:一份針對每個代幣帳戶的版本化紀錄,記錄誰在哪些 slot 之間持有多少數量,並隨著新區塊產生持續更新。你可以用兩種方式限定查詢範圍:按 mint,讀取某個代幣在過去某個 slot 的餘額;或按 program,列出該 program 在該 slot 下所擁有的每個代幣帳戶。若要取得橫跨兩種標準的完整投資組合,分別用 SPL Token 的 program ID 呼叫一次、用 Token-2022 的 program ID 呼叫一次,再合併結果。下方範例僅限定在 SPL Token。
const res = await fetch("https://solana-mainnet.g.alchemy.com/v2/{ALCHEMY_API_KEY}", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "getTokenAccountsByOwnerAtSlot",
params: [
"89zoESAF7JqYQz5uhf5eYwg3QsKXQy5QFs4WZQ4hMPnb",
{ programId: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" },
{ encoding: "jsonParsed", slot: 80000000 }
]
})
});
console.log(await res.json());分頁結果會保持一致,因為 pageKey 固定了你所指定的 slot。就算鏈的最新進度在你分頁的過程中持續前進,你的結果仍然描述的是同一個時間點,每頁最多可回傳 10,000 個帳戶。
為什麼這很重要
特定時間點的持有狀況成為第一級查詢對象。原本你得自己建置並維護的索引管線,現在收斂成一次 RPC 呼叫,讓你的團隊能專注在產品本身,而不是底層管線工程。
這讓一些原本很麻煩的工作變得可行:
- 任何歷史時間點的投資組合與損益(PnL)快照
- 綁定特定 slot 或日期的成本基礎與稅務申報
- 爭議處理、鑑識與事件調查,例如證明某個錢包在被盜前一個區塊持有什麼
- 需要準確歷史狀態、卻不想重演交易紀錄的分析與索引管線
我們在測試期間,將結果與鏈上真實資料進行了比對驗證。抽樣的歷史查詢結果與鏈上餘額及 lamports 完全吻合,包含像是 slot 80,000,000 時的 KIN 餘額這類深層歷史資料。
開始使用
這個方法已在標準的 Solana mainnet 端點上開放使用,所以如果你已經透過 Alchemy 發送 Solana RPC 請求,可以直接用現有的 API key 呼叫它。指向 https://solana-mainnet.g.alchemy.com/v2/{ALCHEMY_API_KEY},加上 slot,就能讀回持有狀況。
請參閱 Solana API quickstart 來設定 key 並發送你的第一個請求。
常見問答
getTokenAccountsByOwnerAtSlot 做什麼?
它會回傳一個 Solana 錢包在你指定的過去 slot 時的代幣帳戶,包含餘額與 lamports。它與 getTokenAccountsByOwner 的結構相同,只是多了一個 slot 參數。
什麼是 SPL Token 與 Token-2022?
它們是 Solana 的兩種代幣標準。SPL Token 是最原始的標準,幾乎涵蓋網路上所有知名代幣。Token-2022 是較新的版本,新增了轉帳手續費、機密餘額等可選功能。這個方法兩者都涵蓋。
這和 getTokenAccountsByOwner 有什麼不同?
getTokenAccountsByOwner 只回傳當前的持有狀況。getTokenAccountsByOwnerAtSlot 則能回答同一個問題在任何過去 slot 的狀態,它讀取的是歷史索引,而不是即時節點狀態。
我需要歸檔節點或自訂索引器嗎?
不需要。這個方法讀取的是預先建好的歷史索引,所以你不需要自己運行歸檔基礎設施,也不必重演交易歷史。
我可以查詢錢包的完整投資組合,而不只是單一代幣嗎?
可以,但如果錢包同時持有兩種標準的代幣,就無法只用一次 programId 呼叫完成。按 mint 限定範圍可查詢單一代幣,按 programId 限定範圍則可列出該 program 在某個 slot 下的所有帳戶。SPL Token 與 Token-2022 使用不同的 program ID,所以要取得完整投資組合,需分別查詢兩者並合併結果。
隨著鏈持續前進,分頁如何保持準確?
pageKey 固定了你查詢的 slot,所以即使有新區塊到達,跨頁的結果仍保持一致,每頁最多可回傳 10,000 個帳戶。
Alchemy 電子報
搶先掌握最新發布消息
訂閱我們的電子報
取得 Alchemy 最新產品更新與資源
輸入您的電子郵件地址,即表示您同意接收我們的行銷通訊與產品更新。您了解 Alchemy 會依照我們的隱私權聲明處理所收到的資訊。您可以隨時取消訂閱。


