第一次学习Hardhat

目录

什么是 Hardhat?

Hardhat 是一个专为以太坊开发者设计的开发环境。它不仅提供了编译、部署、测试和调试智能合约的完整工具链,还拥有强大的插件生态系统,让开发者可以根据自己的需求定制开发流程。相比其他工具,Hardhat 的最大优势在于其出色的调试能力和灵活的架构设计。

搭建开发环境

在开始之前,我们需要先准备好开发环境。正所谓"工欲善其事,必先利其器",一个好的开发环境能让我们事半功倍。

安装 Node.js

Hardhat 基于 Node.js 构建,因此首先需要安装 Node.js。文章推荐使用 nvm (Node Version Manager) 来管理 Node.js 版本,这样可以轻松切换不同版本:

bash 复制代码
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
nvm install 18
nvm use 18
nvm alias default 18
npm install npm --global # Upgrade npm to the latest version

使用 nvm 的好处是可以在不同项目间切换 Node.js 版本,避免版本冲突问题。这里选择 Node.js 18 是因为它是目前的长期支持版本,稳定性和兼容性都比较好。

安装 Hardhat

环境准备就绪后,我们就可以安装 Hardhat 了。创建一个新的项目目录:

bash 复制代码
mkdir hardhat
cd hardhat

然后安装 Hardhat:

bash 复制代码
npm install --save-dev hardhat

安装完成后,目录中会出现 node_modulespackage-lock.jsonpackage.json 等文件,这表明 Hardhat 已经成功安装。

接下来,运行 npx hardhat 命令初始化项目配置。系统会提示你选择创建 Hardhat 配置文件,选择默认选项即可。

Hardhat 的核心架构

在深入开发之前,有必要了解一下 Hardhat 的核心设计理念。Hardhat 是围绕 task(任务) 和 plugins(插件) 这两个核心概念设计的。

每次从命令行运行 Hardhat 时,实际上都是在执行某个特定的任务。比如 npx hardhat compile 就是在运行编译任务。你可以通过运行 npx hardhat 来查看当前项目中所有可用的任务,或者使用 npx hardhat help [task] 来深入了解某个特定任务的使用方法。

Hardhat 的大部分功能都来自插件,这种设计让开发者可以自由选择需要的工具,而不必被一套固定的工具链所束缚。

开发我们的第一个智能合约

理论知识了解得差不多了,现在让我们动手开发第一个智能合约吧!

编写 Token 合约

我们来创建一个简单的 Token 合约。首先创建 contracts 目录:

bash 复制代码
mkdir contracts
cd contracts

然后创建 Token.sol 文件,编写我们的智能合约代码:

solidity 复制代码
//SPDX-License-Identifier: UNLICENSED

// Solidity files have to start with this pragma.
// It will be used by the Solidity compiler to validate its version.
pragma solidity ^0.8.9;

// This is the main building block for smart contracts.
contract Token {
    // Some string type variables to identify the token.
    string public name = "My Hardhat Token";
    string public symbol = "MHT";

    // The fixed amount of tokens, stored in an unsigned integer type variable.
    uint256 public totalSupply = 1000000;

    // An address type variable is used to store ethereum accounts.
    address public owner;

    // A mapping is a key/value map. Here we store each account's balance.
    mapping(address => uint256) balances;

    // The Transfer event helps off-chain applications understand
    // what happens within your contract.
    event Transfer(address indexed _from, address indexed _to, uint256 _value);

    /**
    * Contract initialization.
    */
    constructor() {
        // The totalSupply is assigned to the transaction sender, which is the
        // account that is deploying the contract.
        balances[msg.sender] = totalSupply;
        owner = msg.sender;
    }

    /**
    * A function to transfer tokens.
    *
    * The `external` modifier makes a function *only* callable from *outside*
    * the contract.
    */
    function transfer(address to, uint256 amount) external {
        // Check if the transaction sender has enough tokens.
        // If `require`'s first argument evaluates to `false` then the
        // transaction will revert.
        require(balances[msg.sender] >= amount, "Not enough tokens");

        // Transfer the amount.
        balances[msg.sender] -= amount;
        balances[to] += amount;

        // Notify off-chain applications of the transfer.
        emit Transfer(msg.sender, to, amount);
    }

    /**
    * Read only function to retrieve the token balance of a given account.
    *
    * The `view` modifier indicates that it doesn't modify the contract's
    * state, which allows us to call it without executing a transaction.
    */
    function balanceOf(address account) external view returns (uint256) {
        return balances[account];
    }
}

