連接錢包是進入 Web3 世界的關鍵一步,Web3 用戶經常需要在一些 DApp 網站上連接錢包。但是,僅僅是這個簡單的動作,也可能對用戶造成嚴重的不便。
連接錢包
想象一下這樣一個場景:一位新入門的 Web3 用戶(出於好奇,他安裝了許多個插件錢包),訪問了某個 DApp 網站,並且想要使用自己的瀏覽器插件錢包來連接它,但是當他們點擊網站提供的“Connect Wallet”按鈕,並選擇某個錢包以便想使用它來連接 DApp 時,可能會發現彈出的錢包並不是自己選擇的。這很可能會讓他感到慌亂和窒息,以爲是自己的電腦中了病毒,所以才執行了自己意料之外的操作。
區塊鏈錢包是連接區塊鏈的重要入口,而爲了佔據這個入口,各個錢包使用了它們能想到的各種方式。其中最讓 DApp 开發者以及 DApp 用戶頭疼的要數各錢包對全局變量的篡改。
在當前的瀏覽器錢包實現邏輯中,都有通過向瀏覽器注入全局變量來暴露錢包提供的功能(例如以太坊平台的錢包會將其提供的功能注入到「 window.ethereum 」上),以便 DApp 可以調用錢包提供的方法來與之交互。
只是,由於很多錢包都會將自己注入到同一個 window.ethereum 變量上,就導致在後面注冊的錢包會覆蓋之前注冊的錢包,以至於只能通過這種方式只能喚起最後注冊的那個。
有時候 DApp 用戶爲了可以正常使用自己想要用的錢包,不得不臨時將其他錢包插件禁用,或者直接只安裝某一個錢包。這樣一來,反而與錢包开發者最初的想法大相徑庭了。並且新錢包哪怕做的更出色,也很難吸引到已經使用其他錢包的用戶。
有朋友可能奇怪,爲什么一定要注入到同一個變量中呢?假設有兩個錢包:A 和 B,其實只要 A 將自己注入到「 window.a 」,B 將自己注入到「 window.b 」,想要喚起哪個錢包,就調用其對應的對象中提供的方法,就不會發生上述想要調用 A 卻反而將 B 喚起的問題。這樣確實可以解決競爭問題,但是,問題在於,如此以來,假如 DApp 將要支持多個錢包連接,就必須將开發者想要適配的所有錢包名稱全部預先定義在代碼中,並且在用戶選中某個錢包時,調用該錢包的相關方法。導致相關代碼維護起來相當麻煩。而統一將錢包注入到同一個對象上,則可以免於這個麻煩。
爲了脫離上述的兩難困境,社區中有兩個相似的標准。
以太坊社區在 2023 年 5 月份提出了 EIP-6963 提案。
其中的基本邏輯很簡單,就是舍棄全局變量,轉而使用約定的事件,來解決錢包注冊與發現的問題。
具體來說,插件錢包加載成功後,觸發統一的「 eip6963:announceProvider 」事件,通知 DApp 有新的錢包可用。而 DApp 則通過監聽此事件,來得知自己目前可用的錢包有哪些。
這樣,通過一套抽象的事件監聽邏輯,避免了直接使用全局變量所造成的問題,且能夠自動發現目前用戶環境中可用的錢包。如此一來,兩難自解。
EIP-6963 是以太坊生態標准,但是不止以太坊,其他鏈平台也會有類似的問題。例如 Solana 鏈的錢包,普遍會將自己注入到「 window.solana 」變量上,同樣會造成競爭情況。
那么可否讓 Solana 生態也實現這個標准呢?雖然 EIP-6963 只是爲了解決以太坊生態中的錢包發現問題,但是其中所蕴含的思路其實可以套用在所有鏈平台。那么,我們能否再進一步,提供一套通用的標准,讓所有區塊鏈平台的錢包和 DApp 實現,讓所有鏈平台的开發者和用戶都能享受到 EIP-6963 所提供的便利?理論上是完全沒有問題的,而且已經有开發者在這么做了,也就是 Wallet Standard。
Wallet Standard 所做的核心工作,在於提供了兩個函數:「 registerWallet 」和「 getWallets 」,前者用於錢包,後者用於 DApp。
錢包調用「 registerWallet 」,傳入一個錢包對象,這個對象上封裝了錢包提供的功能(例如 Connect 方法,用於連接錢包)。函數內部會先觸發一個 RegisterWalletEvent 事件,事件的參數其實是一個回調函數,用於讓 DApp 監聽到 RegisterWalletEvent 事件時調用,而這個回調函數實際上會將 wallet 對象傳入,於是 DApp 就可以拿到錢包對象引用,也就可以與錢包進行交互了。
DApp 开發者沒有必要自己來寫監聽、接收錢包對象的代碼,這部分也已經被 Wallet Standard 內置到「 getWallets 」當中。但是,getWallets 只是監聽了事件,具體要怎樣處理事件,還是需要开發者考慮。例如獲取到的 Wallets 放到哪裏?有些錢包在 DApp 加載前就已經加載,而另一些錢包可能在之後才加載,這些錢包的狀態如何維護?Wallet Standard 針對以上細節問題,同時提供了「 @wallet-standard/react 」包,开發者直接使用它提供的 React Hooks 就可以獲取到想要的數據,包括錢包列表、當前連接的錢包、錢包提供的方法等。
Wallet Standard Features
除了最基本的獲取 Wallet 對象外,Wallet Standard 也定義了一些 Features 格式。
實際上,錢包都具有一些最基本的功能,例如連接、監聽錢包事件等。Wallet Standard 提供了「 standard:connect 」、「 standard:events 」等 features,錢包供應商實現這些特性後,DApp 可以直接根據這些值來判斷錢包是否支持某些操作。
上面提到的 "standard:*" 是它內置定義的特性,實際上它們的值並沒有特別強硬的要求,所以可以隨意擴展。不同的鏈平台也會有其獨特的特性,例如 Solana,直接約定 "solana:*" 即可。Solana 平台常見的 features 包括「 solana:signTransaction 」, 「 solana:signMessage 」等。
Wallet Standard 現狀
目前實現了 Wallet Standard 標准的項目實際上並不多,值得一提的有 Solana 和 Sui。
在 Ant Design Web3 的 Solana 適配器中,也支持適配了 Wallet Standard 的錢包的自動檢測,开發者基本只需要通過一個「 autoAddRegisteredWallets 」开啓即可,不需要配置一大堆的錢包元數據,开發體驗和用戶使用體驗直线上升。
ZAN.TOP 連接錢包的邏輯在早期同樣遇到相同的問題,不過現在,得益於 Ant Design Web3 提供的配置,很輕松就適配了 EIP-6963 標准。大家在 https://zan.top/personal/account?chInfo=ch_wxdyh 綁定地址時應該已經體驗到這一點了。
目前各個區塊鏈平台對 Wallet Standard(或 EIP-6963)標准的態度並不相同,這裏舉幾個例子:
比特幣目前爲止似乎沒有類似的標准,有一個實現了 Wallet Standard 標准的項目,但是並沒有引起太多關注,現在也很久沒有提交新的代碼。
目前开發者只能手動維護狀態,或者使用一些开發包來輔助工作。例如在 Ant Design Web3 中的 Bitcoin 適配器實現中,針對不同的錢包,會從不同的全局變量上獲取,並存到統一的狀態中。這其實是等於庫开發者將繁瑣的狀態維護工作接手了。而且,這僅僅解決了錢包衝突問題,無法自動感知可用錢包的問題依然存在。
以太坊平台已經有了 EIP-6963 標准,相關庫和錢包也大多提供了支持。
如上文,官方提供了實現:https://github.com/solana-labs/wallet-standard
Sui 目前已經對 Wallet Standard 提供了實現,在官方文檔上可以找到使用方法:https://docs.sui.io/standards/wallet-standard
wagmi 通過 mipd (https://github.com/wevm/mipd) 庫對 EIP-6963 提供了支持,具體方式可以查看 wagmi 的文檔。
RainbowKit(https://www.rainbowkit.com/)內部邏輯基於 wagmi,所以也已經對 EIP-6963 提供了內置支持。
Ant Design Web3(https://web3.ant.design/) 的 Ethereum 和 Solana 適配器對這兩個標准都進行了非常好的支持,並且开發者开啓起來非常便攜。
對以太坊 DApp 开發者而言,只需要添加 eip6963 配置即可,注意其中與 EIP-6963 相關的在 23-25 行:
而如果你是 Solana 生態的 DApp 开發者,方式也是類似的。它提供了 autoAddRegisteredWallets 屬性:
EIP-6963 和 Wallet Standard 可以極大改善用戶連接錢包的體驗,降低新錢包供應商的准入門檻。希望以後能有更多鏈平台以及錢包、DApp 开發者可以提供或實現相關標准,這有利於 Web3 向着更好的方向發展。
鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播信息之目的,不構成任何投資建議,如有侵權行為,請第一時間聯絡我們修改或刪除,多謝。
標題:Web3 新手系列:點擊 MetaMask 誤喚起其他錢包?錢包衝突解決方案現狀
地址:https://www.100economy.com/article/123826.html