选择Create a JavaScript project(JavaScript编写测试和脚本)

投稿 2026-03-04 10:51 点击数: 2

从零开始构建你的第一个DApp合约

以太坊智能合约是什么?

以太坊智能合约(Smart Contract)是一段部署在以太坊区块链上的自动执行代码,它 predefined 了合约参与方的权利与义务,当预设条件被触发时,合约会按约定规则自动执行操作(如转账、数据存储、逻辑判断等),无需第三方信任背书,它就像“写在区块链上的合同”,一旦部署就无法篡改,且由以太坊网络中的所有节点共同维护和执行。

开发以太坊智能合约的核心步骤

开发以太坊智能合约通常包括环境搭建、合约编写、编译、测试、部署、交互六大环节,下面以最主流的Solidity语言Hardhat框架为例,详细拆解每个步骤。

环境搭建:安装必要工具

开发以太坊合约需要以下基础工具:

  • Node.js:JavaScript运行环境(建议版本≥18),用于运行开发框架(如Hardhat)。
  • Hardhat:以太坊开发框架,提供编译、测试、部署等一体化功能(推荐新手使用,比Truffle更灵活)。
  • MetaMask:浏览器钱包插件,用于管理开发者账户和与测试网/主网交互。
  • Remix IDE:在线Solidity编辑器(可选,适合快速原型验证,无需本地环境)。

安装Hardhat
打开终端,执行以下命令:

npm init -y  # 初始化Node.js项目
npm install --save-dev hardhat  # 安装Hardhat

合约编写:用Solidity定义逻辑

Solidity是以太坊智能合约的核心编程语言,语法类似JavaScript,但专为区块链设计(支持变量状态、修饰符、事件等特性)。

创建Hardhat项目

npx hardhat  # 初始化Hardhat项目# 按提示输入项目名称、是否添加.gitignore等

编写第一个合约
contracts/目录下创建SimpleStorage.sol文件,编写一个简单的“存储合约”,实现“读取/写入数字”功能:

// SPDX-License-Identifier: MIT  // 声明许可证(必须)
pragma solidity ^0.8.20;       // 声明Solidity版本(建议0.8.0+)
contract SimpleStorage {
    uint256 private storedData;  // 状态变量:存储一个无符号整数(private仅合约内可访问)
    // 事件:当数据变更时触发(前端可监听)
    event DataUpdated(uint256 oldData, uint256 newData);
    // 写入数据的函数(public:任何地址均可调用)
    function set(uint256 _data) public {
        uint256 oldData = storedData;
        storedData = _data;  // 修改状态变量(会消耗gas)
        emit DataUpdated(oldData, storedData);  // 触发事件
    }
    // 读取数据的函数(view:不修改状态,免费调用)
    function get() public view returns (uint256) {
        return storedData;
    }
}

合约编译:将Solidity转为字节码

Solidity代码需要编译成以太坊虚拟机(EVM)可执行的字节码(Bytecode)应用二进制接口(ABI),前者部署到链上,后者用于前端与合约交互。

使用Hardhat编译
在终端执行:

npx hardhat compile

编译成功后,字节码和ABI会生成在artifacts/contracts/SimpleStorage.sol/SimpleStorage.json文件中。

合约测试:确保逻辑正确

测试是保证合约安全的关键环节,Hardhat支持使用Mocha(测试框架)和Chai(断言库)编写测试用例。

编写测试脚本
test/目录下创建simpleStorage.test.js文件:

const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("SimpleStorage", function () {
    let SimpleStorage;
    let simpleStorage;
    before(async function () {
        // 部署合约
        SimpleStorage = await ethers.getContractFactory("SimpleStorage");
        simpleStorage = await SimpleStorage.deploy();
        await simpleStorage.deployed();
    });
    it("Should store the value 89.", async function () {
        // 调用set函数写入数据
        await simpleStorage.set(89);
        // 调用get函数读取数据并验证
        expect(await simpleStorage.get()).to.equal(89);
    });
    it("Should emit DataUpdated event.", async function () {
        // 监听事件
        const tx = await simpleStorage.set(42);
        const receipt = await tx.wait();
        const event = receipt.events.find(e => e.event === "DataUpdated");
        expect(event.args.oldData).to.equal(89);
        expect(event.args.newData).to.equal(42);
    });
});

运行测试

npx hardhat test

测试通过后,说明合约逻辑符合预期。

合约部署:将合约上链

部署合约需要账户(用于支付Gas费)和网络(测试网或主网),开发阶段通常使用本地测试网(Hardhat Network)公共测试网(如Goerli、Sepolia)

本地测试网部署
Hardhat默认启动本地节点(端口8545),直接执行部署脚本:
scripts/目录下创建deploy.js

async function main() {
    const SimpleStorage = await ethers.getContractFactory("SimpleStorage");
    const simpleStorage = await SimpleStorage.deploy();
    await simpleStorage.deployed();
    console.log("SimpleStorage deployed to:", simpleStorage.address);
}
main().catch((error) => {
    console.error(error);
    process.exitCode = 1;
});

执行部署:

npx hardhat run scripts/deploy.js --network localhost

返回合约地址(如0x5FbDB2315678afecb367f032d93F642f64180aa3),即本地部署成功。

公共测试网部署(以Goerli为例)

  1. 从Goerli水龙头(如goerli-faucet.pk910.de)获取免费测试ETH(用于支付Gas)。
  2. 在MetaMask中添加Goerli网络(网络ID:5,RPC:https://rpc.ankr.com/eth_goerli)。
  3. 修改hardhat.config.js,添加Goerli配置:
    require("@nomicfoundation/hardhat-toolbox");
    require("dotenv").config();

/* @type import('hardhat/config').HardhatUserConfig / module.exports = { solidity: "0.8.20", networks: { goerli: { url: process.env.GOERLI_RPC_URL, // 从.env文件读取 accounts: [process.env.PRIVATE_KEY], // MetaMask私钥(勿泄露) }, }, };

在项目根目录创建`.env`文件,填入RPC和私钥:  
```env
GOERLI_RPC_URL=https://rpc.ankr.com/eth_goerli
PRIVATE_KEY=你的MetaMask私钥(以0x开头)
  1. 执行部署:
    npx hardhat run scripts/deploy.js --network goerli

    部署成功后,合约地址会显示在Goerli浏览器(如https://goerli.etherscan.io/)上。

合约交互:调用合约功能

部署后,可通过Ethers.js(JavaScript库)与合约交互,例如在前端或脚本中读取/写入数据。

示例脚本(调用合约)
创建interact.js

const { ethers } = require("hardhat");
async function main() {
    const SimpleStorage = await ethers.getContractFactory("SimpleStorage");
    const simpleStorage = await SimpleStorage.attach("0x你的合约地址"); // 替换为实际地址
    // 读取数据
    const storedData = await simpleStorage.get();
    console.log("Stored data:", storedData.toString());
    // 写入数据
    const tx = await simpleStorage.set(100);
    
随机配图
await tx.wait(); console.log("Data updated to 100"); // 再次读取 const newData = await simpleStorage.get(); console.log("New stored data:", newData.toString()); } main().catch((error) => { console.error(error); process.exitCode = 1; });

执行脚本:

node interact.js

开发智能合约的注意事项

  1. 安全性优先

    避免重入攻击(使用`Checks-Effects