Ethers.js 实战:带你掌握 Web3 区块链开发
Table of Contents
Ethers.js 实战:带你掌握 Web3 区块链开发
Web3 时代已来,区块链开发成为技术圈的热门技能。如何快速上手与以太坊交互?Ethers.js 作为一款轻量又强大的工具,能帮你轻松搞定查询、交易和智能合约部署。本文通过一个实战脚本,带你一步步掌握 Web3 区块链开发的核心技能,无论你是新手还是老司机,都能在这里找到实操灵感!
本文基于 Ethers.js 提供了一个 TypeScript 实战案例,涵盖连接区块链、查询区块和余额、发送交易以及部署智能合约的全过程。代码清晰拆解了每个步骤的功能,从初始化提供者到调用合约方法,手把手带你掌握 Web3 开发技巧。运行结果一目了然,助你快速上手区块链编程。
实操
import { Contract, ethers, Wallet } from 'ethers';
import config from './config';
import { ABI, BYTECODE } from "./abi/storage"
async function main() {
const provider = new ethers.JsonRpcProvider(config.localRpcUrl);
const blockNumber = await provider.getBlockNumber();
console.log(`blockNumber: ${blockNumber}`);
const wallet = new ethers.Wallet(config.privateKey, provider);
// const wallet = new Wallet(config.privateKey, provider);
const walletAddress = await wallet.getAddress();
console.log("wallet address: ", wallet.address);
console.log("wallet address: ", walletAddress);
const balance = await provider.getBalance(walletAddress);
console.log("balance: ", balance.toString());
const nonce = await provider.getTransactionCount(walletAddress);
console.log("nonce: ", nonce);
const tx = await wallet.sendTransaction({
to: config.accountAddress2,
value: ethers.parseEther('0.1'),
nonce: nonce,
})
await tx.wait();
const txHash = tx.hash;
console.log("tx hash: ", txHash);
const txReceipt = await provider.getTransactionReceipt(txHash);
console.log("tx receipt: ", txReceipt);
const factory = new ethers.ContractFactory(ABI, BYTECODE, wallet)
const contract = await factory.deploy()
// 4. 等待部署确认
await contract.waitForDeployment()
const contractAddress = await contract.getAddress();
const contractAddress1 = contract.target.toString()
console.log("contract address: ", contractAddress)
console.log("contract address1: ", contractAddress1)
const deployedContract = new Contract(contractAddress, ABI, provider)
const retrieve = await deployedContract.retrieve()
console.log("retrieve: ", retrieve.toString())
}
main().catch((error) => {
console.error("Error:", error);
process.exit(1);
});
这是一个使用 ethers.js 库与以太坊区块链交互的 JavaScript/TypeScript 脚本,主要功能包括查询信息、发送交易和部署智能合约。
代码结构和功能分解
导入部分
import { Contract, ethers, Wallet } from 'ethers';
import config from './config';
import { ABI, BYTECODE } from "./abi/storage";
- 从 ethers 库中导入了三个核心模块:
- Contract: 用于与已部署的智能合约交互。
- ethers: 提供主要工具和方法。
- Wallet: 用于管理私钥和签名交易。
- config: 自定义配置文件,通常包含 RPC URL、私钥等敏感信息。
- ABI 和 BYTECODE: 从 ./abi/storage 文件导入,分别是智能合约的应用二进制接口(ABI)和字节码,通常由 Solidity 编译器生成。
主函数 main
async function main() {
这是一个异步函数,因为区块链操作(如查询、交易)需要等待网络响应。
初始化提供者(Provider)
const provider = new ethers.JsonRpcProvider(config.localRpcUrl);
- 创建一个 JSON-RPC 提供者,用于连接以太坊节点(这里使用 config.localRpcUrl 定义的本地或远程节点)。
- 提供者负责与区块链通信,例如查询数据或发送交易。
查询区块高度
const blockNumber = await provider.getBlockNumber();
console.log(`blockNumber: ${blockNumber}`);
- getBlockNumber(): 获取当前区块链的最新区块高度。
- 输出结果到控制台,用于确认连接是否正常。
创建钱包
const wallet = new ethers.Wallet(config.privateKey, provider);
- 使用私钥(从 config.privateKey 获取)和提供者初始化一个钱包对象。
- 钱包用于签名交易和与区块链交互。
获取钱包地址
const walletAddress = await wallet.getAddress();
console.log("wallet address: ", wallet.address);
console.log("wallet address: ", walletAddress);
- getAddress(): 获取钱包的公钥地址。
- 这里输出了两次地址:
- wallet.address: 直接访问钱包对象的属性。
- walletAddress: 变量存储的地址。
- 两者的值相同,为了验证一致性。
查询余额
const balance = await provider.getBalance(walletAddress);
console.log("balance: ", balance.toString());
- getBalance(): 查询指定地址的以太币余额(单位为 wei)。
- toString(): 将余额从 BigInt 转换为字符串以便显示。
获取交易计数(Nonce)
const nonce = await provider.getTransactionCount(walletAddress);
console.log("nonce: ", nonce);
- getTransactionCount(): 获取该地址的交易计数,用于设置交易的 nonce 值(防止交易重复)。
- nonce 是交易的一个重要参数,必须与链上状态匹配。
发送交易
const tx = await wallet.sendTransaction({
to: config.accountAddress2,
value: ethers.parseEther('0.1'),
nonce: nonce,
});
await tx.wait();
- sendTransaction(): 发送一笔交易:
- to: 目标地址(从 config.accountAddress2 获取)。
- value: 发送 0.1 ETH(parseEther 将以太单位转换为 wei)。
- nonce: 使用之前查询的交易计数。
- tx.wait(): 等待交易被矿工确认并写入区块链。
获取交易哈希和收据
const txHash = tx.hash;
console.log("tx hash: ", txHash);
const txReceipt = await provider.getTransactionReceipt(txHash);
console.log("tx receipt: ", txReceipt);
- tx.hash: 获取交易的哈希值,用于唯一标识这笔交易。
- getTransactionReceipt(): 获取交易收据,包含交易的状态、消耗的 gas 等信息。
部署智能合约
const factory = new ethers.ContractFactory(ABI, BYTECODE, wallet);
const contract = await factory.deploy();
await contract.waitForDeployment();
- ContractFactory: 使用 ABI、字节码和钱包创建一个合约工厂。
- deploy(): 部署智能合约到区块链。
- waitForDeployment(): 等待合约部署完成(即交易被确认)。
获取合约地址
const contractAddress = await contract.getAddress();
const contractAddress1 = contract.target.toString();
console.log("contract address: ", contractAddress);
console.log("contract address1: ", contractAddress1);
- getAddress(): 获取已部署合约的地址。
- contract.target: 直接访问合约对象的目标地址(与 getAddress() 等效)。
- 两种方式的结果相同,输出是为了验证。
与合约交互
const deployedContract = new Contract(contractAddress, ABI, provider);
const retrieve = await deployedContract.retrieve();
console.log("retrieve: ", retrieve.toString());
- 创建一个合约实例,连接到已部署的合约地址。
- retrieve(): 调用合约的 retrieve 方法。
- 输出结果,转换为字符串显示。
错误处理
main().catch((error) => {
console.error("Error:", error);
process.exit(1);
});
- 使用 catch 捕获 main 函数中的任何错误。
- 如果发生错误,打印错误信息并退出程序(退出码 1 表示异常)。
运行
➜ ts-node src/main.ts
blockNumber: 0
wallet address: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
wallet address: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
balance: 10000000000000000000000
nonce: 0
tx hash: 0x1f4b6e1c13d6374c8fabce903e1b3cc947d75be53a8c49b555a63e21b2388d16
tx receipt: TransactionReceipt {
provider: JsonRpcProvider {},
to: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
from: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
contractAddress: null,
hash: '0x1f4b6e1c13d6374c8fabce903e1b3cc947d75be53a8c49b555a63e21b2388d16',
index: 0,
blockHash: '0x9f33e46ed0d4382e849e04e0dee4433c676d9f43c1eb6f0076676bd0251f9fb6',
blockNumber: 1,
logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
gasUsed: 21000n,
blobGasUsed: null,
cumulativeGasUsed: 21000n,
gasPrice: 2000000000n,
blobGasPrice: 1n,
type: 2,
status: 1,
root: undefined
}
contract address: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
contract address1: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
retrieve: 0
总结
通过这个 Ethers.js 实战案例,我们从零开始探索了 Web3 区块链开发的关键环节。无论是发送一笔交易还是部署自己的智能合约,Ethers.js 都展现了简单高效的魅力。掌握这些技能,你就迈出了构建去中心化应用的第一步。接下来,不妨动手试试,把代码跑起来,开启你的 Web3 开发之旅吧!
参考
- https://etherscan.io/
- https://docs.ethers.org/v6/
- https://solidity-by-example.org/
- https://soliditylang.org/
- https://viem.sh/
- https://guoyu.mirror.xyz/RD-xkpoxasAU7x5MIJmiCX4gll3Cs0pAd5iM258S1Ek
- https://web3js.readthedocs.io/en/v1.7.3/

