Ethers.js 实战:带你掌握 Web3 区块链开发

Ethers.js实战:带你掌握Web3区块链开发Web3时代已来,区块链开发成为技术圈的热门技能。如何快速上手与以太坊交互?Ethers.js作为一款轻量又强大的工具,能帮你轻松搞定查询、交易和智能合约部署。本文通过一个实战脚本,带你一步步掌握Web3区块链开发的核心技能,无论你是

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 开发之旅吧!

参考

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
寻月隐君
寻月隐君
0x89EE...a439
不要放弃,如果你喜欢这件事,就不要放弃。如果你不喜欢,那这也不好,因为一个人不应该做自己不喜欢的事。