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

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

以太坊智能合约是什么?

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

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

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

环境搭建:安装必要工具

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

  • Node.js:JavaScript运行环境(建议版本≥18),用于运行开发框架(如Hardhat)。
  • Hardhat:以太坊开发框架,提供编译、测试、部署等一体化功能(推荐新手使用,比Truffle更灵活)。 随机配图
li>
  • 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

    本文由用户投稿上传,若侵权请提供版权资料并联系删除!

    上一篇:

    下一篇: