ethers.js 开发的核心场景

一、核心概念与安装(需掌握)

  • 核心定位:ethers.js 是轻量级以太坊交互库,专注于与区块链、智能合约的高效交互,相比 Web3.js 更简洁,安全性更高。
  • 安装方式
bash 复制代码
npm install ethers  # 基础安装
# 若需兼容 TypeScript,无需额外安装类型文件,库本身自带类型定义

二、Provider(需掌握)

作用:作为与区块链节点的连接层,负责读取链上数据(区块、交易、余额等),不涉及签名操作。

1. 常用 Provider 实例化
  • JsonRpcProvider(连接自定义节点,如本地 Ganache 或私链):
arduino 复制代码
// 连接本地 8545 端口的节点(Ganache 默认端口)
const provider = new ethers.providers.JsonRpcProvider('http://localhost:8545');
  • InfuraProvider(连接 Infura 公共节点,需注册获取项目 ID):
arduino 复制代码
// 连接以太坊主网('mainnet'),替换为你的 Infura 项目 ID
const provider = new ethers.providers.InfuraProvider(
  'mainnet', 
  'your-infura-project-id-here'
);
// 支持测试网:'goerli'、'sepolia' 等
const goerliProvider = new ethers.providers.InfuraProvider('goerli', 'your-id');
2. 核心方法及示例
  • getBlockNumber() :获取当前区块高度
javascript 复制代码
const blockNumber = await provider.getBlockNumber();
console.log('当前区块号:', blockNumber); // 输出类似:18000000
  • getBalance(address) :获取指定地址的 ETH 余额(单位:wei)
ini 复制代码
const address = '0x742d35Cc6634C0532925a3b844Bc454e4438f44e'; // 示例地址
const balanceWei = await provider.getBalance(address);
// 转换为以太单位(1 ETH = 1e18 wei)
const balanceEth = ethers.utils.formatEther(balanceWei);
console.log('ETH 余额:', balanceEth); // 输出类似:'1.2345'
  • getTransaction(transactionHash) :根据交易哈希查询交易详情
csharp 复制代码
const txHash = '0x0a8...'; // 交易哈希(66 字符,0x 开头)
const transaction = await provider.getTransaction(txHash);
console.log('交易详情:', {
  from: transaction.from,    // 发送地址
  to: transaction.to,        // 接收地址(合约调用时为合约地址)
  value: ethers.utils.formatEther(transaction.value), // 转账金额(ETH)
  gasPrice: ethers.utils.formatUnits(transaction.gasPrice, 'gwei'), // gas 价格(gwei)
  blockNumber: transaction.blockNumber // 所在区块号
});
  • getBlock(blockNumber) :获取指定区块的详细信息
javascript 复制代码
const block = await provider.getBlock(18000000); // 传入区块号
console.log('区块信息:', {
  hash: block.hash,         // 区块哈希
  timestamp: new Date(block.timestamp * 1000), // 区块时间(转换为北京时间)
  transactions: block.transactions.length     // 区块内交易数量
});
  • getCode(address) :获取地址的合约字节码(判断是否为合约地址,普通地址返回 0x)
javascript 复制代码
const isContract = await provider.getCode(address);
console.log('是否为合约:', isContract !== '0x'); // 合约地址返回 true

三、Signer(需掌握)

作用:代表一个以太坊账户,具备签名交易和消息的能力,可发送交易(修改链上状态)。

1. 常用 Signer 实例化
  • 从私钥创建(适用于后端或测试环境,私钥需保密):
arduino 复制代码
// 私钥(64 字符,0x 开头)
const privateKey = '0x123...'; // 实际开发中从环境变量获取,避免硬编码
const signer = new ethers.Wallet(privateKey, provider); // 关联 provider
  • 从浏览器钱包获取(如 MetaMask,适用于前端):
javascript 复制代码
// 假设页面已注入 window.ethereum(MetaMask 提供)
await window.ethereum.enable(); // 请求用户授权
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner(); // 获取当前选中的账户签名器
2. 核心方法及示例
  • getAddress() :获取签名者地址
javascript 复制代码
const signerAddress = await signer.getAddress();
console.log('签名者地址:', signerAddress); // 输出类似:'0xabc...'
  • sendTransaction(transaction) :发送 ETH 转账交易
