Metamask財布に反応する方法


フロントエンドとスマート契約を統合するには、最初のタスクは通常、どのようにフロントエンドのアプリケーションに財布を接続することです.このブログのポストは、反応のアプリケーションから財布を接続する方法を示します.

インストールするパッケージ


財布を接続するには以下のパッケージが必要です.
  • WalletConnectProvider
  • ウォレット
  • Web 3モード
  • イーサネット(これは、ブロックチェーン上のスマート契約に接続するために使用されます)
  • 上記のパッケージは、次のコマンドを端末で実行することで、反応アプリケーションにインストールできます.
      npm i --save walletlink @walletconnect/web3-provider ethers 
      web3modal
    
    次のパッケージをインストールした後、あなたの反応を開きますApp.js ファイルまたはアプリケーションの最上位コンポーネントです.最初にインストールしたパッケージをインポートします.
      import { useEffect, useState, useCallback } from "react";
      import { ethers, providers } from "ethers";
      import Web3Modal from "web3modal";
      import WalletConnectProvider from '@walletconnect/web3-provider'
      import WalletLink from 'walletlink';
    
      const App = () => {
         return (
           <div>
             <h1>Hello</h1>
          </div>
         )
      }
    
    これは単純な反応成分の骨格です.我々は、我々が使用したい財布の選択を許可するweb 3モードを宣言した.私たちは、渡されるプロバイダオプションを作成する必要がありますweb3Modal .
      const INFURA_ID = "your-infura-api-key";
      const providerOptions = {
      walletconnect: {
        package: WalletConnectProvider, // required
        options: {
          infuraId: INFURA_ID, // required
        },
      },
      'custom-walletlink': {
        display: {
          logo: 'https://play-lh.googleusercontent.com/PjoJoG27miSglVBXoXrxBSLveV6e3EeBPpNY55aiUUBM9Q1RCETKCOqdOkX2ZydqVf0',
          name: 'Coinbase',
          description: 'Connect to Coinbase Wallet',
        },
        options: {
          appName: 'Coinbase', // Your app name
          networkUrl: `https://mainnet.infura.io/v3/${INFURA_ID}`,
          chainId: 1,
        },
        package: WalletLink,
        connector: async (_, options) => {
          const { appName, networkUrl, chainId } = options
          const walletLink = new WalletLink({
            appName,
          })
          const provider = walletLink.makeWeb3Provider(networkUrl, chainId)
          await provider.enable()
          return provider
        },
      },
    }
    
    
    The WalletLink パッケージは、ユーザーが拡張機能をインストールすることなく、任意のデスクトップブラウザでアプリケーションを使用することができますし、クライアントが生成されたキーを使用してエンドツーエンドの暗号化とアプリとモバイル財布の間に安全なトンネルを確立し、すべてのユーザーの活動を非公開にします.WalletConnect パッケージは、ウォレットとDApps(web 3 Apps)の間で安全に通信するのに役立つオープンプロトコルです.プロトコルはペイロードを中継するためにブリッジ・サーバーを使用している2つのアプリケーションと/またはデバイスの間のリモート接続を確立します.接続するAPIキーを提供する必要があります.
    let web3Modal
    if (typeof window !== 'undefined') {
      web3Modal = new Web3Modal({
        network: 'mainnet', // optional
        cacheProvider: true,
        providerOptions, // required
      })
    }
    
    ProviderOptionsをWeb 3モーダルインスタンスに渡します.アプリ.JSXは今まさにこのように見えます.
    
      import { useEffect, useState, useCallback } from "react";
      import { ethers, providers } from "ethers";
      import Web3Modal from "web3modal";
      import WalletConnectProvider from '@walletconnect/web3-provider'
      import WalletLink from 'walletlink';
    
    const INFURA_ID = "your-infura-api-key";
      const providerOptions = {
      walletconnect: {
        package: WalletConnectProvider, // required
        options: {
          infuraId: INFURA_ID, // required
        },
      },
      'custom-walletlink': {
        display: {
          logo: 'https://play-lh.googleusercontent.com/PjoJoG27miSglVBXoXrxBSLveV6e3EeBPpNY55aiUUBM9Q1RCETKCOqdOkX2ZydqVf0',
          name: 'Coinbase',
          description: 'Connect to Coinbase Wallet',
        },
        options: {
          appName: 'Coinbase', // Your app name
          networkUrl: `https://mainnet.infura.io/v3/${INFURA_ID}`,
          chainId: 1,
        },
        package: WalletLink,
        connector: async (_, options) => {
          const { appName, networkUrl, chainId } = options
          const walletLink = new WalletLink({
            appName,
          })
          const provider = walletLink.makeWeb3Provider(networkUrl, chainId)
          await provider.enable()
          return provider
        },
      },
    }
    
     let web3Modal
    if (typeof window !== 'undefined') {
      web3Modal = new Web3Modal({
        network: 'mainnet', // optional
        cacheProvider: true,
        providerOptions, // required
      })
    }
    
    
      const App = () => {
         return (
           <div>
             <h1>Hello</h1>
          </div>
         )
      }
    
    
    プロバイダーオブジェクトは我々のアプリケーションで永続的である必要があり、アプリケーションのすべてのコンポーネントを通過するプロップを防ぐことができます.コンテキストファイルを作成しますwalletContext.js .
    このファイルには次の内容があります
      import * as React from "react";
    
      const WalletContext = React.createContext();
    
      const accountDetails = {
         provider: null,
         address: null,
         signer: null,
         web3Provider: null,
         network: null
    }
    
    function WalletProvider({children}){
      const [account, setAccountDetails ] = 
       React.useState(accountDetails);
      const value = { account, setAccountDetails };
      return <WalletContext.Provider value={value}>{children} 
      </WalletContext.Provider>
    }
    
    function useWallet(){
        const context = React.useContext(WalletContext);
        if (!context){
            throw new Error("useWallet must be used within a WalletProvider")
        }
        return context;
    }
    
    export {WalletProvider, useWallet }
    
    
    我々は反応文脈を作成し、それを命名したWalletContext . それから、我々はWalletProvider を返す関数WalletContext.Provider ラップされたコンポーネントchildren それはそれに渡されます.インサイドWalletProvider 関数は、接続されたアカウントの詳細を格納するために使用される反応状態を宣言しました.The account 状態を変化させる状態と機能setAccountDetailsvalue プロパティWalletContext.Provider コンポーネント.See application state management
    我々は、財布を接続するために使用されるボタンを作成する必要があります.つの関数を定義しますconnectdisconnect 関数.彼らの名前が示唆するように、彼らは接続を切って、ブロックを財布から切り離すのに用いられます.その前に、関数から返される値を格納するために使用される反応状態を作成する必要があります.
    次に、作成した関数を生成する関数を作成しましたWalletContext . The useWallet フックが消費するWalletContext を返し、context 使用する.
      <-- previous code above -->
    
       const App = () => {
        const { account, setAccountDetails } = useWallet();
        const { provider,
         address,
         signer,
         web3Provider,
         network } = account;
    
    
    const connect = useCallback(async function () {
      const provider = await web3Modal.connect();
      const web3Provider = new providers.Web3Provider(provider);
      const signer = web3Provider.getSigner()
      const address = await signer.getAddress()
      const network = await web3Provider.getNetwork();
      const accountDetails = {
           provider,
           web3Provider,
           signer,
           address,
           network
      }
      setAccountDetails(accountDetails);
    }, []);
    
    const disconnect = useCallback(
      async function () {
        await web3Modal.clearCachedProvider()
        if (provider?.disconnect && typeof provider.disconnect === 'function') {
          await provider.disconnect()
        }
        //reset the state here
       const accountDetails = {
          provider: null,
          web3Provider: null,
          signer: null,
          address: null,
          network: null
     }
     setAccountDetails(accountDetails);
      },
      [provider]
    )
    
         return (
           <div>
             <h1>Hello</h1>
          </div>
         )
      }
    
    
    Connect関数は、既定のWeb 3モード接続に設定されているプロバイダー変数を作成します.このプロバイダーは、それからプロバイダのオブジェクトにプラグインされますether.js .const web3Provider = new providers.Web3Provider(provider)を使用することができますweb3Provider object created by ether.js 得るsigner , network , address からether.js . この値は、setAccountDetails 関数.
    The disconnect 関数はweb3Modal キャッシュ、保存された状態およびprovider . 我々は両方の機能を最適化し、それらを包むuseCallback と依存を渡す.

    自動接続


    我々がすでに我々の財布に接続しているならば、我々はページまたは構成要素を訪問するとき、自動的に再接続したいです.これは、呼び出しによって行うことができますconnect インuseEffect フック.
      // Auto connect to the cached provider
      useEffect(() => {
        if (web3Modal.cachedProvider) {
          connect()
        }
      }, [connect]);
    
    また、いくつかのシナリオを処理するためにプロバイダーオブジェクトのイベントを聞くこともできます.ユーザーが接続されたアカウントを切り替える場合、我々はまだ接続されることがありますように.機能handleAccountsChanged アカウントを変更したイベントを聞くことによって行われ、WalletContext .
         useEffect(() => {
        if (provider?.on) {
          const handleAccountsChanged = (accounts) => {
            console.log('accountsChanged', accounts);
            setAccountDetails({
                ...account,
                address: accounts[0],
            })
          }
          const handleChainChanged = (_hexChainId) => {
            window.location.reload()
          }
    
          const handleDisconnect = (error) => {
            console.log('disconnect', error)
            disconnect()
          }
    
          provider.on('accountsChanged', handleAccountsChanged)
          provider.on('chainChanged', handleChainChanged)
          provider.on('disconnect', handleDisconnect)
    
          // Subscription Cleanup
          return () => {
            if (provider.removeListener) {
              provider.removeListener('accountsChanged', handleAccountsChanged)
              provider.removeListener('chainChanged', handleChainChanged)
              provider.removeListener('disconnect', handleDisconnect)
            }
          }
        }
      }, [provider, disconnect])
    
    
    すべてをまとめる
    //app > jx
      import { useEffect, useState, useCallback } from "react";
    import { ethers, providers } from "ethers";
    import Web3Modal from "web3modal";
    import WalletConnectProvider from '@walletconnect/web3-provider'
    import WalletLink from 'walletlink';
    import { useWallet } from './walletContext';
    
    import './App.css';
    
    const trimAddress = ( address ) => {
      const firstpart = address.slice(0, 4);
      const midpart = "....";
      const endpart = address.slice(address.length - 4, address.length );
      return `${firstpart}${midpart}${endpart}`
    }
    
    const INFURA_ID = '460f40a260564ac4a4f4b3fffb032dad'
    
    
    const providerOptions = {
      walletconnect: {
        package: WalletConnectProvider, // required
        options: {
          infuraId: INFURA_ID, // required
        },
      },
      'custom-walletlink': {
        display: {
          logo: 'https://play-lh.googleusercontent.com/PjoJoG27miSglVBXoXrxBSLveV6e3EeBPpNY55aiUUBM9Q1RCETKCOqdOkX2ZydqVf0',
          name: 'Coinbase',
          description: 'Connect to Coinbase Wallet (not Coinbase App)',
        },
        options: {
          appName: 'Coinbase', // Your app name
          networkUrl: `https://mainnet.infura.io/v3/${INFURA_ID}`,
          chainId: 1,
        },
        package: WalletLink,
        connector: async (_, options) => {
          const { appName, networkUrl, chainId } = options
          const walletLink = new WalletLink({
            appName,
          })
          const provider = walletLink.makeWeb3Provider(networkUrl, chainId)
          await provider.enable()
          return provider
        },
      },
    }
    
    let web3Modal
    if (typeof window !== 'undefined') {
      web3Modal = new Web3Modal({
        network: 'mainnet', // optional
        cacheProvider: true,
        providerOptions, // required
      })
    }
    
    
    function App() {
      const { account, setAccountDetails } = useWallet();
      const { provider,
        address,
        signer,
        web3Provider,
        network } = account;
    
    
    const connect = useCallback(async function () {
      const provider = await web3Modal.connect();
      const web3Provider = new providers.Web3Provider(provider);
      const signer = web3Provider.getSigner()
      const address = await signer.getAddress()
      const network = await web3Provider.getNetwork();
      const accountDetails = {
           provider,
           web3Provider,
           signer,
           address,
           network
      }
      setAccountDetails(accountDetails);
    }, []);
    
    
    
    const disconnect = useCallback(
      async function () {
        await web3Modal.clearCachedProvider()
        if (provider?.disconnect && typeof provider.disconnect === 'function') {
          await provider.disconnect()
        }
        //reset the state here
        const accountDetails = {
          provider: null,
          web3Provider: null,
          signer: null,
          address: null,
          network: null
     }
     setAccountDetails(accountDetails);
    
    },
      [provider]
    )
    
      // Auto connect to the cached provider
      useEffect(() => {
        if (web3Modal.cachedProvider) {
          connect()
        }
      }, [connect]);
    
    
      useEffect(() => {
        if (provider?.on) {
          const handleAccountsChanged = (accounts) => {
            // eslint-disable-next-line no-console
            console.log('accountsChanged', accounts);
            setAccountDetails({
                ...account,
                address: accounts[0],
            })
          }
    
          const handleChainChanged = (_hexChainId) => {
            window.location.reload()
          }
    
          const handleDisconnect = (error) => {
            console.log('disconnect', error)
            disconnect()
          }
    
          provider.on('accountsChanged', handleAccountsChanged)
          provider.on('chainChanged', handleChainChanged)
          provider.on('disconnect', handleDisconnect)
    
          // Subscription Cleanup
          return () => {
            if (provider.removeListener) {
              provider.removeListener('accountsChanged', handleAccountsChanged)
              provider.removeListener('chainChanged', handleChainChanged)
              provider.removeListener('disconnect', handleDisconnect)
            }
          }
        }
      }, [provider, disconnect])
    
      return (
        <div className="App">
             {web3Provider ? (
                   <button className="btn btn-danger" type="button" onClick={disconnect}>
                     {trimAddress(address)}
              </button>
            ) : (
              <button className="btn btn-success" type="button" onClick={connect}>
                Connect
              </button>
            )}
        </div>
      );
    }
    
    export default App;
    
    利用するWalletProvider 我々はアプリのコンポーネントをラップします.これはWalletContext それが必要とされるすべてのコンポーネントで利用できる.
    import { WalletProvider } from "./walletContext";
    ReactDOM.render(
      <React.StrictMode>
        <WalletProvider>
            <App />
        </WalletProvider>
      </React.StrictMode>,
      document.getElementById('root')
    
    コードが利用可能ですhere
    読書ありがとう.