技術解析

免 API key 看餘額是怎麼做到的:公共 RPC + Multicall3 拆解

✍️ ArcSign Security Team 📅 2026年6月23日
免 API key 看餘額是怎麼做到的:公共 RPC + Multicall3 拆解

ArcSign v1.5.0 拿掉了一個一直讓新使用者卡住的步驟:你不再需要去 Alchemy 申請一把 API key 才能看到自己的代幣餘額。全部 7 條 EVM 鏈,餘額開箱即用、零設定、不需金鑰。

這篇文章拆解這背後的工程——以及為什麼「不用 key」在技術上其實是個有趣的問題,而不只是「拿掉一個設定欄位」。

為什麼以前需要 key

讀鏈上資料有兩種:一種是「查某個地址某個代幣的餘額」(eth_call 一個 balanceOf),另一種是「列出這個地址持有哪些代幣」(需要全鏈索引)。前者公共節點做得到,後者做不到。以前 ArcSign 把兩件事綁在同一條 Alchemy 路徑上,所以連看餘額都要 key。v1.5.0 把這兩件事拆開。

問題的本質:餘額 vs 探索

先釐清一個常被混淆的區別,因為整個設計都圍繞它:

  • 「這個地址有多少 USDC?」 —— 這叫 balanceOf 查詢。你已經知道要問哪個合約,只是要它的數字。任何一個 RPC 節點都能用 eth_call 回答。不需要索引、不需要 key。
  • 「這個地址到底持有哪些代幣?」 —— 這叫探索(discovery)。你事先不知道要問哪些合約,需要掃描整條鏈的轉帳事件。這需要全鏈索引器(Alchemy、NodeReal 這類),公共節點做不到

ArcSign v1.4.0 以前把這兩件事綁在同一條 Alchemy 路徑上,所以連「看餘額」這種公共節點做得到的事,都被 key 的需求綁架了。

v1.5.0 的核心洞見是:餘額讀取根本不需要探索。只要我們有一份「該問哪些合約」的清單,剩下的就只是一堆 balanceOf——而那是 keyless 的。於是問題從「怎麼拿到 key」變成「怎麼湊出那份清單,以及怎麼有效率地查」。

第一塊拼圖:公共 RPC 節點池

每條鏈在 ArcSign 內建一組免金鑰的公開 RPC 端點——一個主要端點加數個備援(例如 publicnode 這類穩定的公共節點)。當主要端點失效時,會自動降級到備援。

這裡有個維運細節值得一提:公共端點會壞、會限速、會下線。所以節點池不是寫死一個 URL,而是一個「主要 + 備援」的清單,每條鏈都有,並且有自動化測試在 CI 守著它——確保每條鏈至少有一個能用的 keyless 主要端點。一個失效的公共節點不應該讓整條鏈的餘額顯示掛掉。

第二塊拼圖:Multicall3 把 N 次查詢變一次

有了端點,下一個問題是效率。一個地址在一條鏈上可能有 10、20 種代幣要查餘額。如果每個代幣發一次 eth_call,就是 20 個來回——慢,而且對公共節點不友善(容易踩限速)。

解法是 Multicall3。這是一個部署在幾乎所有 EVM 鏈上、地址都相同0xcA11...CA11)的合約。它的 aggregate3 函式可以把一批呼叫打包成單一交易,一次回傳全部結果。

所以 ArcSign 的做法是:把這個地址在這條鏈上所有要查的代幣的 balanceOf(owner) 呼叫,組成一個 aggregate3 批次,發一個 eth_call 給 Multicall3,拿回全部餘額。20 個查詢變成 1 個來回。每個子呼叫設成允許失敗(AllowFailure: true),所以一個壞掉的代幣合約不會讓整批掛掉。

如果某個端點的 Multicall 失敗,會退回逐端點重試。整條路徑都是 best-effort——某個子查詢失敗就跳過,不會讓整個餘額查詢失敗。

第三塊拼圖:該問哪些合約?

Multicall 需要一份「要查哪些代幣」的清單。這份清單由兩張表合併而成:

