Ethers.js基础

核心知识点讲解

Ethers.js简介

Ethers.js是一个轻量级的JavaScript库,用于与以太坊网络进行交互:

  • 轻量级:比Web3.js更小,加载更快
  • 易于使用:API设计更加简洁直观
  • 功能完整:支持所有以太坊交互功能
  • 钱包集成:内置钱包功能
  • 类型安全:TypeScript支持良好

Ethers.js安装与配置

安装方式

# 使用npm安装
npm install ethers

# 使用yarn安装
yarn add ethers

基本配置

// 引入Ethers.js
const { ethers } = require('ethers');

// 创建Provider
// 连接到本地节点
const provider = new ethers.JsonRpcProvider('http://localhost:8545');

// 连接到Infura节点
const provider = new ethers.JsonRpcProvider('https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY');

// 连接到MetaMask
if (window.ethereum) {
  const provider = new ethers.BrowserProvider(window.ethereum);
  // 请求用户授权
  const signer = await provider.getSigner();
}

Ethers.js核心功能

1. Provider

  • 连接网络:连接到以太坊网络
  • 查询数据:查询区块、交易和账户信息
  • 估算Gas:估算交易Gas消耗
  • 获取网络信息:获取网络ID、链ID等信息

2. Signer

  • 管理账户:管理以太坊账户
  • 签名交易:签名并发送交易
  • 签名消息:签名消息进行身份验证
  • 获取账户信息:获取账户地址、余额等

3. Contract

  • 部署合约:部署智能合约
  • 调用方法:调用合约的读取方法
  • 发送交易:调用合约的写入方法
  • 监听事件:监听合约事件

实用案例分析

连接以太坊网络

// 连接到以太坊网络
const { ethers } = require('ethers');

// 连接到本地Ganache节点
const provider = new ethers.JsonRpcProvider('http://localhost:8545');

// 连接到Infura的Sepolia测试网
const provider = new ethers.JsonRpcProvider('https://sepolia.infura.io/v3/YOUR_INFURA_API_KEY');

// 检查连接状态
async function checkConnection() {
  try {
    const network = await provider.getNetwork();
    console.log('Connected to network:', network.name, '(ID:', network.chainId, ')');
    
    const blockNumber = await provider.getBlockNumber();
    console.log('Current block number:', blockNumber);
    
    return true;
  } catch (error) {
    console.error('Connection error:', error);
    return false;
  }
}

checkConnection();

钱包管理

// 钱包管理
const { ethers } = require('ethers');
const provider = new ethers.JsonRpcProvider('http://localhost:8545');

// 创建钱包
function createWallet() {
  const wallet = ethers.Wallet.createRandom();
  console.log('New wallet address:', wallet.address);
  console.log('Private key:', wallet.privateKey);
  console.log('Mnemonic:', wallet.mnemonic.phrase);
  return wallet;
}

// 从私钥创建钱包
function createWalletFromPrivateKey(privateKey) {
  const wallet = new ethers.Wallet(privateKey, provider);
  console.log('Wallet address:', wallet.address);
  return wallet;
}

// 从助记词创建钱包
function createWalletFromMnemonic(mnemonic) {
  const wallet = ethers.Wallet.fromPhrase(mnemonic, provider);
  console.log('Wallet address:', wallet.address);
  return wallet;
}

// 获取钱包余额
async function getWalletBalance(wallet) {
  try {
    const balance = await wallet.getBalance();
    const balanceInEther = ethers.formatEther(balance);
    console.log('Wallet balance:', balanceInEther, 'ETH');
    return balanceInEther;
  } catch (error) {
    console.error('Error getting balance:', error);
    return '0';
  }
}

// 示例用法
async function main() {
  const wallet = createWallet();
  await getWalletBalance(wallet);
  
  // 从私钥创建钱包
  // const privateKey = '0x1234567890123456789012345678901234567890123456789012345678901234';
  // const walletFromPrivateKey = createWalletFromPrivateKey(privateKey);
  // await getWalletBalance(walletFromPrivateKey);
}

main();

智能合约交互

// 智能合约交互
const { ethers } = require('ethers');
const provider = new ethers.JsonRpcProvider('http://localhost:8545');

// 合约ABI
const contractABI = [
  {
    "inputs": [{"internalType": "uint256", "name": "_value", "type": "uint256"}],
    "name": "setValue",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "getValue",
    "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "anonymous": false,
    "inputs": [{"indexed": false, "internalType": "uint256", "name": "value", "type": "uint256"}],
    "name": "ValueChanged",
    "type": "event"
  }
];

// 合约地址
const contractAddress = '0x1234567890123456789012345678901234567890';

// 获取签名者
async function getSigner() {
  // 从私钥创建签名者
  const privateKey = '0x1234567890123456789012345678901234567890123456789012345678901234';
  const signer = new ethers.Wallet(privateKey, provider);
  return signer;
}

// 创建合约实例
async function createContract() {
  const signer = await getSigner();
  const contract = new ethers.Contract(contractAddress, contractABI, signer);
  return contract;
}

// 调用合约方法(读取)
async function getContractValue() {
  const contract = await createContract();
  try {
    const value = await contract.getValue();
    console.log('Contract value:', value.toString());
    return value;
  } catch (error) {
    console.error('Error getting contract value:', error);
    return 0;
  }
}

// 发送交易(写入)
async function setContractValue(value) {
  const contract = await createContract();
  try {
    const tx = await contract.setValue(value);
    await tx.wait();
    console.log('Transaction hash:', tx.hash);
    return tx;
  } catch (error) {
    console.error('Error setting contract value:', error);
    return null;
  }
}

