前言在以太坊生态中,ethers.js是开发者与区块链交互的核心工具包。本文系统梳理了其六大核心模块(Provider、Contract、Wallet、Utils、部署工具及高级功能),通过代码示例+关键差异对比+安全实践,帮助开发者快速掌握从环境搭建到链上交互的全流程。无论是浏览器端
在以太坊生态中,
ethers.js
是开发者与区块链交互的核心工具包。本文系统梳理了其六大核心模块(Provider、Contract、Wallet、Utils、部署工具及高级功能),通过代码示例 + 关键差异对比 + 安全实践,帮助开发者快速掌握从环境搭建到链上交互的全流程。无论是浏览器端轻量集成,还是 Node.js 服务端深度开发,本文均提供可直接落地的解决方案安装
链接方式
# 在页面上使用链接使用 <script type="module"> import { ethers } from "https://cdnjs.cloudflare.com/ajax/libs/ethers/6.7.0/ethers.min.js"; </script>
安装包方式
# 项目中引入包 npm install ethers import {ethers} from "ethers"; import { BrowserProvider, parseUnits } from "ethers"; import { HDNodeWallet } from "ethers/wallet";
Provider提供者类
通过Provider类,读取链上的信息;
- ethers.BrowserProvider
#和钱包插件交 链接钱包插件读取钱包账号的信息 import { ethers } from "https://cdnjs.cloudflare.com/ajax/libs/ethers/6.7.0/ethers.min.js"; const provider = new ethers.BrowserProvider(window.ethereum);
- ethers.JsonRpcProvider
import { ethers } from "https://cdnjs.cloudflare.com/ajax/libs/ethers/6.7.0/ethers.min.js"; # 注册infura 创意一个项目获取your-infura-project-id ,读取sepolia链上的信息 const ALCHEMY_MAINNET_URL="https://sepolia.infura.io/v3/{your-infura-project-id}" const provider=new ethers.JsonRpcProvider(ALCHEMY_MAINNET_URL); or # 启动ganach # 读取本地ganach const provider = new ethers.JsonRpcProvider("http://127.0.0.1:7545");
区别
特性 ethers.BrowserProvider
ethers.JsonRpcProvider
用途 连接到用户的钱包(如 MetaMask) 连接到远程以太坊节点(如 Infura、Alchemy) 依赖 依赖 window.ethereum
依赖远程节点的 JSON-RPC 接口 用户友好 高(用户直接使用钱包) 低(需要配置远程节点) 安全性 高(私钥存储在本地钱包) 低(需要信任远程节点) 功能 有限(依赖钱包功能) 强大(访问节点全部功能) 适用场景 浏览器环境,用户交互 服务器端或无钱包环境 Provider常见属性和方法
属性
blockNumber
:返回Provider
已经知晓的最新区块号(块高),如果没有同步到区块,则为null
。polling
:可变属性,表示Provider
是否正在轮询。轮询可以设置为临时启用/禁用或永久禁用以允许节点进程退出。pollingInterval
:可变属性,表示Provider
的轮询频率(以毫秒为单位)。默认时间间隔为 4 秒方法
getNetwork()
:获取当前连接的网络信息const ALCHEMY_MAINNET_URL="https://sepolia.infura.io/v3/{your-infura-project-id}" const provider=new ethers.JsonRpcProvider(ALCHEMY_MAINNET_URL); const network = await provider.getNetwork(); # 网络名 console.log("Network name:", network.name);//sepolia # 网络id console.log("Chain ID:", network.chainId);//11155111
getBalance(address)
:获取指定地址的余额
# 节点公钥
例如:0xEb9e88cE633B2a8F400xxxxxxxxx
const balance = await provider.getBalance("0xEb9e88cE633B2a8F400xxxxxxxxx");
console.log("Balance:", ethers.formatEther(balance)); // 把wei格式化为 ETH
getTransaction(transactionHash)
:获取指定交易的详细信息。
const ALCHEMY_MAINNET_URL="https://sepolia.infura.io/v3/{your-infura-project-id}"
const provider=new ethers.JsonRpcProvider(ALCHEMY_MAINNET_URL);
//通过交易hash:在sepolia.etherscan浏览器器上找一个交易hash:例如:0xb1fd8ca5493460bb7d9d1ae7d0a96fcd7a77c3eea53954f9ab6ae6225019972b验证
const transaction = await provider.getTransaction("0xYourTransactionHashHere");
console.log("Transaction from:", transaction.from);
console.log("Transaction to:", transaction.to);
console.log("Transaction value:", ethers.formatEther(transaction.value));
getTransactionReceipt(transactionHash)
:获取指定交易的收据信息。
const ALCHEMY_MAINNET_URL="https://sepolia.infura.io/v3/{your-infura-project-id}"
const provider=new ethers.JsonRpcProvider(ALCHEMY_MAINNET_URL);
//通过交易hash:在sepolia.etherscan浏览器器上找一个交易hash:例如:0xb1fd8ca5493460bb7d9d1ae7d0a96fcd7a77c3eea53954f9ab6ae6225019972b验证
const receipt = await provider.getTransactionReceipt("0xYourTransactionHashHere");
console.log("Transaction status:", receipt.status);
console.log("Transaction logs:", receipt.logs);
sendTransaction(signedTransaction)
:发送一个已签名的交易。
const txHash = await provider.sendTransaction(signedTransaction);
console.log("Transaction hash:", txHash);
getSigner(address)
:获取与指定地址关联的 Signer
对象。
const signer = provider.getSigner("0xYourAddressHere");
console.log("Signer address:", await signer.getAddress());
estimateGas(transaction)
:估算执行指定交易所需的 gas。
const gasEstimate = await provider.estimateGas({
to: "0xRecipientAddressHere",
from: "0xSenderAddressHere",
value: ethers.parseEther("1.0"),
});
console.log("Estimated gas:", gasEstimate.toString());
call(transaction, blockTag)
:调用一个智能合约的函数,不发送交易。
const result = await provider.call({
to: "0xContractAddressHere",
data: "0xYourEncodedFunctionCallHere",
});
console.log("Call result:", result);
getBlock(blockTag)
:获取指定区块的信息
const block = await provider.getBlock("latest");
console.log("Block number:", block.number);
console.log("Block timestamp:", block.timestamp);
getBlockTransactionCount(blockTag)
:获取指定区块中的交易数量。
const transactionCount = await provider.getBlockTransactionCount("latest");
console.log("Transaction count in block:", transactionCount);
resolveName(ensName)
:获取 ensName
对应地址的 Promise,如果没有则为 null
。
provider.resolveName("registrar.firefly.eth").then(function(address) {
console.log("Address: " + address);
// "0x6fC21092DA55B392b045eD78F4732bff3C580e2c"
});
lookupAddress(address)
:获取 address
对应的 ENS 名称的 Promise,如果没有则为 null
。
let address = "0x6fC21092DA55B392b045eD78F4732bff3C580e2c";
provider.lookupAddress(address).then(function(name) {
console.log("Name: " + name);
// "registrar.firefly.eth"
});
# 说明: 使用hardhat 部署成功后会在控制台返回合约地址 abi 在artifacts/contracts/中的json中取出abi数组
# 引入包
import { ethers } from 'https://cdnjs.cloudflare.com/ajax/libs/ethers/6.7.0/ethers.min.js';
//const provider = new ethers.BrowserProvider(window.ethereum);
const provider = new ethers.JsonRpcProvider("http://127.0.0.1:8545");
# 创建合约
const TokenAddress="0xxxxxxxxxx";
const const TokenABI =[{
"inputs": [],
"name": "name",
"outputs": [{"type": "string"}],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "symbol",
"outputs": [{"type": "string"}],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "totalSupply",
"outputs": [{"type": "uint256"}],
"stateMutability": "view",
"type": "function"
}
//其他更多
]
const TokenContract = new ethers.Contract(TokenAddress, TokenABI, provider);
# 代币名
const name = await TokenContract.name();
console.log("Contract Name:", name);
# 代币符合
const symbol = await TokenContract.symbol();
console.log("Contract Symbol:", symbol);
# 代币总额
const totalSupply = await TokenContract.totalSupply();
import { ethers } from 'https://cdnjs.cloudflare.com/ajax/libs/ethers/6.7.0/ethers.min.js';
//const provider = new ethers.BrowserProvider(window.ethereum);
const provider = new ethers.JsonRpcProvider("http://127.0.0.1:8545");
# 创建合约
const TokenAddress="0xxxxxxxxxx";
const const TokenABI =[];
const signer = await provider.getSigner();
const TokenContract = new ethers.Contract(TokenAddress, TokenABI, singer);
# 交互操作 转账
const addr1="0xxxxxxxxxx";
# 给addr1转1LYTH
const tx= await TokenContract.transfer(addr1,1);
# 等待交易成功
await tx.wait()
console.log("查看账号addr1的余额",await TokenContract.balanceOf(addr1))
console.log("查看账号signer的余额",await TokenContract.balanceOf(signer))
const { ethers } = require("hardhat");
async function deployContract() {
try {
const [signer] = await ethers.getSigners();//签名者
//通过 npx hardhat compile编译合约,在artifacts/contracts/xxx.sol/xxx.json中复制abi数组和bytecode码
const abi=[]//
const bytecode="";//
const deployFactory = new ethers.ContractFactory(abi,bytecode,signer)//工厂合约
const TokenContract = await deployFactory.deploy();//部署
console.log("部署合约交易详情",TokenContract.deploymentTransaction())
await TokenContract.waitForDeployment();//等待部署成功
console.log("Token deployed at:", TokenContract.target);//合约地址
# 调用合约的方法和交互
console.log(`合约代号: ${await TokenContract.name()`)
console.log(`合约代号: ${await TokenContract.symbol()}`)
console.log(`合约代号: ${await TokenContract.totalSupply()}`)
const addr1="0xxxxxxx"
const tx= await TokenContract.transfer(addr1,1);//向addr1转1
console.log("Transfer Transaction:", tx);
const balance = await TokenContract.balanceOf(addr1);//查看addr1余额
console.log("Balance:", balance.toString());
console.log(await TokenContract.balanceOf(signer))//查看signer余额
}catch (error) {
console.log(error)
}
}
const Wallet=ethers.Wallet.createRandom();
# 公钥
console.log("Address:", Wallet.address);
# 私钥
console.log("Private Key:", Wallet.privateKey);
# 助记词
console.log("Mnemonic:", Wallet.mnemonic.phrase);
const private=new ethers.JsonRpcProvider("http://127.0.1:8545");
const privateKey = "acxxxxxxxxx";//私钥
const wallet = new ethers.Wallet(privateKey,private);
console.log("Wallet address:", wallet);//钱包公钥
# 助记词
const Mnemonic="quote shy web universe book wheat turtle cabin degree permit beach capable";//12个不同的单词()
const wallet3 = ethers.Wallet.fromPhrase(Mnemonic);
console.log("Wallet3:", wallet3);
console.log("Address:", wallet3.address);
console.log("Private Key:", wallet3.privateKey);
console.log("Mnemonic:", wallet3.mnemonic.phrase);
async function creactKeystoreV3() {
const wallet = ethers.Wallet.createRandom();
// 2. 加密为 Keystore V3 JSON
const password="xxxxxx";//密码
const json = await wallet.encrypt(password);
// 3. 保存到文件
require("fs").writeFileSync("keystore.json", json);
console.log("JSON:", json);
}
creactKeystoreV3();//会在当前页面生成一个keystore.json文件
async function creatWalletJson() {
console.log("开始读取json文件");
const json=require("fs").readFileSync("keystore.json", "utf8");
const password="xxxxxx"
const walletJson =await ethers.Wallet.fromEncryptedJson(json, password);//json文件和密码
console.log("Wallet from JSON:",walletJson);
console.log("Address:", walletJson.address);//钱包地址
console.log("Private Key:", walletJson.privateKey);//私钥
console.log("Mnemonic:", walletJson.mnemonic.phrase);//助记词
}
creatWalletJson();
async function sendTransactionFn() { const private=new ethers.JsonRpcProvider("http://127.0.1:8545"); const privateKey = "xxx";//私钥 const wallet = new ethers.Wallet(privateKey,private); const address1="0xxxxx";//账号1公钥 const tx={ to:address1, value:ethers.parseEther("100"),//转移100eth }// //执行交易 const txRes = await wallet2.sendTransaction(tx); const receipt = await txRes.wait() // 等待链上确认交易 console.log(receipt) // 打印交易的收据 } sendTransactionFn(); // 把公钥导入MetaMask插件中导入在账号可以查看账号余额的变化
# Utils工具类
| 工具方法 | 典型用途 | 示例代码 |
| :------------------------- | :-------------------- | :----------------------------- |
| `parseUnits`/`formatUnits` | 处理代币单位转换(如 ETH ↔ Wei) | `ethers.parseUnits("1.5", 18)` |
| `keccak256` | 生成哈希(如事件签名、地址校验) | `ethers.keccak256("0x1234")` |
| `toChecksumAddress` | 校验并标准化地址格式 | `ethers.getAddress("0x...")` |
| `hexlify`/`hexStripZeros` | 处理十六进制字符串 | `ethers.hexlify([1, 2, 3])` |
| `randomBytes` | 生成安全随机数 | `ethers.randomBytes(32)`
# 总结
通过上述实践,我们系统梳理了 ethers.js 核心模块,在开发中的典型应用场景与最佳实践,为高效构建区块链交互提供了可复用的技术方案。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!