面试题手册

梳理高频技术问题,帮助你按主题复习和查漏补缺。

服务端阅读 02月21日 15:59

如何在 Hardhat 中编写智能合约测试?

Hardhat 提供了强大的测试框架,基于 Mocha 和 Chai,以下是编写测试的核心要点:测试文件结构:const { expect } = require("chai");const { ethers } = require("hardhat");describe("MyContract", function () { beforeEach(async function () { const MyContract = await ethers.getContractFactory("MyContract"); this.contract = await MyContract.deploy(); await this.contract.deployed(); }); it("should return the correct value", async function () { expect(await this.contract.getValue()).to.equal(42); });});核心功能:合约部署const Contract = await ethers.getContractFactory("ContractName");const contract = await Contract.deploy();await contract.deployed();函数调用和断言const tx = await contract.someFunction(param1, param2);await tx.wait(); // 等待交易确认expect(await contract.someViewFunction()).to.equal(expectedValue);事件监听await expect(contract.someFunction()) .to.emit(contract, "EventName") .withArgs(arg1, arg2);交易回滚测试await expect(contract.failingFunction()) .to.be.revertedWith("Error message");快照功能const snapshot = await ethers.provider.send("evm_snapshot", []);// 执行一些操作await ethers.provider.send("evm_revert", [snapshot]);时间操作await ethers.provider.send("evm_increaseTime", [3600]); // 增加1小时await ethers.provider.send("evm_mine"); // 挖掘新区块最佳实践:使用 beforeEach 和 afterEach 管理测试状态为每个测试用例提供清晰的描述测试正常路径和异常路径使用有意义的测试数据保持测试的独立性和可重复性
服务端阅读 02月21日 15:59

Hardhat 如何支持 TypeScript 和类型安全?

Hardhat 对 TypeScript 提供了原生支持,以下是使用 TypeScript 的主要优势和方法:1. 项目初始化使用 TypeScript 模板创建项目:npx hardhat init# 选择 "Create a TypeScript project"2. 类型安全的合约交互Hardhat 自动生成类型定义:import { ethers } from "hardhat";async function main() { const Contract = await ethers.getContractFactory("MyContract"); const contract = await Contract.deploy() as MyContract; // 类型安全的函数调用 await contract.setValue(42); const value = await contract.value(); console.log("Value:", value.toNumber());}3. 使用 TypeChainTypeChain 为合约 ABI 生成类型定义:npm install --save-dev typechain @typechain/ethers-v5在 hardhat.config.ts 中配置:import "@typechain/hardhat";生成的类型定义:import { MyContract } from "../typechain-types";const contract: MyContract = await contractFactory.deploy();4. 测试中的类型安全import { expect } from "chai";import { ethers } from "hardhat";import { MyContract } from "../typechain-types";describe("MyContract", function () { let contract: MyContract; beforeEach(async function () { const ContractFactory = await ethers.getContractFactory("MyContract"); contract = await ContractFactory.deploy(); await contract.deployed(); }); it("should set value correctly", async function () { await contract.setValue(100); expect(await contract.value()).to.equal(100); });});5. 配置文件类型安全使用 TypeScript 配置文件 hardhat.config.ts:import { HardhatUserConfig } from "hardhat/config";import "@nomicfoundation/hardhat-toolbox";const config: HardhatUserConfig = { solidity: "0.8.19", networks: { sepolia: { url: process.env.SEPOLIA_RPC_URL || "", accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [] } }};export default config;6. 环境变量类型定义// .env.d.tsdeclare namespace NodeJS { interface ProcessEnv { SEPOLIA_RPC_URL: string; PRIVATE_KEY: string; ETHERSCAN_API_KEY: string; }}优势:编译时类型检查智能代码补全重构更安全减少运行时错误更好的代码文档团队协作更高效
服务端阅读 02月21日 15:59

Hardhat 主网分叉功能如何使用?