表 A——curated 常見代幣表。 每條鏈一組精選的知名代幣(穩定幣、wrapped native、主流資產,還有 stETH / ankrBNB 這類流動性質押憑證),地址取自官方的 CoinGecko 代幣清單。這份表是寫死在程式裡的——加一條鏈或一個代幣,就是在這張表加一列,多鏈餘額路徑會自動把它納入。

表 B——你自己接觸過的代幣。 表 A 不可能涵蓋每個人持有的每個代幣。所以 ArcSign 維護一份每個 USB 加密儲存的清單,記錄你接觸過、但不在常見清單裡的代幣——來自 swap 的輸出、增量掃描發現的空投、或你手動匯入的。當你 swap 換到一個新代幣、或用「匯入代幣」對話框加一個進來時,它就被寫進這張表(同樣用 AES-256-GCM 加密,跟錢包其他加密資料同一套機制)。

查餘額時,這兩張表針對每條鏈合併(去重,表 A 優先),交給 Multicall。

隱私:這份清單永遠不離開你的裝置

表 B 是加密儲存在你的 USB 上的。沒有任何中央服務知道你持有哪些代幣——「探索」是你自己的機器掃描你自己的地址,結果留在本機。這跟「把地址送給第三方索引器、由它告訴你持有什麼」是相反的隱私模型。

第四塊拼圖:價格

有了餘額數字,還需要美元估值。這個由 DefiLlama 的免費價格 API 提供——一樣不需要 key。對於 provider 沒回價格的代幣(例如某些 BSC 代幣或 native 幣),ArcSign 用 DefiLlama 補上。

把四塊拼起來

於是一次餘額查詢的完整流程是:

錢包 EVM 地址


┌─────────────────────────────────────────────┐
│  每個(地址 × 鏈)組出「要查哪些代幣」          │
│                                               │
│   表 A 常見代幣  ─┐                            │
│   (寫死、curated)│─→ 合併去重 ─→ 代幣清單      │
│   表 B 你的代幣  ─┘   (表 A 優先)             │
│   (USB 加密、私密)                            │
└─────────────────────────────────────────────┘


┌─────────────────────────────────────────────┐
│  公共 RPC 節點池(免 key,主要 + 備援自動切換) │
│        │                                       │
│        ▼                                       │
│  Multicall3(0xcA11…CA11,每鏈同址)           │
│   一個 eth_call 打包 N 個 balanceOf            │
└─────────────────────────────────────────────┘


  DefiLlama 補美元價格(免 key)


  餘額顯示 ✓   ← 全程零 API key、零 provider 設定檔

對照成步驟:

  1. 收集錢包的所有 EVM 地址
  2. 從加密的 USB 載入你的 touched-token 清單(表 B)
  3. 對每個(地址 × 鏈),把常見代幣(表 A)與你的代幣(表 B)合併
  4. 透過公共 RPC + Multicall3 一次查回全部餘額
  5. 用 DefiLlama 補上美元價格

整條路徑沒有開啟任何 provider 設定檔、沒有用到任何 API key

那 key 還用來做什麼?

說清楚以免誤會:v1.5.0 之後,只有 NFT 與交易歷史還需要 provider key。原因正是開頭那個區別——列出你的 NFT、或拉出完整交易史,本質上是「探索」,需要全鏈索引,公共 RPC 做不到。

具體的金鑰矩陣是:

  • 餘額(全 7 鏈) → 公共 RPC + Multicall3,不需 key
  • NFT / 交易歷史 → Ethereum / Polygon / Arbitrum / Optimism / Base 需要 Alchemy key;BSC 需要 NodeReal;Avalanche 用 Glacier(匿名,不需 key)

而且當這些功能缺 key 時,介面會明確標示「需要 key」,而不是默默顯示空白——這是 v1.5.0 一併修掉的另一個體驗問題。

為什麼這個改動重要

對一個冷錢包來說,「零設定就能看到自己有多少錢」不只是方便。它移除了一個會勸退非技術使用者的門檻,也移除了一個隱私風險——你不再需要把你的地址活動透過一把 key 綁定到某個第三方服務的帳號上。

餘額這種最基本、最高頻的操作,本來就不該需要你去別的地方註冊帳號。v1.5.0 把它變回它本來該有的樣子。

想看這一版的其他升級,回到 v1.5.0 版本總覽