昨天介紹了 Wallet 和 Provider 是怎麼與鏈上運作的,且上次在網頁上面做出了一個 Log in metamask
的按鈕,今天的目標就是讓網頁可以連結到 Metamask
,並在同樣的地方顯示出其地址出來。
首先來講一下我的登入設計流程。
Lon in Metamask
的按鍵。Please Install Metamask
,並使其連到 Metamask 的下載頁面。Log in button
時會變色。Log in button
後會跳出 MetaMask 的解鎖畫面,解鎖登入。Metamask
地址的資料,並顯示在原本的按鈕上。首先要在頁面重整時,偵測瀏覽器上是否有安裝任何插件錢包。大致運作流程如下:
useState:isMetamaskInstalled=true
。useEffect()
來偵測這個使用者是否有安裝 Metamask。isMetaMaskInstalled
是 truesetMetamaskInstalled(false)
。const [isMetamaskInstalled, setMetamaskInstalled] = useState(true);
const [isConnected, setConnected] = useState(false);
useEffect(() => {
if (typeof window.ethereum === 'undefined'){
setMetamaskInstalled(false);
}
},[]);
isMetaMaskInstalled
來顯示 Log in button
。使用的是 React 中 bool
+ tag
的語法。
return(
...
{isMetaMaskInstalled && <button className='log-in-btn' onClick={ () => { connectAccount() }}>Log In Metamask</button>}
...
);
connectAccount()
來連接 MetaMask按下按鈕後會透過 window.ethereum.request({ method: 'eth_requestAccounts', });
這個函式來 pop up MetaMask 的頁面
而此函式會 return 帳號地址,我們用 accounts 來接住他,並更新從 App.js 傳入的 propety--accounts(是一個useState
)。
const connectAccount = async () => {
// to detect whether the wallet is installed
if (isConnected === false){
if (window.ethereum) {
const accounts = await window.ethereum.request({
method: 'eth_requestAccounts',
});
setAccounts(accounts);
setConnected(true);
setLogged(true);
}
alert("Successfully Logged in!")
}
console.log(isLogged);
}
isLogged
來顯示地址這邊我宣告:
const [isLogged, setLogged] = useState(false);
並再登入成功後 setLogged(true)
,並在原本的 Log In Button
的邏輯中在加入 !isLogged
,讓他在登入後不顯示。
{ !isLogged && (isMetamaskInstalled && <button className='log-in-btn' onClick={ () => { connectAccount() }}>Log In Metamask</button>) }
最後用一個 <div>
來顯示地址。
{ isLogged && <div>{ showAccount() }</div>}
但是原本的地址足足有 40 個字元這麼多!因此我又用 showAccount()
讓他縮減。
const showAccount = () => {
const prefix = accounts[0].substr(0, 5);
const suffix = accounts[0].substr(36, 40);
return (prefix + "..." + suffix);
}
我在 MetaMask 的官網上找到了更精確的方式來偵測是否安裝 MetaMask,就是 ethereum.isMetamask
。
const checkAccount = async () => {
if(!window.ethereum.isMetamask) {
setMetamaskInstalled(false);
return;
}
}
只要瀏覽器上安裝的插件並非 Metamask 就會請他左轉去安裝。但是這個方法在似乎行不通,會跳出
Uncaught TypeError: Cannot read properties of undefined (reading 'isMetaMask')
這個錯誤。
因此推論需要先確認 window.ethereum
是 defined
(也就是需要安裝其他種錢包),才能再進一步的確認 window.ethereum.isMetaMask
是否存在!
為了測試,我把 chrome 裡面的 MetaMask extension 刪除,改成安裝 coinbase 的錢包。
此時如果只有使用
if (typeof window.ethereum === 'undefined')
setMetaMaskInstalled(false);
在只有安裝 coinbase 的 chrome 裡面,會顯示 Log In MetaMask
,而非 Please Install MetaMask
。
我推論除了 MetaMask 外,其他錢包也會透過 inject 一個 window.ethereum 的 object 給使用者,讓使用者來偵測他們的存在(並做出之後的動作)。
因此若只想要使用者使用 MetaMask 則要改成:
if (typeof window.ethereum === 'undefined')
setMetamaskInstalled(false);
else
if (!window.ethereum.isMetaMask)
setMetamaskInstalled(false);
這樣可以先確認 browser 裡面是沒有錢包(會產生 window.ethereum 的錢包),若有的話再確認其是否是 MetaMask,若不是則還是請她左轉安裝。
以下是我的兩個實作影片!
Lon In MetaMask
。今天實作的部分,大部分的 code 都是查詢不同的頁面,比對、偵錯、才慢慢寫出來的。而其中我最滿意的是,我實作出了一個完整的流程,並且在途中一一解決了很多困難(像是點下 link 後跳出一個新的分頁而不是在同一頁連結、怎麼使用 useEffect()
、useState()
等等)!
若有文章內有任何錯誤的地方歡迎指點與討論!非常感謝!
歡迎贊助窮困潦倒大學生
0xd8538ea74825080c0c80B9B175f57e91Ff885Cb4