web3链接钱包

2,224 阅读3分钟

我这个人很懒,发了一篇文章之后就好久没动了,我其实有考虑过要不要再发一篇关于tradingview的文章,毕竟我当年也是踩了很多坑的,搜了一下有前辈说的比较详细,也就懒得发了,看了一下之前的文章说的还是有点草率,这次讲详细点。理解失误,莫怪,我是个小白。

Web3Modal 的样式基本是不可更改,样式比较试用于pc端,那要自定义样式,然后自己判断怎么做呢?类似于:

image.png

这个需求过来的时候,我也是一头懵,要先判断有没有安装钱包,再连接钱包,然后猛翻文档,然后看到了这段话

image.png

这就可以自己判断了

看看代码

image.png

image.png

在此额外说明一下,Binance Wallet和MetaMask的连接方式一样,注入对象不一样,要额外写方法。两个钱包同时存在的时候,会默认打开Binance Wallet。所以同时存在的时候要判断一下。 walletConnect的链接方法也不一样,也得额外写调用方法。


const isNetwork = 97. //BSC测试链ID
//小狐狸调用
 async initWeb3() {
      const web3 = new Web3(window.ethereum); //注入对象window.ethereum
      if (window.ethereum) {
        window.ethereum.enable();  //默认连接
        ethereum.on('accountsChanged', this.accountsChanged); //监听账户变化
        ethereum.on('networkChanged', this.networkChanged);//监听网络变化
        ethereum.on('close', this.disconnect);  //断开连接
      } else {
        alert('no wallet');
        return;
      }
      const Contract = new web3.eth.Contract(abi, address); 
      this.allMethods = Contract.methods;
      //轮询去获取地址
      const timer = setInterval(async () => {
        const address = await this.getAddress(web3);
        if (address) {
        //地址
          this.address = address;
          //网络
          this.network = ethereum.networkVersion;
          sessionStorage.setItem('address', this.address);
          
        //限制网络,当不在限制的网络时,强行切换(比如限制只能在BSC主链),不需要可以注释
          if (this.network != isNetwork) {
            this.switchNetwork();
            this.address = '';
          }
          clearInterval(timer);
        }
      }, 1000);
    }
    //获取地址
    async getAddress(web3) {
      const account = await web3.eth.getCoinbase();
      if (account) {
        return account;
      }
      return false;
    }
    //切换网络方法,
  switchNetwork() {
  //调用小狐狸api方法,传入你要切换的网络id
      try {
        window.ethereum.request({
          method: 'wallet_switchEthereumChain',
          params: [{ chainId: Web3.utils.toHex(isNetwork) }],
        });
      } catch (switchError) {
        if (switchError.code === 4902) {
          alert('add this chain id');
        }
      }
    }
    
    
    const isBscNet = 'bsc-testnet';
    //Binance Wallet调用
   async initBSCWeb3() {
      const web3 = new Web3(window.BinanceChain);//注入对象window.ethereum
      if (window.BinanceChain) {
        window.BinanceChain.enable();
        BinanceChain.on('accountsChanged', this.accountsChanged);//监听账户变化
        BinanceChain.on('chainChanged', this.BSCNetChanged);//监听网络变化
        BinanceChain.on('disconnect', this.disconnect);//断开连接
        // BinanceChain.on('close', this.disconnect);
      } else {
        alert('no wallet');
        return;
      }

      const Contract = new web3.eth.Contract(abi, address);
      this.allMethods = Contract.methods;
      this.network = window.BinanceChain.chainId;
      //网络不对时切换网络,不需要可以注释
      if (this.network != isBscNet && this.network !== '0x61') {
        this.switchBSCNet();
        this.address = '';
      }
      //获取地址,异步
      const account = await web3.eth.getAccounts();
      if (account) {
        this.address = account[0];
        sessionStorage.setItem('address', this.address);
      }
    }
    //Binance Wallet 切换网络
     async switchBSCNet() {
      try {
        await window.BinanceChain.switchNetwork(isBscNet);
      } catch (switchError) {
        if (switchError.code === 4902) {
          alert('add this chain id');
        }
      }
    }
    
    
    //walletConnect 链接方法, 有些坑,看上篇文章
     async walletConnect() {
      const provider = new WalletConnectProvider({
        infuraId: infuraId, //需要自己去申请,上篇文章有讲
        qrcode: true,
      });

      if (!provider.on) {
        return;
      }
      // Subscribe to accounts change
      provider.on('accountsChanged', this.accountsChanged);
      provider.on('disconnect', (code, reason) => {
        this.disconnect();
      });
      provider.on('close', () => {
        localStorage.removeItem('walletconnect');
      });
      await provider.enable();
      const web3 = new Web3(provider);
      const accounts = await web3.eth.getAccounts();
      this.address = accounts[0];
      const Contract = new web3.eth.Contract(abi, address);
      this.allMethods = Contract.methods;
      this.network = await web3.eth.net.getId();
    }

备注:abi就是你合约的abi,address就是你要调用的合约地址。

image.png

可以在bsc区块链浏览器上去查找所有的代币,搜索名字找你需要的代币,token contract就是代币的合约地址。如上,我查找的是币安链上的USDT, 0x55d398326f99059ff775485246999027b3197955就是USDT的合约地址,在搜索里面输入地址,就能得到地址的详细信息。

image.png

点击Contract就是代币的合约代码。往下翻就能看到它的Contract ABI。如果自己开发代币,后台也会给你ABI和地址。

必要参数都齐了,调用方法就能连接你的小狐狸或钱包。Contract.methods就是代币的所有方法(比如获取余额,转账)

image.png

这是代币的方法,比如USDT,我可以调用方法获取usdt的余额,那bsc呢,bsc不是代币是主币种,web3.eth就是主币种的方法,里面同样有获取余额转账的方法。

//代币获取余额
const getBal = async() = > {
    const balance = await this.allMethods.balanceOf(user_address).call()
}

//代币转账,传入数量要转精度
const transfer = async (number) => {
 const decimals = await this.allMethods.decimals().call();
 const count = number * decimals  //要专门方法处理,直接乘除会有精度丢失。
    try{
    const res = await this.allMethods
      .transfer(toAddress, count)
      .send({ from: user_address });
    }catch(error){
        console.log(error)
    }
}

差不多了,其实我之前研究过别人的开源项目,如果你是用react,你可以看看@web3-react,这个可能能更好的解决这个问题,but,i'm vuer.