// 监听事件
async function listenToEvents() {
  const contract = await createContract();
  
  contract.on('ValueChanged', (value) => {
    console.log('Event received:', value.toString());
  });
  
  console.log('Listening for events...');
}

// 示例用法
async function main() {
  await getContractValue();
  await setContractValue(42);
  await getContractValue();
  await listenToEvents();
}

main();

交易操作

// 交易操作
const { ethers } = require('ethers');
const provider = new ethers.JsonRpcProvider('http://localhost:8545');

// 获取签名者
async function getSigner() {
  // 从私钥创建签名者
  const privateKey = '0x1234567890123456789012345678901234567890123456789012345678901234';
  const signer = new ethers.Wallet(privateKey, provider);
  return signer;
}

// 发送ETH
async function sendEther(to, amount) {
  const signer = await getSigner();
  try {
    const tx = await signer.sendTransaction({
      to: to,
      value: ethers.parseEther(amount)
    });
    await tx.wait();
    console.log('Transaction hash:', tx.hash);
    return tx;
  } catch (error) {
    console.error('Error sending ether:', error);
    return null;
  }
}

// 估算Gas
async function estimateGas(to, amount) {
  try {
    const gas = await provider.estimateGas({
      to: to,
      value: ethers.parseEther(amount)
    });
    console.log('Estimated gas:', gas.toString());
    return gas;
  } catch (error) {
    console.error('Error estimating gas:', error);
    return 21000; // 默认值
  }
}

// 获取Gas价格
async function getGasPrice() {
  try {
    const gasPrice = await provider.getGasPrice();
    const gasPriceInGwei = ethers.formatUnits(gasPrice, 'gwei');
    console.log('Gas price:', gasPriceInGwei, 'Gwei');
    return gasPriceInGwei;
  } catch (error) {
    console.error('Error getting gas price:', error);
    return '0';
  }
}

// 示例用法
async function main() {
  const signer = await getSigner();
  const to = '0x9876543210987654321098765432109876543210';
  const amount = '0.01';
  
  await getGasPrice();
  await estimateGas(to, amount);
  await sendEther(to, amount);
  
  // 检查余额
  const balance = await signer.getBalance();
  console.log('Balance:', ethers.formatEther(balance), 'ETH');
}

main();

区块链查询

// 区块链查询
const { ethers } = require('ethers');
const provider = new ethers.JsonRpcProvider('http://localhost:8545');

// 获取区块信息
async function getBlock(blockNumber) {
  try {
    const block = await provider.getBlock(blockNumber);
    console.log('Block:', block);
    return block;
  } catch (error) {
    console.error('Error getting block:', error);
    return null;
  }
}

// 获取交易信息
async function getTransaction(txHash) {
  try {
    const tx = await provider.getTransaction(txHash);
    console.log('Transaction:', tx);
    return tx;
  } catch (error) {
    console.error('Error getting transaction:', error);
    return null;
  }
}

// 获取交易收据
async function getTransactionReceipt(txHash) {
  try {
    const receipt = await provider.getTransactionReceipt(txHash);
    console.log('Transaction receipt:', receipt);
    return receipt;
  } catch (error) {
    console.error('Error getting transaction receipt:', error);
    return null;
  }
}

// 获取链上信息
async function getChainInfo() {
  try {
    const network = await provider.getNetwork();
    const blockNumber = await provider.getBlockNumber();
    
    console.log('Network name:', network.name);
    console.log('Chain ID:', network.chainId);
    console.log('Current block:', blockNumber);
    
    return {
      name: network.name,
      chainId: network.chainId,
      blockNumber: blockNumber
    };
  } catch (error) {
    console.error('Error getting chain info:', error);
    return null;
  }
}

// 示例用法
async function main() {
  await getChainInfo();
  const latestBlock = await provider.getBlockNumber();
  await getBlock(latestBlock);
  
  // 假设我们有一个交易哈希
  // const txHash = '0x1234567890123456789012345678901234567890123456789012345678901234';
  // await getTransaction(txHash);
  // await getTransactionReceipt(txHash);
}

main();

实践练习

  1. 连接以太坊网络

    • 安装Ethers.js库
    • 连接到本地Ganache节点
    • 连接到Infura的测试网络
    • 检查连接状态和网络信息
  2. 钱包管理

    • 创建新钱包
    • 从私钥和助记词恢复钱包
    • 检查钱包余额
    • 发送ETH到另一个账户
  3. 智能合约交互

    • 部署一个简单的智能合约
    • 调用合约的读取方法
    • 调用合约的写入方法
    • 监听合约事件
  4. 交易操作

    • 估算交易Gas
    • 获取当前Gas价格
    • 发送交易并获取交易收据
    • 验证交易是否成功
  5. 区块链查询

    • 获取最新区块信息
    • 查询指定交易的详细信息
    • 分析区块中的交易
    • 监控网络状态

总结

Ethers.js是一个现代化的以太坊JavaScript库,它提供了与以太坊网络交互的完整功能,同时具有轻量级、易于使用的特点。通过Ethers.js,开发者可以:

  • 连接到以太坊网络:无论是主网、测试网还是本地网络
  • 管理钱包:创建钱包、签名交易、检查余额
  • 与智能合约交互:部署合约、调用方法、监听事件
  • 查询区块链数据:获取区块、交易和网络信息

Ethers.js的API设计更加简洁直观,类型安全支持良好,是构建Web3前端应用的理想选择。它与Web3.js相比,具有更小的体积和更现代的API设计,越来越受到开发者的青睐。

通过本集的学习,你应该能够理解Ethers.js的基本使用方法和核心功能,为开发Web3前端应用打下基础。

« 上一篇 Web3.js基础 下一篇 » 前端与智能合约交互