# Ether.js+Web3modal基础使用

By [point](https://paragraph.com/@point) · 2022-05-02

---

1.说明
----

1.  现在网站会提供很多种钱包，web3modal可以提供统一的provider，不需要你操心太多东西
    
2.  用ether.js而不是web3.js的原因是简单，爽
    

2.安装
----

    npm i web3modal
    npm i ethers
    //另外还需要安装对应wallet的包，自行搜索就行
    

3.连接钱包
------

    // MM默认就有，无需显式加入
    const providerOptions = {
      walletconnect: {
        package: walletconnectProvider,
        options: {
          infuraId: "",
        },
      },
    };
    //构建Web3Modal对象
    const web3Modal = new Web3Modal({
      //缓存provider
      cacheProvider: true,
      providerOptions,
    });
    
    //连接wallet
    async function connect() {
      try {
        const web3ModalProvider = await web3Modal.connect();
        provider = new ethers.providers.Web3Provider(web3ModalProvider);
        //注册监听，比如disconnect，accountsChanged，chainChanged
        registerEthListener(web3ModalProvider);
        //主要是处理业务上的需求
        updateCurrentStatus(await provider.listAccounts());
      } catch (error) {
        console.log(error);
      }
    }
    

4.上面的registerEthListener
------------------------

    //可以根据自己的需要些具体的内容
    function registerEthListener(web3ModalProvider) {
      web3ModalProvider
        .on("disconnect", (error) => {
          
        })
        .on("accountsChanged", (accounts) => {
          
        })
        .on("chainChanged", (chainId) => {
          
        });
    }
    

5.切换网络&添加网络
-----------

    //你需要的network信息
    const networkInfo = {
      localhardhat: {
        //这里一定要16进制，不然报错
        chainId: "0x539",
        chainName: "LOCALHARDHAT",
        nativeCurrency: {
          name: "LOCALHARDHAT",
          symbol: "LH",
          decimals: 18,
        },
        rpcUrls: ["http://192.168.50.36:8545/"],
        blockExplorerUrls: ["http://192.168.50.36:8545/"],
      },
      matic: {
        chainId: "0x89",
        chainName: "Ploygon",
        nativeCurrency: {
          name: "MATIC",
          symbol: "MATIC",
          decimals: 18,
        },
        rpcUrls: ["https://rpc-mainnet.maticvigil.com/"],
        blockExplorerUrls: ["https://polygonscan.com/"],
      },
    };
    //切换网络
    //walletProvider是上面的web3ModalProvider，而不是ethers获取的provider
    async function switchNetwork(network, walletProvider) {
      try {
        await walletProvider.request({
          method: "wallet_switchEthereumChain",
          params: [{ chainId: networkInfo[network].chainId }],
        });
      } catch (error) {
        console.log(error);
        if ((error.code = 4902)) {
          return await addNetwork(network, walletProvider);
        }
        throw error;
      }
    }
    //添加网络
    async function addNetwork(network, walletProvider) {
      try {
        return await walletProvider.request({
          method: "wallet_addEthereumChain",
          params: [networkInfo[network]],
        });
      } catch (error) {
        console.log(error);
      }
    }
    

6.预估Gas调用合约写方法
--------------

1.  这里要引入一个number包用于计算
    

    npm i big-number
    //引入项目
    import BigNumber from "bignumber.js";
    

    //预估gas,并且调用合约
    //functionName:你要调用的方法，如safeMint
    //args：调用合约的参数，array类型，例如[arg1, arg2, arg3, {}],最后的{}不能少，函数中会将计算出来的gas要放里面，如果要传入eth，则最后的{}为{value:xxx}
    async function executeContractMethosWithEstimatedGas(
      functionName,
      args
    ) {
    //合约信息,provider是连接ethers时的
      const contract=new ethers.Contract(contractAddress,contractAbi,provider);
    
      const estimatedGas = new BigNumber(
        ethersOf(
          await contract.estimateGasfunctionName
            .then((value) => {
              const minimumGas = ethers.BigNumber.from("300000");
              if (value.lt(minimumGas)) {
                return minimumGas;
              }
              return values;
            })
            .catch((error) => {
              //出错时给个固定值
              return ethers.BigNumber.from("700000");
            })
        )
      );
    //将计算结果放入参数中
      const argsForOverridden = args.pop();
      args.gasLimit = parseEthers(estimatedGas.times(1.2).toString());
      args.push(argsForOverridden);
      return contract.connect(getSigner())functionName;
    }
    //以下是周边函数
    function getSigner(){
      if(!provider){
        console.log("please connect awallet first");
        return;
      }
      return provider.getSigner();
    }
    
    function parseUnits(amount,unit){
      const bnAmount=new BigNumber(amount);
      try {
        return ethers.utils.parseUnits(bnAmount.toFixed(unit),unit);
      } catch (error) {
        return ethers.BigNumber.from(bnAmount.times(Math.pow(10,unit)).toFixed(0));
      }
    }
    const ETHER_DECIMALS=18;
    function parseEthers(amount){
      return parseUnits(amount,ETHER_DECIMALS);
    }
    
    function ethersOf(amount){
      return ethers.utils.formatEther(amount);
    }
    

7.网络确认
------

说明：一个写操作分为两步。1.提交执行，2.网络确认。类似uni页面操作后会有pending

    //tx是上面executeContractMethosWithEstimatedGas会返回的结果
    async function waitForTransaction(tx){
      //2是网络确认数量，自定义
      return await provider.waitForTransaction(tx.hash,2);
    }
    

以上就是一些基础操作，还有个读合约，那个别的网站都有，就没贴了

签名：

[https://mirror.xyz/0xE3a463d743F762D538031BAD3f1E748BB41f96ec/S1CbvnSfUIMKk1CkUr9nQDiT\_YN1iHMGsL2IlJE3KGw](https://mirror.xyz/0xE3a463d743F762D538031BAD3f1E748BB41f96ec/S1CbvnSfUIMKk1CkUr9nQDiT_YN1iHMGsL2IlJE3KGw)

---

*Originally published on [point](https://paragraph.com/@point/ether-js-web3modal)*
