合约开发工具hardhat

1,212 阅读4分钟

基础命令

Hardhat是一个非常流行的以太坊智能合约开发框架,提供了一系列工具和插件来帮助开发、测试和部署智能合约。下面是一些基本的Hardhat命令和它们的用途:

基本命令

  1. 初始化一个新项目

    npx hardhat
    

    这个命令会启动一个新项目的创建过程,包括建立项目结构和安装必要的依赖。

  2. 编译智能合约

    npx hardhat compile
    

    该命令编译项目中的智能合约。编译后的合约会生成相应的工件(artifacts),这些文件包含了ABI和字节码。

  3. 运行测试

    npx hardhat test
    

    这个命令运行项目中的测试脚本。Hardhat支持使用Mocha和Chai来编写测试。

  4. 部署合约

    npx hardhat run scripts/deploy.js
    

    使用此命令运行部署脚本以部署智能合约。deploy.js是你的部署脚本文件。

  5. 启动本地开发网络

    npx hardhat node
    

    这个命令启动了一个本地的以太坊网络,用于开发和测试。它会模拟真实的区块链环境。

  6. 运行任务或脚本

    npx hardhat run --network <network-name> scripts/your-script.js
    

    运行特定的脚本或任务,并可以指定网络(比如localhost、testnet或mainnet)。

  7. 交互式控制台

    npx hardhat console
    

    启动一个交互式JavaScript控制台,允许与Hardhat环境和部署的合约进行交互。

  8. 清理工件

    npx hardhat clean
    

    清除编译生成的工件和缓存,有助于解决某些构建问题。

配置和自定义

Hardhat的行为可以通过在项目根目录中编辑hardhat.config.js文件来自定义。你可以在这个文件中配置网络、编译器版本、插件等。

插件

Hardhat社区提供了许多插件,用于扩展功能,如Gas报告器、代码覆盖率分析和更高级的部署机制。你可以通过NPM安装这些插件,并在hardhat.config.js中进行配置。

有关合约命令

  1. 账户列表

    npx hardhat accounts
    

    列出可用的以太坊账户地址。

  2. 检查Gas使用

    npx hardhat gas-reporter
    

    生成Gas使用报告(需要安装相关插件)。

  3. Flatten合约

    npx hardhat flatten > output.sol
    

    代码扁平 将合约和其依赖合并到一个文件(需要安装相关插件)。

  4. 验证合约

    npx hardhat verify --network [网络名] [合约地址] [合约构造函数参数]
    

    在Etherscan等公共区块链浏览器上验证智能合约代码(需要配置API密钥)

hardhat.config.js.ts

这里是一个整合了常用配置和自定义任务的 hardhat.config.js 文件的例子,包含了详细的注释以解释每个部分的作用:

require("@nomiclabs/hardhat-waffle");
require("@nomiclabs/hardhat-ethers");
require("@nomiclabs/hardhat-etherscan");
require("dotenv").config();

module.exports = {
  // Solidity编译器配置
  solidity: {
    version: "0.8.4", // 指定Solidity版本
    settings: {
      optimizer: {
        enabled: true, // 启用优化器
        runs: 200     // 指定优化器运行次数
      }
    }
  },

  // 网络配置
  networks: {
    hardhat: {
      // 用于本地开发的Hardhat网络设置
    },
    rinkeby: {
      url: process.env.RINKEBY_URL, // 连接到Rinkeby测试网的URL
      accounts: [process.env.PRIVATE_KEY] // 用于部署的账户私钥
    },
    // 你可以添加更多网络配置
  },

  // Etherscan插件配置
  etherscan: {
    apiKey: process.env.ETHERSCAN_API_KEY // Etherscan API密钥,用于合约验证
  },

  // 自定义任务 npx hardhat accounts .....
  tasks: {
    accounts: async (_, { ethers }) => { // 自定义任务:列出所有账户
      const accounts = await ethers.getSigners();
      accounts.forEach((account) => {
        console.log(account.address);
      });
    },
    greet: task("greet", "Prints a greeting") // 自定义任务:打印问候语
      .addParam("name", "The name to greet") // 定义参数
      .setAction(async (taskArgs, hre) => {  // 定义任务动作
        console.log(`Hello, ${taskArgs.name}!`);
      })
  },

  // 配置文件路径
  paths: {
    sources: "./contracts",    // 指定Solidity源文件路径
    tests: "./test",           // 指定测试文件路径
    cache: "./cache",          // 编译缓存路径
    artifacts: "./artifacts"   // 编译合约的输出路径
  },

  // Mocha测试框架配置
  mocha: {
    timeout: 20000 // 测试运行的超时时间(毫秒)
  },

  // 默认网络配置
  defaultNetwork: "hardhat",

  // Hardhat运行时环境扩展
  extendEnvironment: (hre) => {
    hre.myHelper = async () => { /* 自定义扩展内容 */ };
  }
};

