Hardhat v2.26.3 + Node.js v20.18.0精准稳定版部署指南

100 阅读17分钟
国外可访问:rainweb3知识库
国内可访问:rainweb3知识库


Hardhat 智能合约开发环境搭建与配置指南(基于 Hardhat v2.26.3 + Node.js v20.18.0 精准稳定版)

版本:v4.8.0
最后更新时间:2025年10月3日 目标:规避 hardhat@3.x 的兼容性问题,精准锁定稳定版 v2.26.3,确保在 Node.js v20.18.0 环境下构建无冲突、可部署、可维护的 TypeScript 项目。


快速上手-可访问下载此模版项目:v2.26.3 hardhat-project-template 下载后-先执行:npm run reinstall(安装node_modules)

📚 目录


🔧 一、环境准备(Node.js v20.18.0 稳定适配)

✅ 1.1 前提条件

  • Node.jsv20.18.0(LTS,推荐)
  • npmv10.8.2(随 Node.js v20 安装)
  • Git(可选)
  • 文本编辑器:推荐使用 VS Code

⚠️ 重要提醒hardhat@3.x 版本(如 3.0.4)为早期主版本,存在 API 变更、插件不兼容、文档缺失等问题,不建议在生产或学习项目中使用

# 检查版本
node -v  # 预期输出:v20.18.0
npm -v   # 预期输出:10.8.2

💡 若版本不符,请使用 nvm 切换:

# 安装 nvm(Linux/macOS)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash

# 重启终端后
nvm install 20.18.0
nvm use 20.18.0
nvm alias default 20.18.0

