使用 Ethers.js 进行 Solidity 智能合约开发全指南

·

概述

在掌握了 Solidity 基础语法和开发框架后,深入理解底层交互原理至关重要。本文将详细介绍如何使用 Ethers.js 库与以太坊测试网络进行交互,涵盖合约编译、部署到 Rinkeby 测试网以及基础交互操作,为后续使用高级框架打下坚实基础。

Ethers.js 简介

Ethers.js 是一个轻量级、功能完整的以太坊 JavaScript 库,提供了与以太坊区块链交互的核心功能。该库以其简洁的 API 设计和出色的安全性在开发者社区中广受好评。

安装与配置

通过 yarn 包管理器可快速安装 Ethers.js:

yarn add ethers

在项目中通过 require 语句引入库:

const ethers = require('ethers');

智能合约编译流程

示例合约结构

以下是一个简单的存储合约示例,展示了基本的数据存储和检索功能:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

contract SimpleStorage {
    uint256 favoriteNumber;
    bool favoriteBool;
    
    struct People {
        uint256 favoriteNumber;
        string name;
    }
    
    People public person = People({favoriteNumber: 2, name: "Arthur"});
    People[] public people;
    mapping(string => uint256) public nameToFavoriteNumber;
    
    function store(uint256 _favoriteNumber) public returns (uint256) {
        favoriteNumber = _favoriteNumber;
        return favoriteNumber;
    }
    
    function retrieve() public view returns (uint256) {
        return favoriteNumber;
    }
    
    function addPerson(string memory _name, uint256 _favoriteNumber) public {
        people.push(People({favoriteNumber: _favoriteNumber, name: _name}));
        nameToFavoriteNumber[_name] = _favoriteNumber;
    }
}

编译工具配置

使用 solc 编译器进行合约编译:

yarn solcjs --bin --abi --include-path node_modules/ --base-path . -o . SimpleStorage.sol

为提升开发效率,可在 package.json 中配置编译脚本:

{
  "scripts": {
    "compile": "yarn solcjs --bin --abi --include-path node_modules/ --base-path . -o . SimpleStorage.sol"
  }
}

获取编译输出

编译完成后,读取生成的 ABI 和字节码文件:

const fs = require('fs-extra');
const abi = fs.readFileSync("./SimpleStorage_sol_SimpleStorage.abi", "utf-8");
const binary = fs.readFileSync("./SimpleStorage_sol_SimpleStorage.bin", "utf-8");

测试环境搭建

Alchemy 平台配置

  1. 访问 Alchemy 官网注册账户并登录
  2. 在控制台创建新的应用程序
  3. 选择 Rinkeby 测试网络作为部署环境
  4. 记录生成的 HTTP URL 供后续连接使用

MetaMask 钱包设置

  1. 安装并配置 MetaMask 浏览器扩展
  2. 创建或导入以太坊账户
  3. 切换网络至 Rinkeby 测试网

获取测试代币

通过以下水龙头获取 Rinkeby 测试网 ETH:

网络连接与合约部署

连接测试网络节点

使用 Ethers.js 连接 Alchemy 提供的节点服务:

const provider = new ethers.providers.JsonRpcProvider(process.env.ALCHEMY_RPC_URL);

连接以太坊钱包

通过私钥连接钱包并提供签名支持:

const wallet = new ethers.Wallet(process.env.RINKEBY_PRIVATE_KEY, provider);

合约部署流程

创建合约工厂实例

const contractFactory = new ethers.ContractFactory(abi, binary, wallet);

执行部署操作

const contract = await contractFactory.deploy();
await contract.deployTransaction.wait(1);

合约交互方法

数据检索操作

调用合约的只读方法获取存储数据:

const currentFavoriteNumber = await contract.retrieve();

数据存储操作

发送交易更新合约状态:

const transactionResponse = await contract.store("7");
const transactionReceipt = await transactionResponse.wait(1);

低级交易构造

手动构建交易数据

const nonce = await wallet.getTransactionCount();
const tx = {
    nonce: nonce,
    gasPrice: 20000000000,
    gasLimit: 1000000,
    to: null,
    value: 0,
    data: "0x" + binary,
    chainId: 1337,
};

交易签名与发送

const signedTx = await wallet.signTransaction(tx);
const sentTxResponse = await wallet.sendTransaction(tx);
await sentTxResponse.wait(1);

开发实践建议

在实际项目开发中,虽然通常会使用 HardHat 或 Brownie 等高级框架,但理解底层交互机制仍然非常重要。这有助于调试复杂问题并优化合约交互逻辑。

👉 查看实时开发工具与资源

常见问题

Ethers.js 与 Web3.js 有何区别?

Ethers.js 设计更加模块化,API 更简洁直观,且内置支持 TypeScript。它在处理钱包管理和交易签名方面提供了更好的安全性和用户体验,特别适合前端应用集成。

为什么要使用测试网络?

测试网络提供与主网相似的环境,但不消耗真实的 ETH。开发者可以免费获取测试代币,放心地进行合约部署和功能测试,避免因错误操作造成资金损失。

如何选择合适的 Gas 价格?

Gas 价格直接影响交易确认速度。在测试网上可以使用较低的 Gas 价格,而在主网部署时需要根据网络拥堵情况调整。可以使用 Gas 跟踪工具查询实时建议价格。

合约部署失败常见原因有哪些?

常见原因包括:Gas 不足、合约代码存在错误、编译器版本不匹配、账户余额不足等。仔细检查错误信息并确保测试网有足够的测试代币。

如何确保私钥安全?

私钥应存储在环境变量中,切勿直接写入代码或提交到版本控制系统。考虑使用硬件钱包或多重签名方案来管理重要账户的私钥。

什么时候需要手动构造交易?

当需要精确控制交易参数(如 Gas 限制、Gas 价格)或实现特定高级功能时,手动构造交易是必要的。但对于大多数常规操作,使用合约抽象层更简便安全。

总结

掌握 Ethers.js 的使用为智能合约开发奠定了重要基础。通过理解底层交互机制,开发者能够更有效地使用高级框架,快速定位和解决开发过程中遇到的问题。后续我们将进一步探讨 HardHat 框架的高级特性和最佳实践。