【Ethers v6 实战】使用 MetaMask 实现钱包连接、签名与转账功能

在区块链前端开发中,与钱包交互是核心功能之一。本文基于 Ethers v6 版本,详细讲解如何通过 MetaMask 钱包实现地址获取、消息签名和 ETH 转账三大基础功能,并提供完整代码示例与优化建议。

一、环境准备

1. 依赖安装

首先需要安装项目所需依赖:

# 安装 Ethers v6(区块链交互核心库)
npm install ethers

# (可选)安装 jQuery(本文示例使用,可替换为原生 JS 或其他框架)
npm install jquery

2. 核心库说明

  • Ethers v6:轻量级以太坊开发库,提供与区块链交互的核心 API(比 Web3.js 更简洁)。
  • MetaMask:浏览器钱包扩展,用于管理用户私钥、签名交易,本文通过 window.ethereum 接口与其交互。

二、功能实现详解

1. 初始化Provider与核心变量

import $ from 'jquery';
import { ethers } from "ethers";

// 初始化 Provider(连接 MetaMask 钱包)
const provider = new ethers.BrowserProvider(window.ethereum);
let signer = null; // 签名器(需用户授权后获取)

// 注意:生产环境中绝对不要硬编码私钥!
// 以下仅为示例,实际开发应通过 MetaMask 提供的 signer 签名
const walletPrivateKey = '0x...'; // 测试用私钥(请勿用于生产)
const wallet = new ethers.Wallet(walletPrivateKey);
const activeWallet = wallet.connect(provider); // 连接到 Provider 的钱包实例

关键说明

  • BrowserProvider:Ethers v6 中用于连接浏览器钱包(如 MetaMask)的类,替代了 v5 中的 Web3Provider
  • signer:签名器对象,需用户授权后通过 provider.getSigner() 获取,用于发起签名和交易。

2. 连接钱包(获取地址与余额)

实现点击按钮连接 MetaMask,并显示用户地址和余额:

// 绑定连接钱包按钮事件
$(document).on('click', '#connectButton', async () => {
  try {
    // 1. 请求用户授权连接钱包(触发 MetaMask 弹窗)
    await provider.send("eth_requestAccounts", []);
    
    // 2. 获取签名器(用户授权后才能进行签名/转账操作)
    signer = await provider.getSigner();
    
    // 3. 获取钱包地址
    const address = await signer.getAddress();
    $('#address').text(`已连接:${address.substring(0, 6)}...${address.substring(38)}`); // 地址脱敏显示
    
    // 4. 获取 ETH 余额('pending' 表示包含未确认交易的余额)
    const balance = await provider.getBalance(address, 'pending');
    const balanceEther = ethers.formatEther(balance); // 转换为 ETH 单位(默认是 wei)
    $('#balance').text(`余额:${balanceEther.slice(0, 6)} ETH`);

  } catch (error) {
    console.error('连接失败:', error);
    $('#app').append(`<p class="error">连接钱包失败:${error.message}</p>`);
  }
});

优化点

  • 地址脱敏显示(只展示前6位和后4位),增强安全性。
  • 余额格式化(限制小数位数),避免过长数字影响美观。
  • 错误信息展示给用户,而非仅在控制台输出。

3. 消息签名功能

让用户对自定义消息进行签名(常用于身份验证):

// 绑定签名按钮事件
$(document).on('click', '#signButton', async () => {
  if (!signer) {
    alert('请先连接钱包');
    return;
  }

  try {
    const message = $('#signMessage').val() || '默认签名消息:验证我的身份';
    
    // 调用 signer 签名消息(会触发 MetaMask 签名弹窗)
    const signature = await signer.signMessage(message);
    
    $('#signatureResult').text(`签名结果:${signature}`);
    console.log('签名成功:', signature);

  } catch (error) {
    console.error('签名失败:', error);
    $('#signatureResult').text(`签名失败:${error.message}`);
  }
});

应用场景
用户无需转账即可证明对钱包的所有权(如登录验证、权限确认)。

4. ETH 转账功能

实现向指定地址转账 ETH 的功能:

// 绑定转账按钮事件
$(document).on('click', '#transferButton', async () => {
  if (!signer) {
    alert('请先连接钱包');
    return;
  }

  try {
    // 1. 获取并验证输入
    const targetAddress = $('#targetAddress').val().trim();
    const amount = $('#transferAmount').val().trim();

    // 验证地址格式
    if (!ethers.isAddress(targetAddress)) {
      alert('目标地址格式错误');
      return;
    }

    // 验证金额合法性
    if (isNaN(amount) || parseFloat(amount) <= 0) {
      alert('请输入有效的转账金额');
      return;
    }

    // 2. 格式化金额(转换为 wei 单位,区块链交易的最小单位)
    const amountWei = ethers.parseEther(amount);

    // 3. 发起转账交易(会触发 MetaMask 确认弹窗)
    const tx = await signer.sendTransaction({
      to: targetAddress,
      value: amountWei,
      // 可选:设置 gas 价格(不设置则由 MetaMask 自动估算)
      // gasLimit: ethers.parseUnits('21000', 'wei'),
    });

    $('#transferResult').text(`转账已发起,交易哈希:${tx.hash}`);
    console.log('交易详情:', tx);

    // 4. 等待交易上链(可选,用于确认交易成功)
    const receipt = await tx.wait();
    if (receipt.status === 1) {
      $('#transferResult').append('<br>交易已确认!');
    }

  } catch (error) {
    console.error('转账失败:', error);
    $('#transferResult').text(`转账失败:${error.message}`);
  }
});

关键知识点

  • parseEther(amount):将 ETH 金额转换为 wei(1 ETH = 10^18 wei),区块链交易必须使用 wei 单位。
  • sendTransaction:发起转账交易,返回的 tx 对象包含交易哈希(hash),可用于在区块链浏览器查询。
  • tx.wait():等待交易被区块确认(返回 receipt),receipt.status === 1 表示交易成功。

三、完整代码与页面结构

1. HTML 页面

<div id="app">
  <button id="connectButton">连接 MetaMask</button>
  <p>钱包地址:<span id="address"></span></p>
  <p>ETH 余额:<span id="balance"></span></p>

  <hr>
  <h3>消息签名</h3>
  <input type="text" id="signMessage" placeholder="输入要签名的消息">
  <button id="signButton">签名</button>
  <p id="signatureResult"></p>

  <hr>
  <h3>ETH 转账</h3>
  <input type="text" id="targetAddress" placeholder="目标地址">
  <input type="number" id="transferAmount" placeholder="转账金额(ETH)" step="0.001">
  <button id="transferButton">转账</button>
  <p id="transferResult"></p>
</div>

2. 核心 JS 逻辑

整合上述代码,注意初始化顺序和事件绑定时机。

四、注意事项与最佳实践

  1. 私钥安全
    生产环境中绝对不要硬编码私钥(walletPrivateKey)!本文中 activeWallet 仅为示例,实际应使用用户授权的 signer 发起交易(MetaMask 会安全管理私钥)。

  2. 错误处理
    钱包操作可能因用户拒绝、网络问题等失败,需完善错误处理(如用户关闭 MetaMask 弹窗、余额不足等)。

  3. 单位转换
    区块链中金额以 wei 为单位,务必使用 parseEther(ETH → wei)和 formatEther(wei → ETH)进行转换,避免计算错误。

  4. 网络切换
    可通过 provider.getNetwork() 检查当前网络,提示用户切换到目标链(如以太坊主网、测试网)。

  5. Gas 优化
    复杂交易可手动设置 gasLimitgasPrice,简单转账(21000 gas)可由 MetaMask 自动估算。

五、总结

本文通过 Ethers v6 实现了与 MetaMask 的三大核心交互:

  • 连接钱包并获取地址、余额
  • 对自定义消息进行签名
  • 发起 ETH 转账并确认交易

掌握这些功能后,可进一步扩展至 ERC20 代币转账、智能合约交互等复杂场景。实际开发中需注重用户体验(如加载状态、操作反馈)和安全性(避免私钥泄露、验证输入合法性)。

如有疑问,欢迎在评论区交流!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

代码搬运媛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值