javascript 复制代码
const toAddress = '0x123...'; // 接收地址
const transaction = {
  to: toAddress,
  value: ethers.utils.parseEther('0.01') // 转账 0.01 ETH(转换为 wei)
};
// 发送交易并等待确认(返回交易收据)
const txResponse = await signer.sendTransaction(transaction);
const txReceipt = await txResponse.wait(); // 等待区块确认(默认 1 个确认)
console.log('交易确认:', txReceipt.transactionHash); // 输出交易哈希
  • signMessage(message) :对消息进行签名(用于身份验证)
ini 复制代码
const message = '请确认登录,时间:' + new Date().toISOString();
const signature = await signer.signMessage(message);
console.log('消息签名:', signature); // 输出 132 字符的签名
// 验证签名(可选,用于后端校验)
const recoveredAddress = ethers.utils.verifyMessage(message, signature);
console.log('签名是否匹配:', recoveredAddress === signerAddress); // true

四、Contract(需掌握)

作用:与智能合约交互的核心类,需传入合约地址、ABI 和 Signer/Provider(只读操作可用 Provider,写操作需 Signer)。

1. 实例化 Contract
arduino 复制代码
// 合约地址(示例:USDC 合约主网地址)
const contractAddress = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
// ABI(仅需包含调用的函数/事件,可从 Etherscan 或编译输出中获取)
const abi = [
  'function balanceOf(address) view returns (uint256)', // 只读方法
  'function transfer(address to, uint256 amount) returns (bool)' // 写方法
];
// 实例化合约(写操作需传入 signer,只读操作可传入 provider)
const contract = new ethers.Contract(contractAddress, abi, signer);
2. 调用合约方法
  • 调用 view/pure 方法(只读,不产生交易):
ini 复制代码
// 调用 ERC20 的 balanceOf 方法查询余额(单位:代币最小单位,如 USDC 为 6 位小数)
const userAddress = '0x742d...';
const balanceWei = await contract.balanceOf(userAddress); // 返回 BigNumber
// 转换为可读格式(USDC 精度为 6,即 1 USDC = 1e6 最小单位)
const balanceUsdc = ethers.utils.formatUnits(balanceWei, 6);
console.log('USDC 余额:', balanceUsdc); // 输出类似:'100.50'
  • 调用修改状态的方法(产生交易,需签名):
ini 复制代码
// 调用 ERC20 的 transfer 方法转账
const to = '0x123...'; // 接收地址
const amount = ethers.utils.parseUnits('50', 6); // 转账 50 USDC(转换为最小单位)
const txResponse = await contract.transfer(to, amount);
const txReceipt = await txResponse.wait(); // 等待交易确认
console.log('转账成功,交易哈希:', txReceipt.transactionHash);
3. 监听合约事件
javascript 复制代码
// 监听 ERC20 的 Transfer 事件(事件名区分大小写)
contract.on('Transfer', (from, to, value, event) => {
  console.log('Transfer 事件:');
  console.log('从:', from);
  console.log('到:', to);
  console.log('金额(USDC):', ethers.utils.formatUnits(value, 6));
  console.log('事件详情:', event); // 包含事件所在区块、日志等信息
});
// 停止监听(避免内存泄漏)
// contract.removeAllListeners('Transfer');

五、ABI 与合约交互细节(需掌握)

  • ABI 结构:JSON 数组,每个元素描述函数或事件,例如:
bash 复制代码
[
  {
    "constant": true, // view/pure 方法为 true
    "inputs": [{"name": "owner", "type": "address"}],
    "name": "balanceOf",
    "outputs": [{"name": "", "type": "uint256"}],
    "type": "function"
  },
  {
    "anonymous": false,
    "inputs": [
      {"indexed": true, "name": "from", "type": "address"},
      {"indexed": true, "name": "to", "type": "address"},
      {"indexed": false, "name": "value", "type": "uint256"}
    ],
    "name": "Transfer",
    "type": "event"
  }
]
    • 函数的 constant: true 对应 Solidity 的 view/pure,调用时无需交易。
    • 事件的 indexed 字段表示该参数可用于过滤(最多 3 个)。
  • 函数调用参数处理
    • 基本类型(uint256、address 等)直接传入对应值。
    • 数组类型需传入 JavaScript 数组,例如 [1, 2, 3]。
    • 结构体需按 ABI 定义的顺序传入字段值。

六、Utils 工具函数(需掌握部分)