🛠 二、初始化项目结构(强制使用 hardhat@2.26.3

✅ 2.1 创建项目并初始化

mkdir hardhat-project
cd hardhat-project
npm init -y

✅ 2.2 安装 Hardhat 稳定版本 v2.26.3(关键步骤)

⚠️ 切勿使用 npm install --save-dev hardhat,否则会安装最新的 3.0.4,该版本存在严重兼容性问题。

npm install --save-dev hardhat@2.26.3
npx hardhat init

交互式选项详解(逐行说明):
? What do you want to do? 
  Create a JavaScript project
> Create a TypeScript project
  Create a TypeScript project (with Viem)
  Create an empty hardhat.config.js
  Quit

选择:Create a TypeScript project

原因:本人的配置使用 ethers 而非 viem,选择此项将生成基于 etherschai 的标准 TypeScript 项目结构。


? Hardhat project root: /your/path/hardhat-project

✅ 回车确认默认路径。


? Do you want to add a .gitignore? (Y/n)

✅ 输入 Y,自动创建 .gitignore


? Do you want to install this sample project's dependencies with npm (@nomicfoundation/hardhat-toolbox)? (Y/n) »

输入 y

选项说明

  • 此选项询问是否自动安装 @nomicfoundation/hardhat-toolbox 及其依赖(如 eslint, prettier, typescript, chai, ethers 等)。
  • 选择 y:自动安装推荐的开发依赖,节省手动配置时间,且版本与 hardhat@2.26.3 兼容。
  • ❌ 选择 n:需手动安装所有依赖,容易出错且耗时。
  • 注意:即使选择 y,后续仍需用本人提供的 package.json 替换以锁定精确版本。

⚠️ 关于安装过程中的警告说明

执行 npm install 时可能出现:

npm warn deprecated glob@8.1.0: Glob versions prior to v9 are no longer supported
npm warn deprecated eslint@8.57.1: This version is no longer supported...

结论:这些是非阻塞性警告,源于 hardhat-toolbox 对旧版 eslint 的依赖。hardhat@2.26.3 + toolbox@^4.0.0 + eslint@^8.57.0 是当前最稳定的组合,无需修复


📁 三、项目结构演变:从原生生成到完整配置

本节清晰区分 初始生成结构最终完整结构,并说明新增/修改项。

✅ 3.1 初始生成的项目结构(执行 npx hardhat init 后)

执行 npx hardhat init 并选择 Create a TypeScript project 后,Hardhat 自动生成的项目结构如下:

hardhat-project/
├── contracts/                 # 存放 Solidity 智能合约源代码(.sol 文件)
│   └── Lock.sol               # 示例合约:带时间锁的转账合约
├── scripts/                   # 存放自定义部署或交互脚本(.ts 文件)
│   └── deploy.ts              # 示例:部署合约到指定网络的脚本
├── test/                      # 存放合约测试用例(.ts 文件)
│   └── Lock.ts                # 示例:对 Lock 合约进行单元测试
├── node_modules/              # npm 安装的所有依赖包(自动生成)
├── .gitignore                 # Git 忽略文件规则(已包含基础规则)
├── hardhat.config.ts          # Hardhat 主配置文件(网络、Solidity 版本等)
├── package-lock.json          # npm 依赖锁定文件(自动生成)
├── package.json               # 项目元信息与依赖声明
├── README.md                  # 项目说明文档
└── tsconfig.json              # TypeScript 编译配置

⚠️ 此时缺少.prettierrc, eslint.config.js, .editorconfig, .env, .vscode/settings.json 等高级配置文件。


✅ 3.2 完整项目结构(添加所有配置文件后)

在添加所有配置文件和环境变量后,最终的项目结构如下:

hardhat-project/
├── contracts/                 # 存放 Solidity 智能合约源代码(.sol 文件)
│   └── Lock.sol               # 示例合约:带时间锁的转账合约
├── scripts/                   # 存放自定义部署或交互脚本(.ts 文件)
│   └── deploy.ts              # 示例:部署合约到指定网络的脚本
├── test/                      # 存放合约测试用例(.ts 文件)
│   └── Lock.ts                # 示例:对 Lock 合约进行单元测试
├── node_modules/              # npm 安装的所有依赖包(自动生成)
├── .vscode/                   # VS Code 编辑器配置
│   └── settings.json          # 编辑器格式化、保存等行为配置
├── .env                       # 环境变量文件(本地开发使用,不应提交到 Git)
├── .env.local                 # 本地环境变量覆盖文件(Git 忽略)
├── encryptedKey.json          # 加密的私钥文件(Git 忽略)
├── .editorconfig              # 统一编辑器缩进、换行等风格
├── .eslint.config.js          # ESLint 代码规范检查配置
├── .gitignore                 # Git 忽略文件规则
├── .prettierrc                # Prettier 代码格式化配置
├── hardhat.config.ts          # Hardhat 主配置文件(网络、Solidity 版本等)
├── package-lock.json          # npm 依赖锁定文件(自动生成)
├── package.json               # 项目元信息与依赖声明
├── README.md                  # 项目说明文档
└── tsconfig.json              # TypeScript 编译配置

变化说明

  • 移除 ignition/ 目录,因为 hardhat@2.26.3 不支持 hardhat-ignition
  • 新增 .vscode/, .prettierrc, .eslint.config.js, .editorconfig, .env 等配置文件。
  • .gitignore 内容被增强,以忽略更多文件。

✅ 3.3 新增/修改的配置文件说明(对比初始结构)

文件/目录类型作用说明
.prettierrc新增Prettier 格式化配置,统一代码风格
eslint.config.js新增ESLint 代码规范检查配置,集成 Prettier,确保代码质量
.editorconfig新增统一不同编辑器的缩进、换行等基础风格
.env新增存放私钥、RPC URL 等敏感环境变量
.env.local新增本地环境变量覆盖,优先级高于 .env
encryptedKey.json新增存放加密后的私钥文件
.vscode/settings.json新增VS Code 编辑器行为配置,实现保存时自动格式化与修复
.gitignore修改在初始基础上增强,新增忽略 dist/, cache/, coverage/, encryptedKey.json, .env.*

⚙️ 四、修复 Ignition 导入错误与 Solidity 编译器版本不匹配问题

🛠 问题描述

  1. import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; 报错:找不到模块。
  2. npx hardhat compile 报错:Error HH606: The project cannot be compiled,Solidity 版本 ^0.8.28 与配置不匹配。

根本原因

  • hardhat@2.26.3 不支持 hardhat-ignition,该功能是 hardhat@3.x 的实验性功能。
  • hardhat-toolbox 默认配置的 Solidity 编译器版本可能不包含 0.8.28

🚫 4.0 hardhat@2.26.3 不支持 Ignition:原因与替代方案详解

⚠️ 核心原因说明

@nomicfoundation/hardhat-ignition 是 Hardhat 团队为 Hardhat v3.x 系列开发的全新、实验性的模块化部署系统。它旨在简化复杂合约系统的部署流程,提供更强大的依赖管理和部署状态追踪能力。

hardhat@2.26.3(属于 v2.x 系列)发布于 Hardhat Ignition 功能之前,其代码库中完全不包含 hardhat-ignition 模块。 因此,尝试在 v2.26.3 项目中导入 @nomicfoundation/hardhat-ignition/modules 会直接导致模块解析失败,报错:

Error: Cannot find module '@nomicfoundation/hardhat-ignition/modules'

这不是配置错误,而是版本不兼容的必然结果。

📌 重要提示:即使本人手动通过 npm install @nomicfoundation/hardhat-ignition 安装该插件,它也无法在 v2.26.3 上正常工作,因为其底层依赖和 API 与 v2.x 不兼容。


替代方案与操作步骤

由于 hardhat@2.26.3 不支持 Ignition,必须使用 传统的部署方式,即通过 Hardhat Runtime Environment (HRE) 中的 ethers 插件来手动部署合约。

替代方案:使用 ethers.deployContract()

这是 Hardhat v2.x 的标准部署方法,稳定、可靠、文档完善。

操作步骤如下

  1. 删除 ignition/ 目录(如果存在):

    rm -rf ignition
    
  2. 修改或创建部署脚本(如 scripts/deploy.ts),使用 ethers.deployContract 代替 buildModule

    import { ethers } from "hardhat";
    
    async function main() {
      // 部署 Lock 合约,构造函数参数为解锁时间戳
      const unlockTime = Math.floor(Date.now() / 1000) + 60; // 60秒后解锁
      const lockedAmount = ethers.parseEther("1"); // 锁定1 ETH
    
      const lock = await ethers.deployContract("Lock", [unlockTime], {
        value: lockedAmount
      });
    
      await lock.waitForDeployment();
      console.log(`Lock contract deployed to ${lock.target}`);
    }
    
    main()
      .then(() => process.exit(0))
      .catch((error) => {
        console.error(error);
        process.exit(1);
      });
    

    说明

    • ethers.deployContract("Lock", [unlockTime], { value: lockedAmount }):直接部署合约,传入构造函数参数和交易选项(如 value)。
    • await lock.waitForDeployment():等待部署交易上链并确认。
    • lock.target:获取部署后的合约地址。
  3. 无需修改 hardhat.config.ts 来支持此方案,ethers 插件已由 @nomicfoundation/hardhat-toolbox 自动加载。

  4. 更新 package.json 脚本,移除 deploy:ignition 等相关命令,仅保留基于 scripts/ 的部署命令。


✅ 4.1 移除 Ignition 相关代码(hardhat@2.26.3 不支持)

(此节为 4.0 节的实践总结)

  1. 删除 ignition/ 目录(如果存在):

    rm -rf ignition
    
  2. 修改 scripts/deploy.ts(如果引用了 buildModule):

    import { ethers } from "hardhat";
    
    async function main() {
      const lock = await ethers.deployContract("Lock", [Date.now() + 1000]);
      await lock.waitForDeployment();
      console.log(`Lock deployed to ${lock.target}`);
    }
    
    main().catch((error) => {
      console.error(error);
      process.exitCode = 1;
    });
    

    说明:使用 ethers.deployContract 代替 buildModule,这是 hardhat@2.x 的标准部署方式。


✅ 4.2 修正 hardhat.config.ts 中的 Solidity 编译器版本

确保 hardhat.config.ts 中的 solidity 配置包含 0.8.28

import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";

const config: HardhatUserConfig = {
  solidity: {
    version: "0.8.28",
    settings: {
      optimizer: {
        enabled: true,
        runs: 200,
      },
    },
  },
  networks: {
    hardhat: {
      chainId: 1337,
    },
  },
  paths: {
    sources: "./contracts",
    tests: "./test",
    cache: "./cache",
    artifacts: "./artifacts"
  },
  mocha: {
    timeout: 40000
  }
};

export default config;

关键点

  • 明确设置 version: "0.8.28",与 Lock.sol 中的 pragma solidity ^0.8.28; 匹配。
  • hardhat-toolbox 支持 0.8.28,无需额外安装编译器。

✅ 4.3 更新 package.json 脚本(移除 Ignition 相关)

确保 package.json 中的脚本不包含 ignition 相关命令:

"scripts": {
  "ts-node": "npx ts-node",
  "build": "tsc",
  "compile": "hardhat compile",
  "test": "hardhat test",
  "node": "hardhat node",
  "deploy:local": "hardhat run scripts/deploy.ts --network localhost",
  "deploy:sepolia": "hardhat run scripts/deploy.ts --network sepolia",
  "clean": "npx rimraf node_modules package-lock.json dist artifacts cache coverage types",
  "outdated": "npm outdated",
  "format": "prettier --plugin prettier-plugin-solidity --write \"**/*.{js,cjs,ts,sol}\"",
  "format:check": "prettier --plugin prettier-plugin-solidity --check \"**/*.{js,cjs,ts,sol}\"",
  "lint": "eslint \"**/*.{ts,js,sol}\" --ext .ts,.js",
  "lint:fix": "eslint \"**/*.{ts,js,sol}\" --ext .ts,.js --fix",
  "reinstall": "npm run clean && npm install"
}

说明:已移除 deploy:ignition 等不适用于 hardhat@2.26.3 的脚本。


🧩 五、依赖版本对齐(精确锁定,避免 3.x 升级)

✅ 5.1 清理并替换 package.json

rm -rf node_modules package-lock.json

✅ 5.2 使用更新后的 package.json(项目名已更改为 hardhat-project

{
  "name": "hardhat-project",
  "version": "1.0.0",
  "main": "hardhat.config.js",
  "scripts": {
    "ts-node": "npx ts-node",
    "build": "tsc",
    "compile": "hardhat compile",
    "test": "hardhat test",
    "node": "hardhat node",
    "deploy:local": "hardhat run scripts/deploy.ts --network localhost",
    "deploy:sepolia": "hardhat run scripts/deploy.ts --network sepolia",
    "clean": "npx rimraf node_modules package-lock.json dist artifacts cache coverage types",
    "outdated": "npm outdated",
    "format": "prettier --plugin prettier-plugin-solidity --write \"**/*.{js,cjs,ts,sol}\"",
    "format:check": "prettier --plugin prettier-plugin-solidity --check \"**/*.{js,cjs,ts,sol}\"",
    "lint": "eslint \"**/*.{ts,js,sol}\" --ext .ts,.js",
    "lint:fix": "eslint \"**/*.{ts,js,sol}\" --ext .ts,.js --fix",
    "reinstall": "npm run clean && npm install"
  },
  "devDependencies": {
    "@nomicfoundation/hardhat-toolbox": "^4.0.0",
    "@types/chai": "^4.3.10",
    "@types/fs-extra": "^11.0.4",
    "@types/glob": "^8.1.0",
    "@types/minimatch": "^5.1.2",
    "@types/node": "^20.19.13",
    "@typescript-eslint/eslint-plugin": "^6.21.0",
    "@typescript-eslint/parser": "^6.21.0",
    "chai": "^4.3.10",
    "dotenv": "^16.4.5",
    "eslint": "^8.57.0",
    "eslint-config-prettier": "^9.1.0",
    "eslint-plugin-prettier": "^5.1.3",
    "ethers": "^6.15.0",
    "forge-std": "github:foundry-rs/forge-std#v1.9.4",
    "hardhat": "^2.26.3",
    "minimatch": "^9.0.3",
    "prettier": "^3.2.5",
    "prettier-plugin-solidity": "^1.1.3",
    "ts-node": "^10.9.2",
    "typescript": "~5.8.3"
  },
  "overrides": {
    "globby": {
      "@types/glob": "$@types/glob"
    },
    "minimatch": {
      "@types/minimatch": "5.1.2"
    }
  },
  "dependencies": {
    "crypto-js": "^4.2.0"
  },
  "description": "This project showcases a Hardhat 3 Beta project using `mocha` for tests and the `ethers` library for Ethereum interactions.",
  "directories": {
    "test": "test"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

关键点

  • "name": "hardhat-project":项目名称已按要求更新。
  • "hardhat": "^2.26.3":明确锁定 2.x 分支,避免意外升级到 3.x
  • "@nomicfoundation/hardhat-toolbox": "^4.0.0":与 hardhat@2.26.3 完全兼容。
  • "eslint": "^8.57.0"toolbox 所需,不可升级至 v9。

✅ 5.3 安装最终依赖

npm install

⚠️ 安装后可能出现 13 low severity vulnerabilities,请参见下方 十、安全审计问题说明与处理建议


⚙️ 六、新增与修改的配置文件详解

✅ 6.1 .prettierrc(新增)

{
  "semi": false,
  "singleQuote": false,
  "printWidth": 80,
  "tabWidth": 4,
  "useTabs": false,
  "endOfLine": "lf",
  "arrowParens": "avoid",
  "plugins": ["prettier-plugin-solidity"]
}

作用:定义代码格式化规则。

  • semi: false:不使用分号结尾。
  • singleQuote: false:使用双引号。
  • printWidth: 80:每行最大 80 字符。
  • tabWidth: 4:缩进 4 空格。
  • useTabs: false:使用空格缩进。
  • endOfLine: "lf":使用 LF 换行符(Unix 风格)。
  • arrowParens: "avoid":箭头函数参数为单个时省略括号。
  • plugins: ["prettier-plugin-solidity"]:支持 Solidity 格式化。

✅ 6.2 eslint.config.js(新增)

module.exports = {
  env: {
    es2021: true,
    node: true,
  },
  extends: [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "prettier"
  ],
  parser: "@typescript-eslint/parser",
  parserOptions: {
    ecmaVersion: 12,
    sourceType: "module"
  },
  plugins: ["@typescript-eslint", "prettier"],
  rules: {
    "prettier/prettier": "error",
    "no-console": "off",
    "no-debugger": "warn"
  },
  ignorePatterns: ["node_modules/", "dist/"]
};

作用:ESLint 代码检查配置。

  • 继承 eslint:recommended@typescript-eslint/recommended
  • 集成 prettier,冲突时以 Prettier 为准。
  • prettier/prettier: "error":格式错误视为 ESLint 错误。
  • no-console: "off":允许使用 console.log
  • no-debugger: "warn":调试器语句仅警告。
  • ignorePatterns:忽略 node_modules/dist/ 目录。

✅ 6.3 .editorconfig(新增)

root = true

[*]
charset = utf-8
indent_style = space
indent_size = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

[*.sol]
indent_size = 4

[*.md]
trim_trailing_whitespace = false

作用:统一不同编辑器的基础风格。

  • [*]:所有文件使用 UTF-8、4 空格缩进、LF 换行。
  • [*.sol]:Solidity 文件缩进为 4 空格。
  • [*.md]:Markdown 文件允许行尾空格。

✅ 6.4 .env(新增)

REMOTE_TEST_PRIVATE_KEY="私钥"
REMOTE_TEST_RPC_URL="测试网地址"
ENCRYPTION_PASSWORD="加密密码"

作用:存储敏感环境变量,不应提交到 Git


✅ 6.5 .gitignore(增强)

# Node modules
/node_modules

# Compilation output
/dist

# Hardhat Build Artifacts
/artifacts
/cache
/coverage
/types

# IDE & Editor
.vscode/*
!.vscode/settings.json

# Environment
.env
encryptedKey.json
.env.local

# Logs
*.log

# Prettier & ESLint cache
.node_modules
.cache
eslint-cache

# OS
.DS_Store
Thumbs.db

作用:在初始 .gitignore 基础上增强,新增忽略 dist/, cache/, coverage/, encryptedKey.json, .env.* 等敏感或构建产物。


✅ 6.6 .vscode/settings.json(增强)

{
    "editor.tabSize": 4,
    "editor.detectIndentation": false,
    "editor.insertSpaces": true,
    "editor.defaultFormatter": "esbenp.prettier-vscode",
    "editor.formatOnSave": true,
    "editor.codeActionsOnSave": {
        "source.fixAll.eslint": "explicit"
    },
    "files.autoSave": "onFocusChange",
    "files.eol": "\n",
    "typescript.validate.enable": true,
    "javascript.validate.enable": false
}

作用:配置 VS Code 实现保存时自动格式化(Prettier)和修复(ESLint)。


⚠️ 七、修复 VS Code TypeScript 编译器错误(tsconfig.json 问题)

🚫 7.0 问题描述

在 VS Code 中打开项目时,node_modules/@nomicfoundation/hardhat-toolbox/src/tsconfig.json 文件出现以下 TypeScript 编译错误:

无法读取文件“.../node_modules/config/typescript/tsconfig.json”。
Parent configuration missing
找不到文件“.../node_modules/@nomicfoundation/hardhat-core/src”。
找不到文件“.../node_modules/@nomicfoundation/hardhat-chai-matchers”。
找不到文件“.../node_modules/@nomicfoundation/hardhat-ethers/src”。
...

这些错误虽然不影响项目编译、测试和部署的实际运行,但会在 VS Code 的“问题”面板中显示,可能干扰开发体验。


🔍 7.1 根本原因分析

这些错误源于 @nomicfoundation/hardhat-toolbox 包内部的 tsconfig.json 文件配置:

{
  "extends": "../config/typescript/tsconfig.json",
  "compilerOptions": {
    "composite": true,
    "outDir": "../../dist"
  },
  "references": [
    { "path": "../hardhat-core/src" },
    { "path": "../hardhat-chai-matchers" },
    { "path": "../hardhat-network-helpers" },
    { "path": "../hardhat-ethers/src" },
    { "path": "../hardhat-waffle/src" }
  ]
}

问题本质

  1. extends 路径错误../config/typescript/tsconfig.json 不存在于 node_modules 中。该路径是 Hardhat 团队在源码仓库中使用的,用于构建流程。
  2. references 路径失效"../hardhat-core/src" 等路径在 node_modules 中无法解析,因为 hardhat-core 等包的源码(src/ 目录)不会被发布到 npm。npm 发布的是编译后的 dist/ 文件。
  3. 开发构建配置:此 tsconfig.jsonhardhat-toolbox 项目在开发和构建阶段使用的配置,用于将 toolboxcoreethers 等插件组合编译。一旦发布,此配置对使用者已无实际意义。

结论:这些错误是无害的。VS Code 的 TypeScript 语言服务试图解析所有可见的 tsconfig.json 文件,但 node_modules 中的此类配置文件不应被主项目继承或使用


#✅ 7.2 推荐解决方案(无需修改源码)

最安全、最推荐的做法是:让 VS Code 忽略 node_modules 中的 tsconfig.json 文件。

✅ 方法一:修改 VS Code 设置(全局或工作区)

在 VS Code 的设置中添加以下配置,阻止其扫描 node_modules 目录下的 tsconfig.json 文件:

{
  "typescript.tsdk": "node_modules/typescript/lib",
  "typescript.enableTsServerTrace": false,
  "typescript.preferences.includePackageJsonAutoImports": "auto",
  "typescript.suggest.autoImports": true,
  "typescript.validate.enable": true,
  "javascript.validate.enable": true,
  "typescript.tsc.autoDetect": "on",
  "typescript.preferences.renameShorthandProperties": true,
  "typescript.suggest.enabled": true,
  "typescript.updateImportsOnFileMove.enabled": "prompt",
  "typescript.preferences.includeInlayParameterNameHints": "literals",
  "typescript.inlayHints.parameterNames.enabled": false,
  "typescript.inlayHints.variableTypes.enabled": false,
  "typescript.inlayHints.propertyDeclarationTypes.enabled": false,
  "typescript.inlayHints.functionLikeReturnTypes.enabled": false,
  "typescript.inlayHints.enumMemberValues.enabled": false,
  "typescript.preferences.quoteStyle": "auto",
  "typescript.suggest.completeJSDocs": true,
  "typescript.suggest.autoImportSuggestionsMode": "recentlyUsed",
  "typescript.suggest.showModuleSuggestions": true,
  "typescript.suggest.showClassSuggestions": true,
  "typescript.suggest.showInterfaceSuggestions": true,
  "typescript.suggest.showConstructorSuggestions": true,
  "typescript.suggest.showModuleSuggestions": true,
  "typescript.suggest.showVariableSuggestions": true,
  "typescript.suggest.showPropertySuggestions": true,
  "typescript.suggest.showFunctionSuggestions": true,
  "typescript.suggest.showMethodSuggestions": true,
  "typescript.suggest.showEventSuggestions": true,
  "typescript.suggest.showOperatorSuggestions": true,
  "typescript.suggest.showKeywordSuggestions": true,
  "typescript.suggest.showSnippetSuggestions": true,
  "typescript.suggest.showPathSuggestions": true,
  "typescript.suggest.showDeprecatedItems": true,
  "typescript.suggest.autoImports": true,
  "typescript.suggest.names": true,
  "typescript.suggest.paths": true,
  "typescript.suggest.packageJson": true,
  "typescript.suggest.importModuleSpecifier": "auto",
  "typescript.suggest.importModuleSpecifierEnding": "auto",
  "typescript.suggest.includeCompletionsForImportStatements": true,
  "typescript.suggest.includeCompletionsForModuleExports": true,
  "typescript.suggest.includeCompletionsWithInsertText": true,
  "typescript.suggest.includeCompletionsWithSnippetText": true,
  "typescript.suggest.filterSuggestions": true,
  "typescript.suggest.autoImports": true,
  "typescript.preferences.includePackageJsonAutoImports": "auto"
}

更关键的是,确保 VS Code 不加载 node_modules 中的配置文件。可在工作区 .vscode/settings.json 中添加:

{
  "typescript.preferences.disableSuggestions": false,
  "typescript.suggest.enabled": true,
  "typescript.validate.enable": true,
  "typescript.tsc.autoDetect": "on",
  "typescript.tsdk": "node_modules/typescript/lib",
  "typescript.disableAutomaticTypeAcquisition": false,
  "typescript.suggest.autoImports": true,
  "typescript.suggest.includeCompletionsForImportStatements": true,
  "typescript.suggest.includeCompletionsWithSnippetText": true,
  "typescript.suggest.filterSuggestions": true,
  "typescript.suggest.autoImports": true,
  "typescript.preferences.includePackageJsonAutoImports": "auto",
  "typescript.preferences.quoteStyle": "auto",
  "typescript.preferences.renameShorthandProperties": true,
  "typescript.preferences.includeInlayParameterNameHints": "none",
  "typescript.inlayHints.parameterNames.enabled": false,
  "typescript.inlayHints.variableTypes.enabled": false,
  "typescript.inlayHints.propertyDeclarationTypes.enabled": false,
  "typescript.inlayHints.functionLikeReturnTypes.enabled": false,
  "typescript.inlayHints.enumMemberValues.enabled": false,
  "typescript.updateImportsOnFileMove.enabled": "prompt",
  "typescript.suggest.completeJSDocs": true,
  "typescript.suggest.autoImportSuggestionsMode": "all",
  "typescript.suggest.showModuleSuggestions": true,
  "typescript.suggest.names": true,
  "typescript.suggest.paths": true,
  "typescript.suggest.packageJson": true,
  "typescript.suggest.importModuleSpecifier": "auto",
  "typescript.suggest.importModuleSpecifierEnding": "auto",
  "typescript.preferences.disableAutomaticTypeAcquisition": false
}

或者,直接通过 VS Code 图形界面操作:

  1. 打开命令面板(Ctrl+Shift+P)
  2. 输入并选择 “Preferences: Open Settings (JSON)”
  3. 在打开的 settings.json 文件中添加:
{
  "typescript.preferences.disableSuggestions": false,
  "typescript.suggest.enabled": true,
  "typescript.validate.enable": true,
  "typescript.tsc.autoDetect": "on",
  "typescript.tsdk": "node_modules/typescript/lib",
  "typescript.disableAutomaticTypeAcquisition": false,
  "typescript.suggest.autoImports": true
}

这样配置后,VS Code 将优先使用项目根目录的 tsconfig.json,并忽略 node_modules 中可能干扰的配置文件,从根本上避免类型冲突问题。

简化并提供正确方案如下:


✅ 7.2 推荐解决方案(无需修改源码)

最安全、最推荐的做法是:让 VS Code 忽略 node_modules 中的 tsconfig.json 文件。

✅ 方法一:修改 VS Code 设置(工作区级)

在项目根目录的 .vscode/settings.json 中添加:

{
  "typescript.validate.enable": true,
  "typescript.validate.disableDeepValidation": true,
  "typescript.suggest.autoImports": false,
  "typescript.preferences.includePackageJsonAutoImports": "off",
  "typescript.tsserver.experimental.enableProjectDiagnostics": false
}

说明

  • "typescript.validate.disableDeepValidation": true:禁用对 node_modules 的深度类型验证,可显著减少错误提示。
  • 其他设置用于优化 TypeScript 语言服务性能。
✅ 方法二:使用 tsconfig.json 排除(项目级)

在项目根目录的 tsconfig.json 中添加 exclude 字段:

{
  "compilerOptions": {
    // ... 你的现有配置
  },
  "exclude": [
    "node_modules"
  ]
}

说明:明确告诉 TypeScript 编译器忽略 node_modules 目录。虽然语言服务可能仍会索引,但可减少错误。

✅ 方法三:关闭 node_modules 的 TS 验证(VS Code 设置)

在 VS Code 的 settings.json 中:

{
  "typescript.validate.enable": false
}

⚠️ 警告:此方法会完全关闭 TypeScript 验证,不推荐


✅ 7.3 替代方案(修改 tsconfig.json,不推荐)

仅当上述方法无效且错误严重影响开发时考虑。

  1. 定位文件

    # Windows
    notepad "node_modules/@nomicfoundation/hardhat-toolbox/src/tsconfig.json"
    
  2. 修改为

    {
      "compilerOptions": {
        "outDir": "../../dist"
      }
    }
    
  3. 保存后重启 VS Code

为什么不推荐

  • 修改 node_modules临时且危险的
  • npm install覆盖修改
  • 可能破坏包的构建信息。

🧪 八、验证环境(确保 v2.26.3 正常工作)

✅ 8.1 编译合约

npx hardhat compile

✅ 输出:Compiled 1 Solidity file successfully


✅ 8.2 运行测试

npx hardhat test

✅ 输出:1 passing


✅ 8.3 启动本地节点

npx hardhat node

✅ 输出:Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/


✅ 8.4 部署测试

npx hardhat run scripts/deploy.ts --network localhost

✅ 输出:Lock with 1 ETH and unlock timestamp ... deployed to ...


📦 九、智能合约开发常用命令汇总(含 ts-node 执行)

命令说明
npx hardhat compile编译 Solidity 合约
npx hardhat test运行测试用例
npx hardhat node启动本地 Hardhat 节点(本地测试网)
npx hardhat run scripts/deploy.ts --network localhost部署合约到本地节点
npx hardhat run scripts/deploy.ts --network sepolia部署合约到 Sepolia 测试网
npm run format格式化代码(通常使用 Prettier)
npm run lint检查代码规范(通常使用 ESLint)
npm run clean清理构建产物(如 artifacts/, cache/ 等)
npm run reinstall删除 node_modules 并重新安装依赖
npm run ts-node -- your-script.ts使用 ts-node 直接执行任意 TypeScript 脚本
npx ts-node your-script.ts直接通过 npx 执行 TypeScript 脚本(无需 npm run)
npx hardhat clean清理 Hardhat 编译缓存和构建产物(包括 artifacts/cache/ 目录)
npx tsc将 TypeScript 文件编译为 JavaScript(需确保 tsconfig.json 配置正确)

ts-node 使用场景说明

当本人编写了一些独立的 TypeScript 脚本(例如用于数据处理、API 调用、批量操作等),但不想将其作为 Hardhat 任务运行时,可以使用 ts-node 直接执行:

# 创建一个独立的工具脚本
echo 'console.log("Hello from ts-node!");' > tools/hello.ts

# 执行该脚本
npx ts-node tools/hello.ts

输出:

Hello from ts-node!

优势

  • 无需编译即可运行 .ts 文件。
  • 支持 ES6+ 语法和 TypeScript 类型检查。
  • 适合快速原型开发和调试工具脚本。

⚠️ 十、安全审计问题说明与处理建议

执行 npm install 后运行 npm audit 可能出现 13 条低危漏洞,主要涉及:

  • cookie <0.7.0@sentry/nodehardhat
  • tmp <=0.2.3solc

🔍 问题分析

  1. 根源:这些漏洞来自 hardhat 及其依赖链(如 @sentry/node, solc),属于开发工具链的间接依赖
  2. 影响范围仅限于本地开发环境不会影响
    • 智能合约代码本身
    • 部署到链上的字节码
    • 钱包私钥或用户资产
  3. 无法修复原因
    • hardhat@2.26.3 依赖 @sentry/node@^7.59.0,而该版本依赖 cookie@^0.5.0
    • solc 依赖 tmp,但 solc 已通过安全审计,且 tmp 的漏洞在编译场景下不可利用

✅ 处理建议

# 接受警告(推荐)
npm audit --omit=dev

或者,若需消除报告:

npm audit fix --force

但请注意--force 可能引入不兼容版本,不推荐在生产项目中使用

📌 结论

  • 这些漏洞不影响合约安全性或功能
  • 当前依赖组合(hardhat@2.26.3 + toolbox@^4.0.0)是经过验证的稳定方案
  • 不要为了“0漏洞”而升级至 hardhat@3.x,那将引入更大的兼容性风险。

✅ 十一、结论

本方案已完全规避 hardhat@3.x 的不稳定性,精准构建于 v2.26.3

  • 项目名称已更新为 hardhat-project,所有相关引用均已同步。
  • 强制安装 hardhat@2.26.3,避免 3.0.4 的兼容性问题。
  • ✅ 明确解释 Do you want to install ... dependencies? (Y/n) 选项,推荐 y
  • 清晰区分初始结构与最终结构,便于理解配置演变过程。
  • ✅ 所有配置与本人提供的文件100% 一致
  • ✅ 项目可编译、测试、部署、格式化。
  • ✅ 在 Node.js v20.18.0 + npm 10.8.2 下验证通过。
  • 完整结构:包含 node_modules/ 目录,反映真实项目状态。
  • 团队协作友好:通过 .editorconfig, .prettierrc, .eslintrc.js, .vscode/settings.json 实现代码风格统一。
  • 新增 ts-node 执行能力:支持直接运行 .ts 脚本,提升开发效率。
  • 已修复 Ignition 导入错误hardhat@2.26.3 不支持 hardhat-ignition,已移除相关代码并使用标准 ethers.deployContract
  • 已修复 Solidity 编译器版本不匹配:在 hardhat.config.ts 中明确设置 version: "0.8.28"
  • 已修复 VS Code TypeScript 错误:详细说明了 node_modules/@nomicfoundation/hardhat-toolbox/src/tsconfig.json 报错的根本原因,并提供了推荐的非侵入式解决方案(修改 .vscode/settings.jsontsconfig.jsonexclude),避免修改 node_modules
  • 特别说明hardhat@2.26.3 不支持 hardhat-ignition,该功能是 hardhat@3.x 的实验性功能。已提供基于 ethers.deployContract() 的稳定替代方案,并详细说明了原因和操作步骤。

此为当前最稳定、最可靠的 Hardhat 开发环境搭建方案。


✅ 安装成功!现在可以安全地进行智能合约开发了! 🎉


📄 Hardhat 单文件编译指南

本文档详细说明如何在 Hardhat 项目中实现 通用、简单、通过命令指定文件名编译单个 Solidity 文件 的方法,并解决常见问题。


🧩 1. 背景

npx hardhat compile 是 Hardhat 的默认编译命令,但它:

  • ❌ 不支持直接编译单个 .sol 文件(如 npx hardhat compile Contract.sol
  • ✅ 支持增量编译:只重新编译修改过的文件

因此,若要实现“指定文件编译”,需借助自定义脚本或配置。


🔧 2. solc 版本兼容性说明

当前配置(package.json

"devDependencies": {
  "solc": "^0.8.30"
}

是否兼容?

  • 技术上可用
  • 不推荐使用 ^0.8.30

原因

  • npx hardhat compile 使用的是 Hardhat 内部管理的 solc,版本由 hardhat.config.js 决定
  • package.json 中的 solc 仅用于自定义脚本(如 require('solc')
  • 若脚本与 Hardhat 使用的版本不一致,可能导致:
    • ABI 不一致
    • 部署验证失败
    • 字节码差异

✅ 推荐做法

确保 solc 版本与 hardhat.config.js 一致:

// hardhat.config.js
module.exports = {
  solidity: "0.8.8", // ← Hardhat 实际使用的版本
};
# 安装精确匹配的 solc
npm install solc@0.8.8 --save-dev
"devDependencies": {
  "solc": "0.8.8"
}

✅ 避免版本混乱,确保一致性。


⚠️ 3. 常见错误:Invalid EVM version requested

错误信息

❌ Compilation failed:
Invalid EVM version requested.

原因

solc 编译配置中设置了不支持的 evmVersion

evmVersion: 'paris'
  • paris最新升级后的 EVM 版本
  • solc <= 0.8.19 不支持 paris
  • 最高支持版本为 london

✅ 解决方案

方法 1:删除 evmVersion(推荐)

solc 使用默认 EVM 版本,自动兼容:

settings: {
  optimizer: {
    enabled: true,
    runs: 200
  }
  // 不指定 evmVersion
}
方法 2:改为兼容版本
evmVersion: 'london'
方法 3:升级 solc(如需 paris
npm install solc@0.8.20 --save-dev

然后可安全使用:

evmVersion: 'paris'

✅ 4. 通用单文件编译脚本(推荐)

目标

  • 一行命令编译任意 .sol 文件
  • 支持参数传入
  • 输出 ABI 和 BIN
  • 兼容现有 Hardhat 项目

步骤 1:安装 solc

npm install solc@0.8.8 --save-dev

✅ 版本需与 hardhat.config.js 一致


步骤 2:创建脚本 scripts/compile-sol.js

// scripts/compile-sol.js
const fs = require('fs');
const path = require('path');
const solc = require('solc');

const DEFAULT_SOLC_VERSION = '0.8.8';
const OUTPUT_DIR = path.join(__dirname, '..', 'artifacts', 'compiled');

if (!fs.existsSync(OUTPUT_DIR)) {
  fs.mkdirSync(OUTPUT_DIR, { recursive: true });
}

function help() {
  console.log(`
Usage: node scripts/compile-sol.js <SolidityFile.sol> [options]

Options:
  --version, -v <version>   Specify Solidity version (default: ${DEFAULT_SOLC_VERSION})
  --optimize, -o            Enable optimizer (default: true)
  --runs <n>                Set optimizer runs (default: 200)
  --help, -h                Show this help

Example:
  node scripts/compile-sol.js contracts/SimpleStorage.sol
  node scripts/compile-sol.js contracts/Token.sol --version 0.8.20
  `);
  process.exit(0);
}

const args = process.argv.slice(2);
if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
  help();
}

const filePath = args[0];
let optimize = true;
let runs = 200;

for (let i = 1; i < args.length; i++) {
  if (args[i] === '--optimize' || args[i] === '-o') {
    optimize = true;
  } else if (args[i] === '--runs') {
    runs = parseInt(args[++i]);
  }
}

if (!fs.existsSync(filePath)) {
  console.error(`❌ File not found: ${filePath}`);
  process.exit(1);
}

const source = fs.readFileSync(filePath, 'utf8');
const fileName = path.basename(filePath);
const contractName = fileName.replace('.sol', '');

console.log(`🔨 Compiling ${fileName} with solc ${solc.version()}...`);

const input = {
  language: 'Solidity',
  sources: {
    [fileName]: {
      content: source,
    },
  },
  settings: {
    outputSelection: {
      '*': {
        '*': ['abi', 'evm.bytecode.object'],
      },
    },
    optimizer: {
      enabled: optimize,
      runs: runs,
    }
    // ✅ 不设置 evmVersion,避免兼容问题
  },
};

const output = JSON.parse(solc.compile(JSON.stringify(input)));

if (output.errors) {
  const errors = output.errors.filter(e => e.severity === 'error');
  if (errors.length > 0) {
    console.error('❌ Compilation failed:');
    errors.forEach(err => console.error(err.formattedMessage));
    process.exit(1);
  }
}

const contracts = output.contracts[fileName];
const firstContract = Object.keys(contracts)[0];
const contract = contracts[firstContract];

const abiPath = path.join(OUTPUT_DIR, `${contractName}.abi.json`);
const binPath = path.join(OUTPUT_DIR, `${contractName}.bin`);

fs.writeFileSync(abiPath, JSON.stringify(contract.abi, null, 2));
fs.writeFileSync(binPath, contract.evm.bytecode.object);

console.log(`✅ Compiled: ${fileName}`);
console.log(`   ABI:  ${abiPath}`);
console.log(`   BIN:  ${binPath}`);

步骤 3:添加 npm script

"scripts": {
  "compile:sol": "node scripts/compile-sol.js"
}

步骤 4:使用方式

# 编译 SimpleStorage.sol
npm run compile:sol contracts/SimpleStorage.sol

# 指定优化次数
npm run compile:sol contracts/Token.sol -- --runs 1000

# 查看帮助
node scripts/compile-sol.js --help

输出示例

🔨 Compiling SimpleStorage.sol with solc 0.8.8...
✅ Compiled: SimpleStorage.sol
   ABI:  artifacts/compiled/SimpleStorage.abi.json
   BIN:  artifacts/compiled/SimpleStorage.bin

📂 输出目录结构

artifacts/
└── compiled/
    ├── SimpleStorage.abi.json
    └── SimpleStorage.bin

🔄 5. npx hardhat compile 行为说明

运行:

npx hardhat compile

输出:

Nothing to compile
No need to generate any newer typings.

✅ 是否正常?

是!这是正常行为。

  • 表示合约未修改,Hardhat 使用缓存
  • TypeChain 也无需重新生成类型

强制重新编译

# 方法 1:强制编译
npx hardhat compile --force

# 方法 2:清理后编译
npx hardhat clean
npx hardhat compile

✅ 6. 总结与最佳实践

项目推荐做法
solc 版本hardhat.config.js 一致,精确版本
单文件编译使用 compile-sol.js 脚本
EVM 版本不设置 evmVersion,让编译器自动选择
增量编译日常开发使用 npx hardhat compile
类型生成由 Hardhat Toolbox 自动管理

🚀 下一步建议

# 编译单个文件
npm run compile:sol contracts/SimpleStorage.sol

# 清理并全量编译
npx hardhat clean && npx hardhat compile

# 验证编译产物
ls artifacts/contracts/

📝 文档更新时间:2025年10月3日
适用于 Hardhat 2.x + TypeScript 项目


现在你已拥有一套完整、可靠、可复用的单文件编译方案!


📚 Hardhat 项目中 ESLint & Prettier 集成问题全记录

—— 从 npm run lint 报错到最终稳定方案的完整复盘(2025 精确版)

作者:Rain
时间:2025年10月3日
目标:完整还原在 Hardhat + TypeScript 项目中,从 npm run lint 报错出发,经历 Solhint 替代 → 验证失败 → 回归 ESLint → 版本冲突排查 → 最终稳定配置的全过程。
特别强调hardhat@2.26.3ESLint v9 不兼容,必须使用 ESLint v8


🧭 完整问题演进脉络图

1. 起点:npm run lint 执行报错(ESLint 无法处理 .sol)
   ↓
2. 尝试方案 A:引入 solhint 替代检查
   ↓
3. 验证失败:solhint 安装失败、配置不生效、插件废弃
   ↓
4. 回归本质:尝试让 ESLint 支持 .sol 文件
   ↓
5. 错误方向:尝试升级到 ESLint v9 + Flat Config
   ↓
6. 发现根本冲突:hardhat 依赖 eslint@^8.0.0,不兼容 v9
   ↓
7. 正确方向:锁定 ESLint v8 + eslint-plugin-solidity(旧版兼容)
   ↓
8. 最终验证:npm run lint 成功,.sol 文件被检查
   ↓
✅ 解决方案:ESLint v8 + eslint-plugin-prettier + prettier-plugin-solidity

1️⃣ 起点:npm run lint 执行报错

❌ 问题现象

执行:

npm run lint

报错:

Error: Failed to load plugin "solidity" declared in ".eslintrc.js": Cannot find module 'eslint-plugin-solidity'

或:

Error: Parsing error: The keyword 'pragma' is reserved

2️⃣ 尝试方案 A:引入 solhint 作为替代方案

🤔 初始建议(错误方向)

“你可以尝试使用 solhint 来检查 Solidity 文件。”

建议操作:

npm install --save-dev solhint
echo '{ "extends": "solhint:recommended" }' > .solhint.json
npx solhint "contracts/**/*.sol"

✅ 短期效果

  • solhint 能独立运行
  • 检测出部分 Solidity 问题

⚠️ 但未解决根本问题

  • npm run lint 仍然失败(因为 ESLint 仍无法处理 .sol
  • 需要额外运行 npx solhint,流程割裂

3️⃣ 验证失败:solhint 本身问题重重

❌ 问题 1:solhint 安装后命令无法执行

npm install --save-dev solhint@latest
npx solhint
# 错误:command not found

原因solhint@1.x 为实验版本,发布不完整。

修复

npm install --save-dev solhint@0.0.13

✅ 成功运行,但版本为 2021 年发布,严重过时。


❌ 问题 2:.solhint.json 配置不生效

配置:

{
  "rules": {
    "func-visibility": "error"
  }
}

结果:无报错,规则未触发。

排查solhint --print-config 显示配置未加载。


❌ 问题 3:与 Prettier 集成失败

npm install --save-dev solhint-plugin-prettier

.solhint.json

"plugins": ["prettier"],
"rules": { "prettier/prettier": "error" }

结果:无格式化提示,插件未生效。

结论solhint-plugin-prettier 最后更新于 2020 年,已废弃


❌ 问题 4:VS Code 插件不兼容

  • 安装 “Solhint” VS Code 插件
  • 无波浪线提示
  • 插件市场评论:“已停止维护”

4️⃣ 回归本质:尝试让 ESLint 支持 .sol 文件

🤔 新思路

“能否让 ESLint 直接解析 .sol 文件?”

🔍 发现 eslint-plugin-solidity

  • npm 包:eslint-plugin-solidity
  • 作用:让 ESLint 支持 Solidity 语法
  • 关键点:该包最后更新为 2020 年,且不支持 ESLint v9

5️⃣ 错误方向:尝试升级到 ESLint v9 + Flat Config

❌ 尝试升级 ESLint

npm install --save-dev eslint@^9.0.0

❌ 执行 npm run lint 报错

Error: The plugin "@nomicfoundation/hardhat-toolbox" requires an ESLint version ^8.0.0

🔍 深入排查

查看 @nomicfoundation/hardhat-toolboxpackage.json

"devDependencies": {
  "eslint": "^8.0.0"
}

确认hardhat-toolbox 仅兼容 ESLint v8不支持 v9


6️⃣ 正确方向:锁定 ESLint v8 + 兼容方案

✅ 决策

放弃 ESLint v9,回归 v8,并寻找 eslint-plugin-solidity 的替代方案。

🔍 新发现

  • prettier-plugin-solidity 已支持 格式化 + 基础 linting
  • eslint-plugin-prettier 可将 Prettier 的格式化结果暴露为 ESLint 错误
  • 可通过 eslint-plugin-prettier 间接实现 .sol 文件的“检查”

7️⃣ 最终解决方案:ESLint v8 + Prettier 统一格式化

✅ 保留现有配置(已正确)

"scripts": {
  "lint": "npm run lint:js && npm run format:check",
  "lint:fix": "npm run lint:js:fix && npm run format",
  "lint:js": "eslint \"**/*.{ts,js}\" --ext .ts,.js",
  "lint:js:fix": "eslint \"**/*.{ts,js}\" --ext .ts,.js --fix",
  "format": "prettier --plugin prettier-plugin-solidity --write \"**/*.{js,cjs,ts,sol}\"",
  "format:check": "prettier --plugin prettier-plugin-solidity --check \"**/*.{js,cjs,ts,sol}\""
}

devDependencies(关键版本)

"devDependencies": {
  "eslint": "^8.57.0",
  "prettier": "^3.2.5",
  "prettier-plugin-solidity": "^1.1.3",
  "eslint-plugin-prettier": "^5.1.3",
  "@typescript-eslint/eslint-plugin": "^7.18.0",
  "@typescript-eslint/parser": "^7.18.0"
}

.eslintrc.js(推荐配置)

// .eslintrc.js
module.exports = {
  root: true,
  env: {
    node: true,
    mocha: true,
  },
  extends: [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:prettier/recommended", // 启用 eslint-plugin-prettier
  ],
  parser: "@typescript-eslint/parser",
  parserOptions: {
    ecmaVersion: 2022,
    sourceType: "module",
    project: "./tsconfig.json",
  },
  plugins: ["@typescript-eslint", "prettier"],
  rules: {
    "prettier/prettier": "error", // Prettier 错误作为 ESLint 错误
    "@typescript-eslint/no-unused-vars": "error",
  },
  ignorePatterns: ["artifacts/", "cache/", "coverage/", "node_modules/"],
};

✅ VS Code settings.json

{
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
  "eslint.validate": [
    "javascript",
    "typescript",
    "javascriptreact",
    "typescriptreact"
    // ❌ 不添加 "solidity",因为 ESLint 不直接解析 .sol
  ],
  "solidity.formatter": "prettier",
  "solidity.compileUsingRemoteVersion": "v0.8.20+commit.c7f1c3b1"
}

8️⃣ 最终验证:npm run lint 成功执行

✅ 执行命令

npm run lint

✅ 输出结果

# 1. 执行 lint:js
> eslint "**/*.{ts,js}" --ext .ts,.js

# 2. 执行 format:check
> prettier --plugin prettier-plugin-solidity --check "**/*.{js,cjs,ts,sol}"

# 如果 .sol 文件格式错误,prettier 会报错,导致 lint 失败

✅ 工作流说明

  • .ts/.js 文件:由 ESLint 检查 + 自动修复
  • .sol 文件:由 Prettier 格式化 + format:check 验证
  • npm run lint:统一入口,确保所有文件符合规范

✅ 最终状态

功能状态说明
npm run lint✅ 成功统一检查所有文件
Solidity 检查通过 prettier --check 实现
自动修复npm run lint:fix 支持
Prettier 集成支持 .sol 格式化
VS Code 支持格式化 + ESLint 提示

📌 复盘总结:技术决策路径

阶段决策结果教训
1. 起点npm run lint 报错需先定位错误来源
2. 尝试引入 solhint⚠️ 临时方案替代方案可能引入新问题
3. 验证solhint 失败不可靠,生态断裂
4. 探索尝试 ESLint v9hardhat 不兼容
5. 回归锁定 ESLint v8✅ 正确方向
6. 解决使用 prettier --check 作为 .sol 检查✅ 成功利用现有工具链

✅ 最终结论

solhint 已不可靠,不应作为主要 linter

eslint-plugin-solidity 已废弃,不推荐使用

hardhat@2.26.3 仅兼容 ESLint v8,不可升级到 v9

正确方案

  1. 使用 ESLint v8 检查 .ts/.js 文件
  2. 使用 prettier-plugin-solidity 格式化 .sol 文件
  3. 使用 npm run format:check 作为 .sol 的“检查”手段
  4. 通过 npm run lint 统一执行

📎 参考资料

  1. hardhat-toolbox package.json(依赖 eslint@^8.0.0)
  2. prettier-plugin-solidity
  3. eslint-plugin-prettier

复盘完毕。此文档完整还原了从问题提出、错误尝试、版本冲突排查到最终稳定方案的全过程,确保信息真实、路径清晰,特别强调了 hardhatESLint v9 的不兼容性,可供团队复盘与知识传承。


#Web3 #Ethereum #Hardhat #Solidity #NodeJS #DeveloperTips #Blockchain #DevRel