当前位置: 首页 > 工具软件 > log4web.js > 使用案例 >

如何配置web3.js和连接MetaMask

昝成弘
2023-12-01

1、创建utils文件夹在这个文件夹下创建web3.ts文件:

import { ethers } from 'ethers'
import { ExternalProvider, JsonRpcFetchFunc } from '@ethersproject/providers';
import { InjectedConnector } from '@web3-react/injected-connector'


// 提供一个provider转成web3provider

export const getLibray = (provider: ExternalProvider | JsonRpcFetchFunc) => {
    const web3Provider = new ethers.providers.Web3Provider(provider)
    return web3Provider
}

export const InjectConnector = new InjectedConnector({ supportedChainIds: [56] })

2、创建chain文件夹,在这个文件夹下创建一个index.ts文件:

// 支持的链
export const SuportChain = {
    eth: {
        chanId: 1,
        name: 'eth'
    },
    bsc: {
        chainId: 56,
        name: 'bsc'
    },
    polygon: {
        chainId: 56,
        name: 'polygon'
    }
}

// 链id 网络id
export enum NetworkID {
    // 主网
    Mainnet = 56,
    // 测试网
    Testnet = 97
}

export enum SUPPORT_CHAIN {
    BSC = 56,
    BSCTEST = 97
}

// 当前链ID
export const CURRENT_CHAIN = 56

// MetaMask 中 request 请求中的 methods 方法
export enum MetaMaskRequestMethods {
    // 添加在metamask中不存在的链
    addEthereumChain = "wallet_addEthereumChain",
    // 吧Token代币添加到钱包中
    watchAsset = 'wallet_watchAsset',
    // 获取当前链接的网络Id
    chainId = 'eth_chainId',
    // eth_requestAccunts 获取账号(可以理解为链接钱包)
    requestAccount = 'eth_requestAccounts',
    // 获取账户地址
    accounts = 'eth_accounts',
    // 获取最新区块编号
    blockNumber = 'eth_blockNumber'
}
// 添加一条链到metamask上时请求网络参数
export const AddEthereumChainParams: { [key: number]: any } = {
    8: {
        chainId: '0x8',
        chainName: 'Ubiq',
        chativeCurrency: {
            name: 'Ubiq Ether',
            symbol: 'BUQ',
            decimals: 18,
        },
        rpcUrl: ['https://rpc.octano.dev/'],
        blockExplorerUrls: ['https://ubiqscan.io/']
    },
    56: {
        chainId: '0x38',
        chainName: 'Binance Smart Chain Mainnet',
        nativeCurrency: {
            name: 'BNB',
            symbol: 'bnb',
            decimals: 18
        },
        rpcUrls: ['https://bsc-dataseed1.ninicoin.io', 'https://bsc-dataseed1.defibit.io', 'https://bsc-dataseed.binance.org'],
        blockExplorerUrls: ['https://bscscan.com/'],
    }
}

3、在react-app-env.d.ts内添加:

/// <reference types="react-scripts" />
interface Window {
    ethereum?:{
        isMetaMask?:true
        request?:(...args:any[])=>Promise<void>
    }
    BinanceChain?:{
        bnbSign?:(address:string,message:string) => Promise<{publicKey:string;signature:string}>
    }
    web3:any
}

4、创建types文件夹,在这个文件夹中创建ethereum.tsx文件:

type EthereumProviderEip1193 = {
    request: (args: {
        method: string
        params?: unknown[] | object
    }) => Promise<unknown>
}

type EthereumProviderSend = {
    send: (method: string, params: string[]) => Promise<unknown>
}

type EthereumProviderSendAsync = {
    sendAsync: (
        params: {
            method: string
            params: string[]
            from: string
            jsonrpc: '2.0'
            id: number
        },
        callback: (err: Error, result: unknown) => void
    ) => void
    selectedAddress: string
}

/**
 * window.ethereum 类型
 * Eip-1193 规范
 */
export type EthereumProvider = EthereumProviderEip1193 &
    EthereumProviderSend &
    EthereumProviderSendAsync

5、再到utils文件夹中创建ethereum.ts文件:

import { AddEthereumChainParams, MetaMaskRequestMethods } from "chain";
import { EthereumProvider } from "types/ethereum";

function isUnwrappedRpcResult(response: unknown): response is {
    error?: string
    result?: unknown
} {
    return (
        typeof response === 'object' && response !== null && 'jsonrpc' in response
    )
}
/**
 * 防止有的客户端没有包裹response
 */
