第一次学习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);
}

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

相关推荐
CryptoRzz1 天前
越南k线历史数据、IPO新股股票数据接口文档
java·数据库·后端·python·区块链
CryptoPP2 天前
获取越南股票市场列表(包含VN30成分股)实战指南
大数据·服务器·数据库·区块链
链上日记2 天前
OKZOO亮相欧洲区块链大会:HealthFi全球化进程加速
区块链
本郡主是喵2 天前
用 TypeScript 进行 Truffle 测试
学习·区块链
YSGZJJ2 天前
股指期货套期保值的风险有哪些?
区块链
落雪财神意3 天前
股指10月想法
大数据·人工智能·金融·区块链·期股
leijiwen3 天前
农业与供应链类 RWA 落地研究报告
区块链
数据与人工智能律师3 天前
解码Web3:DeFi、GameFi、SocialFi的法律风险警示与合规路径
大数据·网络·人工智能·云计算·区块链
CryptoRzz3 天前
欧美(美股、加拿大股票、墨西哥股票)股票数据接口文档
java·服务器·开发语言·数据库·区块链
安当加密4 天前
基于区块链的分布式密钥管理系统:构建去中心化、高可信的密码基础设施
分布式·去中心化·区块链