1. 什么是 Hardhat?

Hardhat 是一个专为 Ethereum 智能合约开发设计的开发环境。它集成了编译、部署、测试和调试工具,帮助开发者高效构建去中心化应用(DApps)。Hardhat 的核心优势在于其灵活性和强大的插件系统,允许开发者根据需要扩展功能。

2. Hardhat 的核心功能
  • 编译合约:支持 Solidity 合约的编译,生成 ABI 和字节码。
  • 部署合约:提供脚本工具,方便将合约部署到不同网络(如本地、测试网、主网)。
  • 测试合约:集成 Mocha 和 Chai,支持编写和运行测试用例。
  • 调试合约:提供详细的错误信息和堆栈跟踪,便于调试。
  • 插件系统:支持通过插件扩展功能,如与 Etherscan、Waffle 等工具集成。
3. 安装与设置
  1. 安装 Node.js 和 npm:确保已安装 Node.js 和 npm。
  2. 创建项目
    mkdir my-hardhat-project
    cd my-hardhat-project
    npm init -y
    
  3. 安装 Hardhat
    npm install --save-dev hardhat
    
  4. 初始化 Hardhat 项目
    npx hardhat
    
    选择“Create an empty hardhat.config.js”来创建一个空的配置文件。
4. 配置文件 (hardhat.config.js)

配置文件用于设置网络、编译器版本、插件等。示例:

require("@nomiclabs/hardhat-waffle");

module.exports = {
  solidity: "0.8.4",
  networks: {
    ropsten: {
      url: "https://ropsten.infura.io/v3/YOUR_INFURA_PROJECT_ID",
      accounts: ["YOUR_PRIVATE_KEY"]
    }
  }
};
5. 编写和编译合约
  1. 创建合约文件:在 contracts/ 目录下创建 .sol 文件,例如 Greeter.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    
    contract Greeter {
        string private greeting;
    
        constructor(string memory _greeting) {
            greeting = _greeting;
        }
    
        function greet() public view returns (string memory) {
            return greeting;
        }
    
        function setGreeting(string memory _greeting) public {
            greeting = _greeting;
        }
    }
    
  2. 编译合约
    npx hardhat compile
    
6. 部署合约
  1. 编写部署脚本:在 scripts/ 目录下创建 deploy.js
    async function main() {
        const Greeter = await ethers.getContractFactory("Greeter");
        const greeter = await Greeter.deploy("Hello, Hardhat!");
    
        await greeter.deployed();
    
        console.log("Greeter deployed to:", greeter.address);
    }
    
    main().catch((error) => {
        console.error(error);
        process.exitCode = 1;
    });
    
  2. 部署合约
    npx hardhat run scripts/deploy.js --network ropsten
    
7. 测试合约
  1. 编写测试用例:在 test/ 目录下创建 test.js
    const { expect } = require("chai");
    
    describe("Greeter", function () {
        it("Should return the new greeting once it's changed", async function () {
            const Greeter = await ethers.getContractFactory("Greeter");
            const greeter = await Greeter.deploy("Hello, Hardhat!");
    
            await greeter.deployed();
            expect(await greeter.greet()).to.equal("Hello, Hardhat!");
    
            await greeter.setGreeting("Hola, Hardhat!");
            expect(await greeter.greet()).to.equal("Hola, Hardhat!");
        });
    });
    
  2. 运行测试
    npx hardhat test
    
8. 调试合约

Hardhat 提供了详细的错误信息和堆栈跟踪,便于调试。可以使用 console.log 在合约中打印调试信息。

9. 插件与扩展

Hardhat 支持多种插件,如:

  • hardhat-waffle:集成 Waffle 测试框架。
  • hardhat-etherscan:与 Etherscan 集成,验证合约。
  • hardhat-deploy:简化部署流程。

实际案例:简单的投票合约

1. 创建项目
mkdir voting-dapp
cd voting-dapp
npm init -y
npm install --save-dev hardhat
npx hardhat
2. 编写合约

contracts/ 目录下创建 Voting.sol

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

contract Voting {
    mapping(bytes32 => uint256) public votesReceived;
    bytes32[] public candidateList;

    constructor(bytes32[] memory candidateNames) {
        candidateList = candidateNames;
    }

    function voteForCandidate(bytes32 candidate) public {
        require(validCandidate(candidate));
        votesReceived[candidate] += 1;
    }

    function totalVotesFor(bytes32 candidate) public view returns (uint256) {
        require(validCandidate(candidate));
        return votesReceived[candidate];
    }

    function validCandidate(bytes32 candidate) public view returns (bool) {
        for (uint256 i = 0; i < candidateList.length; i++) {
            if (candidateList[i] == candidate) {
                return true;
            }
        }
        return false;
    }
}
3. 编译合约
npx hardhat compile
4. 部署合约

scripts/ 目录下创建 deploy.js

async function main() {
    const candidates = ["Candidate1", "Candidate2", "Candidate3"].map(c => ethers.utils.formatBytes32String(c));
    const Voting = await ethers.getContractFactory("Voting");
    const voting = await Voting.deploy(candidates);

    await voting.deployed();

    console.log("Voting deployed to:", voting.address);
}

main().catch((error) => {
    console.error(error);
    process.exitCode = 1;
});

运行部署脚本:

npx hardhat run scripts/deploy.js --network ropsten
5. 测试合约

test/ 目录下创建 test.js

const { expect } = require("chai");

describe("Voting", function () {
    it("Should return the correct total votes for a candidate", async function () {
        const candidates = ["Candidate1", "Candidate2", "Candidate3"].map(c => ethers.utils.formatBytes32String(c));
        const Voting = await ethers.getContractFactory("Voting");
        const voting = await Voting.deploy(candidates);

        await voting.deployed();

        await voting.voteForCandidate(candidates[0]);
        await voting.voteForCandidate(candidates[0]);
        await voting.voteForCandidate(candidates[1]);

        expect(await voting.totalVotesFor(candidates[0])).to.equal(2);
        expect(await voting.totalVotesFor(candidates[1])).to.equal(1);
        expect(await voting.totalVotesFor(candidates[2])).to.equal(0);
    });
});

运行测试:

npx hardhat test
6. 总结

通过这个简单的投票合约案例,我们展示了如何使用 Hardhat 进行智能合约的开发、编译、部署和测试。Hardhat 的强大功能和灵活性使得 Ethereum 开发变得更加高效和便捷。希望这个案例能帮助你更好地理解和使用 Hardhat!

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