1. 单位转换
  • parseEther(etherString) :将 ETH 字符串转换为 wei(BigNumber)
arduino 复制代码
const oneEthInWei = ethers.utils.parseEther('1.0'); // 1e18 wei
console.log(oneEthInWei.toString()); // '1000000000000000000'
  • formatEther(wei) :将 wei 转换为 ETH 字符串
ini 复制代码
const wei = ethers.BigNumber.from('2500000000000000000'); // 2.5 ETH
const eth = ethers.utils.formatEther(wei); // '2.5'
  • parseUnits(value, decimals) :通用单位转换(适用于代币,如 USDC 为 6 位小数)
arduino 复制代码
// 50 USDC(6 位小数)转换为最小单位
const usdcAmount = ethers.utils.parseUnits('50', 6); // 50 * 1e6 = 50000000
  • formatUnits(wei, decimals) :反向转换(代币最小单位转可读格式)
ini 复制代码
const usdcInSmallestUnit = ethers.BigNumber.from('12345678'); // 12.345678 USDC
const usdc = ethers.utils.formatUnits(usdcInSmallestUnit, 6); // '12.345678'
2. 地址操作
  • isAddress(address) :验证地址合法性(返回布尔值)
arduino 复制代码
console.log(ethers.utils.isAddress('0x742d35Cc6634C0532925a3b844Bc454e4438f44e')); // true
console.log(ethers.utils.isAddress('invalid-address')); // false
  • getAddress(address) :标准化地址(转换为 checksum 格式,大小写区分)
ini 复制代码
const normalized = ethers.utils.getAddress('0x742d35cc6634c0532925a3b844bc454e4438f44e');
console.log(normalized); // '0x742d35Cc6634C0532925a3b844Bc454e4438f44e'(带大小写)

七、错误处理(需掌握)

区块链交互可能因网络、Gas、权限等原因失败,需用 try/catch 捕获错误。

javascript 复制代码
async function sendTransaction() {
  try {
    const txResponse = await signer.sendTransaction({
      to: '0x123...',
      value: ethers.utils.parseEther('0.01')
    });
    console.log('交易发送成功,哈希:', txResponse.hash);
    const receipt = await txResponse.wait();
    console.log('交易确认,区块:', receipt.blockNumber);
  } catch (error) {
    // 常见错误处理
    if (error.code === ethers.errors.CALL_EXCEPTION) {
      console.error('合约调用失败(可能是方法不存在或参数错误)');
    } else if (error.code === ethers.errors.INSUFFICIENT_FUNDS) {
      console.error('余额不足,无法支付转账金额或 Gas');
    } else if (error.message.includes('User rejected transaction')) {
      console.error('用户拒绝了交易签名(MetaMask 等钱包)');
    } else {
      console.error('未知错误:', error.message);
    }
  }
}

以上内容覆盖了 ethers.js 开发的核心场景,掌握这些函数和用法后,可应对绝大多数智能合约交互、交易处理和链上数据查询需求。实际开发中,建议结合官方文档(docs.ethers.io/v5/)和具体场景灵活运用。

相关推荐
dingzd955 小时前
如何轻松解除Facebook封锁
web3·互联网·facebook·tiktok·instagram·指纹浏览器·clonbrowser
清 晨5 小时前
创建多个Facebook账号的终极解决方案
web3·互联网·facebook·tiktok·instagram·指纹浏览器·clonbrowser
木西6 小时前
React Native DApp 开发全栈实战·从 0 到 1 系列(expo-router)
react native·web3·app
清 晨3 天前
Web3.0引领互联网未来,助力安全防护升级
安全·web3·互联网·facebook·tiktok·instagram·clonbrowser
运维开发王义杰3 天前
Web3: 用ERC-1400革新公司股权激励
web3
加速财经3 天前
WEEX参与欧洲两场重要Web3线下活动,助力社区协作与技术交流
人工智能·web3
Sui_Network4 天前
Walrus 与 Pipe Network 集成,提升多链带宽并降低延迟
人工智能·web3·区块链·智能合约·量子计算
idaretobe4 天前
宝龙地产债务化解解决方案二:基于资产代币化与轻资产转型的战略重构
人工智能·web3·去中心化·区块链·智能合约·信任链
元宇宙时间5 天前
引领GameFi 2.0新范式:D.Plan携手顶级财经媒体启动“龙珠创意秀”
人工智能·web3·区块链