Hardhat 主网分叉功能允许开发者基于以太坊主网或测试网的当前状态创建本地开发环境,这对于测试 DeFi 协议和与现有合约交互非常有用。基本用法:在 hardhat.config.js 中配置分叉:networks: { hardhat: { forking: { url: process.env.MAINNET_RPC_URL, blockNumber: 15000000 // 可选:指定分叉区块 } }}使用场景:测试与主网合约的交互const uniswapRouter = await ethers.getContractAt( "IUniswapV2Router02", "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D");模拟真实市场条件// 获取主网上的代币价格const dai = await ethers.getContractAt("IERC20", DAI_ADDRESS);const price = await someOracle.getPrice(dai.address);测试 DeFi 协议集成// 在分叉环境中测试 Aave 集成const pool = await ethers.getContractAt( "IPool", "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2");高级配置:networks: { hardhat: { forking: { url: process.env.MAINNET_RPC_URL, blockNumber: 15000000, enabled: true }, chainId: 1 // 保持与主网相同的 chainId }}测试中的使用:describe("Mainnet Fork Tests", function () { it("should interact with Uniswap", async function () { // 获取测试账户 const [signer] = await ethers.getSigners(); // 获取主网 USDC const usdc = await ethers.getContractAt("IERC20", USDC_ADDRESS); const balance = await usdc.balanceOf(signer.address); console.log("USDC Balance:", balance.toString()); });});注意事项:需要 RPC 节点支持归档数据分叉会增加内存使用确保有足够的测试 ETH考虑使用固定的区块号以确保测试可重复性最佳实践:使用环境变量存储 RPC URL指定固定的区块号以确保测试稳定性在 CI/CD 中使用归档节点定期更新分叉区块号
服务端阅读 02月21日 15:59

Hardhat Network 的特点和优势是什么?

Hardhat Network 是 Hardhat 内置的本地以太坊网络,专为开发环境设计,具有以下特点:主要特性:即时挖矿:每个交易自动包含在下一个区块中,无需等待挖矿时间,大大加快开发测试速度。账户管理:默认提供 20 个测试账户,每个账户预分配 10000 ETH,方便测试各种场景。快照功能:支持创建和恢复网络状态快照,可以在测试中快速回滚到特定状态,非常适合测试可逆操作。Gas 优化:在本地网络中 Gas 费用为 0,但仍然会计算 Gas 使用量,帮助开发者优化合约。调试支持:提供 Console.log 功能,可以在合约中输出调试信息,支持交易回溯和错误堆栈跟踪。主网分叉:可以基于以太坊主网或测试网的状态创建分叉,模拟真实网络环境进行测试。与真实网络的区别:无需等待区块确认Gas 费用为零预置测试账户支持高级调试功能可以重置网络状态使用场景:单元测试和集成测试合约开发调试DeFi 协议测试交易流程验证
服务端阅读 02月21日 15:59

什么是 Hardhat Ignition 及其使用方法?

Hardhat Ignition 是 Hardhat 的声明式部署系统,提供了更强大和可维护的部署方式:核心概念:模块化部署使用模块定义部署逻辑支持模块间的依赖关系声明式配置而非命令式脚本部署状态管理自动跟踪部署状态支持增量部署避免重复部署基本使用:创建部署模块:const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules");module.exports = buildModule("TokenModule", (m) => { const token = m.contract("MyToken", ["MyToken", "MTK", 18]); return { token };});高级功能:参数化部署module.exports = buildModule("TokenModule", (m) => { const name = m.getParameter("name", "MyToken"); const symbol = m.getParameter("symbol", "MTK"); const token = m.contract("MyToken", [name, symbol, 18]); return { token };});依赖管理module.exports = buildModule("DAppModule", (m) => { const token = m.contract("MyToken"); const sale = m.contract("TokenSale", [token]); // 调用 token 合约的函数 m.call(token, "transferOwnership", [sale]); return { token, sale };});现有合约使用module.exports = buildModule("Module", (m) => { const existingContract = m.contractAt( "ExistingContract", "0x1234..." ); return { existingContract };});部署命令:# 部署到本地网络npx hardhat ignition deploy ./ignition/modules/Module.js# 部署到测试网npx hardhat ignition deploy ./ignition/modules/Module.js --network sepolia# 使用参数部署npx hardhat ignition deploy ./ignition/modules/Module.js --parameters name:CustomToken,symbol:CTK# 验证部署npx hardhat ignition deploy ./ignition/modules/Module.js --verify部署计划:Ignition 会生成部署计划,显示将要执行的操作:npx hardhat ignition plan ./ignition/modules/Module.js优势:声明式配置更易理解自动处理部署依赖支持部署验证更好的错误处理适合复杂的多合约部署便于团队协作
服务端阅读 02月21日 15:58

Hardhat 常用插件有哪些及其用途?

Hardhat 插件系统极大地扩展了其功能,以下是常用插件及其用途:核心插件:@nomicfoundation/hardhat-toolbox集成了多个常用插件包含 Ethers.js、Chai、Waffle、Etherscan、Hardhat Ignition 等适合快速开始项目hardhat-gas-reporter生成 Gas 使用报告帮助优化合约 Gas 消耗支持多种货币显示 Gas 成本@nomiclabs/hardhat-etherscan自动验证合约到 Etherscan支持多网络验证简化合约验证流程hardhat-abi-exporter导出合约 ABI 到 JSON 文件便于前端集成支持自定义导出格式开发辅助插件:hardhat-contract-sizer分析合约大小检测是否超过 24KB 限制帮助优化合约代码hardhat-deploy提供高级部署功能支持合约升级保存部署历史hardhat-ethers提供 Ethers.js 集成增强的合约交互类型安全的合约调用安全插件:hardhat-ethcan安全漏洞检测常见攻击模式识别代码质量检查hardhat-spdx-license-checker检查 SPDX 许可证标识确保合规性自动添加许可证安装和使用:// 安装插件npm install --save-dev hardhat-gas-reporter// 在 hardhat.config.js 中引入require("hardhat-gas-reporter");// 配置插件gasReporter: { enabled: true, currency: "USD"}插件开发:Hardhat 支持自定义插件开发,可以扩展任务、环境、配置等功能,满足特定项目需求。
服务端阅读 02月21日 15:58

Hardhat 配置文件的主要配置项有哪些?

Hardhat 的配置文件 hardhat.config.js(或 .ts)是项目的核心配置文件,主要包含以下配置项:基础配置:solidity 编译器配置solidity: { version: "0.8.19", settings: { optimizer: { enabled: true, runs: 200 } }}网络配置networks: { hardhat: { chainId: 31337 }, sepolia: { url: process.env.SEPOLIA_RPC_URL, accounts: [process.env.PRIVATE_KEY] }, mainnet: { url: process.env.MAINNET_RPC_URL, accounts: [process.env.PRIVATE_KEY] }}路径配置paths: { sources: "./contracts", tests: "./test", cache: "./cache", artifacts: "./artifacts"}高级配置:插件配置require("@nomicfoundation/hardhat-toolbox");require("@nomiclabs/hardhat-etherscan");Etherscan 验证配置etherscan: { apiKey: process.env.ETHERSCAN_API_KEY}Gas 报告配置gasReporter: { enabled: true, currency: "USD"}最佳实践:使用环境变量存储敏感信息为不同环境(开发、测试、生产)配置不同网络启用编译器优化以减少 Gas 消耗使用 TypeScript 配置文件获得类型安全合理设置 optimizer runs 参数
服务端阅读 02月21日 15:58

Hardhat 与 Truffle、Remix 的对比和选择?

Hardhat、Truffle 和 Remix 是三个流行的以太坊开发框架,各有特点:Hardhat优势:现代化的开发体验,TypeScript 原生支持内置本地网络,即时挖矿,快速测试强大的调试功能,支持 console.log灵活的插件系统,丰富的生态系统优秀的文档和社区支持适合中大型项目和团队协作劣势:学习曲线相对较陡配置项较多,需要一定时间熟悉Truffle优势:历史悠久,成熟稳定简单易用,上手快内置合约迁移系统广泛的社区和资源劣势:开发体验相对落后调试功能较弱本地网络需要额外配置(Ganache)TypeScript 支持不够完善Remix优势:基于浏览器,无需安装适合快速原型开发内置编译器、部署、调试适合初学者学习劣势:不适合大型项目缺乏版本控制集成测试功能有限不适合团队协作对比总结:| 特性 | Hardhat | Truffle | Remix ||------|---------|---------|-------|| 本地网络 | 内置 | 需 Ganache | 无 || TypeScript | 原生支持 | 有限 | 无 || 调试功能 | 强大 | 基础 | 基础 || 插件系统 | 丰富 | 有限 | 无 || 学习曲线 | 中等 | 简单 | 最简单 || 团队协作 | 优秀 | 良好 | 差 |选择建议:Hardhat:现代项目、团队协作、需要高级功能Truffle:传统项目、简单需求、快速原型Remix:学习 Solidity、快速测试、小型项目
服务端阅读 02月21日 15:58

什么是 Hardhat 及其核心功能?

Hardhat 是一个专为以太坊开发者设计的开发环境,它提供了一套完整的工具链用于智能合约的开发、测试、编译和部署。核心功能包括:本地开发网络:Hardhat Network 是一个内置的以太坊网络,专门为开发而设计,支持即时挖矿、账户管理等功能,开发者可以无需连接到真实网络即可测试合约。智能合约编译:基于 Solidity 编译器,支持多版本 Solidity 编译,自动处理依赖关系,生成类型安全的 TypeScript 绑定。测试框架:内置基于 Mocha 和 Chai 的测试框架,支持异步测试、快照回滚、事件监听等功能,提供丰富的断言库。部署脚本:使用 Hardhat Ignition 或自定义部署脚本,支持多网络部署、部署验证、合约升级等复杂场景。调试工具:提供 Console.log 功能、交易回溯、堆栈跟踪等调试能力,帮助开发者快速定位问题。插件生态:丰富的插件系统,支持 Ethers.js、Waffle、TypeChain、Etherscan 验证等扩展功能。主要优势:快速的开发迭代周期完整的 TypeScript 支持强大的调试能力灵活的配置系统活跃的社区和文档支持
服务端阅读 02月21日 15:58

Hardhat 中的调试技巧有哪些?

Hardhat 提供了强大的调试功能,以下是主要的调试技巧:1. Console.log 调试在 Solidity 合约中使用 console.log:import "hardhat/console.sol";contract MyContract { function setValue(uint256 _value) public { console.log("Setting value to:", _value); value = _value; console.log("Value set successfully"); }}2. 交易回溯使用 hardhat --verbose 查看详细交易信息:npx hardhat test --verbose在测试中捕获错误堆栈:try { await contract.someFunction();} catch (error) { console.log(error);}3. Hardhat Network 控制台启动交互式控制台:npx hardhat console在控制台中执行命令:const Contract = await ethers.getContractFactory("MyContract");const contract = await Contract.deploy();await contract.setValue(42);console.log(await contract.value());4. 调试测试使用 --debug 标志运行测试:npx hardhat test --debug5. 查看事件监听合约事件:contract.on("EventName", (arg1, arg2, event) => { console.log("Event emitted:", arg1, arg2);});6. 状态快照使用快照功能快速重置状态:const snapshot = await ethers.provider.send("evm_snapshot", []);// 执行操作await ethers.provider.send("evm_revert", [snapshot]);7. Gas 分析使用 gas-reporter 插件分析 Gas 使用:npx hardhat test --gas最佳实践:在开发阶段大量使用 console.log生产环境移除 console.sol 导入使用有意义的日志信息结合事件和日志进行调试利用快照功能提高测试效率