在区块链开发中,使用 ethers.js 读取合约信息是最基础且最重要的技能之一。ethers.js 目前的主流版本是 v6,相比旧版(v5)在 API 上更加精简和模块化。
要读取合约信息,你只需要三个核心要素:
- Provider:连接区块链的节点("读"操作不需要私钥,只需 Provider)。
- 合约地址:合约在链上的唯一标识。
- ABI (Application Binary Interface):合约的"说明书",告诉 ethers 哪些函数可以调用。
1. 核心步骤拆解
第一步:初始化 Provider
你可以使用公共的 RPC 节点(如 Alchemy、Infura)或者浏览器插件(如 MetaMask)。
javascript
import { ethers } from "ethers";
// 方式 A: 使用公共 RPC 节点 (读取链上数据常用)
const provider = new ethers.JsonRpcProvider("https://mainnet.infura.io/v3/YOUR_API_KEY");
// 方式 B: 使用浏览器钱包 (DApp 常用)
// const provider = new ethers.BrowserProvider(window.ethereum);
第二步:定义 ABI 和地址
如果你只需要读取特定功能(例如代币余额),可以使用 Human-Readable ABI(人类可读 ABI),这比复杂的 JSON 格式要简洁得多。
javascript
const contractAddress = "0x..."; // 合约地址
const abi = [
"function name() view returns (string)",
"function symbol() view returns (string)",
"function balanceOf(address) view returns (uint256)",
"function decimals() view returns (uint8)"
];
第三步:实例化合约并读取
javascript
async function readContract() {
// 创建合约实例 (地址, ABI, Provider)
const contract = new ethers.Contract(contractAddress, abi, provider);
// 调用合约的 view 函数
const name = await contract.name();
const symbol = await contract.symbol();
const decimals = await contract.decimals();
// 查询某个地址的余额
const balance = await contract.balanceOf("0xUserAddress...");
// 格式化输出 (将大数转换为人类可读的数字,如 1.5 ETH)
console.log(`代币名称: ${name}`);
console.log(`余额: ${ethers.formatUnits(balance, decimals)} ${symbol}`);
}
readContract();
2. 常见问题与进阶技巧
数据单位处理
区块链上的数值通常以"最小单位"(如 Wei)存储,没有小数点。
formatUnits(value, decimals): 将原始数据(BigInt)转为带小数点的字符串。formatEther(value): 快捷转换 18 位小数(常用于 ETH 或标准 ERC20)。
读取结构体或多个返回值
如果合约函数返回一个结构体或多个值,ethers.js 会返回一个类似数组的对象,你可以通过索引或属性名访问:
javascript
const result = await contract.getUserInfo(address);
console.log(result.name, result.age);
错误处理
网络延迟或合约地址错误会导致调用失败,建议使用 try-catch。
javascript
try {
const data = await contract.someFunction();
} catch (error) {
console.error("读取失败:", error.reason || error.message);
}
3. 学习路线建议
| 阶段 | 重点 |
|---|---|
| 入门 | 掌握 JsonRpcProvider 和 Contract 类的基本用法。 |
| 进阶 | 学习如何从 Etherscan 获取完整的 JSON ABI。 |
| 实战 | 尝试读取一个 ERC20 代币的名称、符号和总供应量。 |
| 高级 | 学习 StaticCall(模拟交易执行而不发送)和事件监听 contract.on。 |