在这个配置文件中,我们包含了如下几个主要部分:

  1. Solidity编译器配置:用于设定Solidity版本和编译器优化设置。
  2. 网络配置:定义连接到不同以太坊网络(如Hardhat本地网络、Rinkeby测试网)的参数。
  3. Etherscan插件配置:用于配置与Etherscan的集成,便于合约验证。
  4. 自定义任务:定义一些自定义的Hardhat任务,比如列出账户地址和打印问候语。
  5. 文件路径配置:设定Solidity源代码、测试代码、编译产物的存放路径。
  6. Mocha测试配置:配置Mocha测试框架的行为,例如设置超时时间。
  7. 默认网络:当不显式指定网络时使用的默认网络。
  8. 环境扩展:向Hardhat运行时环境添加自定义的功能或属性。

通过这个配置文件,你可以根据项目需求调整Hardhat的行为,包括编译设置、网络连接、自定义任务等,使之更贴合你的项目开发流程。

hardhat-abi-exporterABI导出

安装插件:

npm install --save-dev hardhat-abi-exporter

hardhat.config.js文件中配置插件:

require('hardhat-abi-exporter');

module.exports = {
  // ...其他配置
  abiExporter: {
    path: './data/abi',
    clear: true,
    flat: true,
    // 只导出外部和公共方法的ABI
    only: [':ERC20$'],
    spacing: 2,
    pretty: true,
  },
};

问题

管理不同环境下的 部署隔离问题

1. 使用环境变量

通过 .env 文件和 dotenv 库来设置环境变量。首先,需要在项目根目录下创建一个 .env 文件,并设置合约参数:

# .env 文件
CONTRACT_PARAM1=Value1
CONTRACT_PARAM2=Value2

然后,在 deploy.js 脚本中使用这些环境变量:

// scripts/deploy.js

require("dotenv").config();
const hre = require("hardhat");

async function main() {
  const MyContract = await hre.ethers.getContractFactory("MyContract");
  const param1 = process.env.CONTRACT_PARAM1;
  const param2 = process.env.CONTRACT_PARAM2;

  const myContract = await MyContract.deploy(param1, param2);
  await myContract.deployed();
  console.log("MyContract deployed to:", myContract.address);
}

2. 使用命令行参数(并不推荐)

使用命令行参数传递合约参数。这可以通过修改 deploy.js 来实现,使其能够读取命令行参数:

// scripts/deploy.js

const hre = require("hardhat");

async function main() {
  const MyContract = await hre.ethers.getContractFactory("MyContract");

  // 从命令行读取参数
  const param1 = process.argv[2];
  const param2 = process.argv[3];

  const myContract = await MyContract.deploy(param1, param2);
  await myContract.deployed();
  console.log("MyContract deployed to:", myContract.address);
}

然后,通过命令行运行部署脚本,并传递参数:

npx hardhat run scripts/deploy.js --network [网络名] Value1 Value2

3. 使用外部配置文件(推荐)

创建一个配置文件,比如 config.json,并在部署脚本中导入这个文件:

// config.json
{
  "param1": "Value1",
  "param2": "Value2"
}

然后在 deploy.js 中引用这些配置:

// scripts/deploy.js

const hre = require("hardhat");
const config = require("../config.json");

async function main() {
  const MyContract = await hre.ethers.getContractFactory("MyContract");

  const param1 = config.param1;
  const param2 = config.param2;

  const myContract = await MyContract.deploy(param1, param2);
  await myContract.deployed();
  console.log("MyContract deployed to:", myContract.address);
}

总结

这些方法使你能够在部署脚本之外灵活地指定智能合约的参数,既提高了代码的可维护性,也增加了部署过程的灵活性。选择哪种方法取决于你的具体需求和项目结构。