这个合约虽然简单,但包含了智能合约的核心要素:

  • 状态变量:存储合约的状态信息
  • 事件:用于通知外部应用合约内部发生的变化
  • 构造函数:合约部署时执行的初始化代码
  • 函数:合约提供的功能接口

编译合约

编写完成后,使用以下命令编译合约:

bash 复制代码
npx hardhat compile

编译成功后,Hardhat 会生成相应的 artifacts(合约的编译产物),这些文件将在后续的部署和测试中使用。

测试合约

没有经过测试的代码是不可靠的,智能合约尤其如此。让我们为合约编写测试用例。

首先创建测试目录:

bash 复制代码
mkdir test

然后创建 Token.js 测试文件:

javascript 复制代码
const { expect } = require("chai");

describe("Token contract", function () {
    it("Deployment should assign the total supply of tokens to the owner", async function () {
        const [owner] = await ethers.getSigners();

        const Token = await ethers.getContractFactory("Token");

        const hardhatToken = await Token.deploy();

        const ownerBalance = await hardhatToken.balanceOf(owner.address);
        expect(await hardhatToken.totalSupply()).to.equal(ownerBalance);
    });
});

运行测试:

bash 复制代码
npx hardhat test

如果一切正常,测试应该会通过。这表明我们的合约在基本功能上是正确的。

调试合约

Hardhat 内置了 Hardhat Network,这是一个专门为开发设计的以太坊本地网络。它允许我们在本地部署合约、运行测试和调试代码,而无需连接到真实的区块链网络。

更令人兴奋的是,Hardhat 支持在 Solidity 代码中使用 console.log!这在传统的区块链开发中是很难实现的。让我们来体验一下这个强大的功能。

首先,在合约中导入 console:

solidity 复制代码
pragma solidity ^0.8.9;

import "hardhat/console.sol";

contract Token {
    // ... 之前的代码 ...
}

然后在 transfer 函数中添加调试信息:

solidity 复制代码
function transfer(address to, uint256 amount) external {
    require(balances[msg.sender] >= amount, "Not enough tokens");

    console.log(
        "Transferring from %s to %s %s tokens",
        msg.sender,
        to,
        amount
    );

    balances[msg.sender] -= amount;
    balances[to] += amount;

    emit Transfer(msg.sender, to, amount);
}

现在,当我们运行测试时,就能在控制台看到详细的调试信息了。这对于排查问题和理解合约执行流程非常有帮助。

相关推荐
会跑的葫芦怪2 小时前
Go语言在区块链开发中的应用场景详解
golang·区块链
The Open Group2 小时前
TOGAF® 与新兴技术:区块链、物联网与量子计算
物联网·区块链·量子计算
Sui_Network4 小时前
Sui Stack Messaging SDK:为 Web3 打造可编程通信
大数据·人工智能·科技·web3·去中心化·区块链
央链知播7 小时前
链改2.0总架构师何超秘书长重构“可信资产lPO与数链金融RWA”
金融·重构·web3·区块链·业界资讯
MicroTech202519 小时前
微算法科技(NASDAQ: MLGO)融合二次矩阵变换模型,研发基于区块链的可溯源IP版权保护算法
区块链
天涯学馆19 小时前
Solidity多重签名合约:打造超安全的区块链投票机制
智能合约·solidity
科技圈快讯1 天前
解构IDP未来前景:去中心化金融的“阳谋”与以人为本的生态蓝图(解读)
金融·去中心化·区块链
kida_yuan1 天前
【以太来袭】1. 企业以太坊回归
区块链
央链知播1 天前
三板汇茶咖空间签约“可信资产IPO与数链金融RWA”链改2.0项目联合实验室
金融·区块链·业界资讯