在区块链前端开发中,与钱包交互是核心功能之一。本文基于 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 逻辑
整合上述代码,注意初始化顺序和事件绑定时机。
四、注意事项与最佳实践
-
私钥安全:
生产环境中绝对不要硬编码私钥(walletPrivateKey
)!本文中activeWallet
仅为示例,实际应使用用户授权的signer
发起交易(MetaMask 会安全管理私钥)。 -
错误处理:
钱包操作可能因用户拒绝、网络问题等失败,需完善错误处理(如用户关闭 MetaMask 弹窗、余额不足等)。 -
单位转换:
区块链中金额以 wei 为单位,务必使用parseEther
(ETH → wei)和formatEther
(wei → ETH)进行转换,避免计算错误。 -
网络切换:
可通过provider.getNetwork()
检查当前网络,提示用户切换到目标链(如以太坊主网、测试网)。 -
Gas 优化:
复杂交易可手动设置gasLimit
和gasPrice
,简单转账(21000 gas)可由 MetaMask 自动估算。
五、总结
本文通过 Ethers v6 实现了与 MetaMask 的三大核心交互:
- 连接钱包并获取地址、余额
- 对自定义消息进行签名
- 发起 ETH 转账并确认交易
掌握这些功能后,可进一步扩展至 ERC20 代币转账、智能合约交互等复杂场景。实际开发中需注重用户体验(如加载状态、操作反馈)和安全性(避免私钥泄露、验证输入合法性)。
如有疑问,欢迎在评论区交流!