export function rpcResult(response: unknown): unknown | null {
    // Some providers don’t wrap the response
    if (isUnwrappedRpcResult(response)) {
        if (response.error) {
            throw new Error(response.error)
        }
        return response.result || null
    }

    return response || null
}
/**
 * metamask request 方法封装
 * @param ethereum provider, 浏览器中使用window.ethereum
 * @param method 请求方法
 * @param params 参数
 * @returns 
 */
export async function ethereumRequest(
    ethereum: EthereumProvider,
    method: string,
    params: string[]
): Promise<any> {
    // If ethereum.request() exists, the provider is probably EIP-1193 compliant.
    if (ethereum.request) {
        return ethereum.request({ method, params }).then(rpcResult)
    }
    // This is specific to some older versions of MetaMask combined with Web3.js.
    if (ethereum.sendAsync && ethereum.selectedAddress) {
        return new Promise((resolve, reject) => {
            ethereum.sendAsync(
                {
                    method,
                    params,
                    from: ethereum.selectedAddress,
                    jsonrpc: '2.0',
                    id: 0,
                },
                (err: Error, result: any) => {
                    if (err) {
                        reject(err)
                    } else {
                        resolve(result)
                    }
                }
            )
        }).then(rpcResult)
    }
    // If none of the previous two exist, we assume the provider is pre EIP-1193,
    // using .send() rather than .request().
    if (ethereum.send) {
        return ethereum.send(method, params).then(rpcResult)
    }
    throw new Error(
        'The Ethereum provider doesn’t seem to provide a request method.'
    )
}

/**
 * 获取区块编码
 * @param ethereum provider, 默认使用window.ethereum
 * @returns 
 */
export async function getBlockNumber(ethereum?: EthereumProvider) {
    ethereum = ethereum ?? window.ethereum as any
    return ethereumRequest(ethereum!, MetaMaskRequestMethods.blockNumber, [])
}
/**
 * 添加链到metamask 上
 */
export async function addChainToBlock(id: number, ethereum?: EthereumProvider) {
    ethereum = ethereum ?? window.ethereum as any
    const params = AddEthereumChainParams[id]
    // ! 确保ethereum 部位null
    return ethereumRequest(ethereum!, MetaMaskRequestMethods.addEthereumChain, [params])
}

6、在创建hooks文件夹,在这个文件夹里创建useAuth.ts:

import { UnsupportedChainIdError, useWeb3React } from '@web3-react/core'
import { InjectConnector } from '../utils/web3'
import { addChainToBlock } from 'utils/ethereum'

export const useAuth = () => {
    const { activate } = useWeb3React()
    const Login = () => {
        if (InjectConnector) {
            activate(InjectConnector, async (error: Error) => {
                if (error instanceof UnsupportedChainIdError) {
                    const hasSetup = await addChainToBlock(56)
                    if (hasSetup) {
                        activate(InjectConnector)
                    }
                }
            })
        }
    }
    return Login
}

然后再src目录下的index.tsx文件下这么写:

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
// 这下边的两个是添加的引入文件
import { getLibray } from "./utils/web3";
import { Web3ReactProvider } from "@web3-react/core";

ReactDOM.render(
  <React.StrictMode>
    
    {/* 在这里用 Web3ReactProvider 包裹 app 文件 */}
    <Web3ReactProvider getLibrary={getLibray}>
        <App />
    </Web3ReactProvider>

  </React.StrictMode>,
  document.getElementById("root")
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

在然后再你需要获取MetaMask小狐狸地址的地方这么写:

import React, { useEffect } from "react";
import "./App.css";
import { useWeb3React } from "@web3-react/core";
import { useAuth } from "hooks/useAuth";

function App() {
  const Login = useAuth();
  const { account, library, chainId } = useWeb3React();
  console.log("地址1", account);

  const GetClick = () => {
    Login();
    console.log("地址2", account);
  };

  useEffect(() => {
    Login();
  }, []);

  return (
    <div className="App">
      <button onClick={GetClick}>获取钱包地址</button>
    </div>
  );
}

export default App;

你只需要按我说的创建文件夹步骤复制代码,就可以链接到你的小狐狸了,记得要在tsconfig.json文件中添加"baseUrl": "src",

希望我能帮到你。我技术有限,有不对的地方请在评论区指教;

 类似资料: