本教程面向有基础JavaScript/TypeScript经验、想用Claude Code加速Web3全栈开发的工程师。你将学会:用Claude Code编写、测试、审计Solidity智能合约,搭建Hardhat/Foundry工程化环境,并通过React + wagmi构建完整DApp前端。全程AI辅助,从零交付一个可部署的去中心化投票应用。
| 工具 | 版本要求 | 安装方式 |
|---|---|---|
| Node.js | v20+ | nvm install 20 && nvm use 20 |
| Claude Code | 最新版 | npm install -g @anthropic-ai/claude-code |
| MetaMask | 浏览器扩展 | Chrome/Firefox应用商店安装 |
| Git | v2.40+ | 系统包管理器安装 |
确保你的终端已登录Claude Code:
claude
# 首次使用会引导你完成API Key配置
在动手之前,先理解我们要构建的项目全貌:
graph TB
subgraph "开发环境"
CC[Claude Code CLI]
HD[Hardhat / Foundry]
end
subgraph "智能合约层"
SC[VoteContract.sol]
TEST[Test Suite]
AUDIT[Security Audit]
end
subgraph "DApp前端层"
REACT[React + Vite]
WAGMI[wagmi + viem]
UI[TailwindCSS UI]
end
subgraph "区块链网络"
LOCAL[Hardhat Local<br/>:8545]
SEPOLIA[Sepolia Testnet]
MAIN[Mainnet]
end
CC -->|"生成/审查代码"| SC
CC -->|"编写测试"| TEST
CC -->|"安全审计"| AUDIT
SC --> HD
HD --> LOCAL
HD --> SEPOLIA
SEPOLIA --> MAIN
WAGMI -->|"读写合约"| SC
REACT --> WAGMI
UI --> REACT
创建项目根目录,让Claude Code理解这是一个Web3项目:
mkdir decentralized-voting && cd decentralized-voting
claude init
在项目根目录创建 CLAUDE.md,为Claude Code提供Web3开发上下文:
# 项目:去中心化投票DApp
## 技术栈
- 智能合约:Solidity 0.8.24+, Hardhat
- 前端:React 19 + Vite + TypeScript
- Web3库:wagmi v2 + viem
- 样式:TailwindCSS v4
- 测试网络:Sepolia
## 代码规范
- Solidity:遵循 NatSpec 注释标准
- TypeScript:严格模式
- 合约函数:先检查条件,再执行状态变更,最后触发事件(Checks-Effects-Interactions)
- 所有外部调用必须放在函数最后
## 安全要求
- 禁止使用 tx.origin 做权限校验
- 状态变更后必须 emit event
- 使用 OpenZeppelin 的 Ownable、ReentrancyGuard
- 合约测试覆盖率需 > 90%
这个 CLAUDE.md 是关键——它让Claude Code在后续所有操作中都遵循Web3安全最佳实践。
用Claude Code一键生成Hardhat项目骨架:
claude -p "初始化一个Hardhat TypeScript项目,安装以下依赖:
- @openzeppelin/contracts
- @nomicfoundation/hardhat-toolbox
- hardhat-deploy
配置hardhat.config.ts支持Sepolia测试网和本地节点。
不要用hardhat init交互式命令,直接创建所有文件。"
Claude Code会生成以下文件结构:
decentralized-voting/
├── contracts/
├── scripts/
├── test/
├── ignition/
├── hardhat.config.ts
├── package.json
└── tsconfig.json
验证安装:
npx hardhat compile
# 预期输出:Compiled 0 Solidity files successfully
这是本教程的核心环节。用Claude Code编写一个功能完整的去中心化投票合约:
claude -p "在 contracts/ 目录下创建 DecentralizedVoting.sol 智能合约,功能需求:
1. 管理员创建投票提案(标题、描述、投票截止时间)
2. 使用 Merkle 树白名单机制控制投票权(gas优化)
3. 每个白名单地址只能投票一次
4. 支持查看提案状态和投票结果
5. 提案到期后自动计算结果
技术要求:
- Solidity 0.8.24
- 继承 OpenZeppelin 的 Ownable, ReentrancyGuard
- 使用 NatSpec 注释
- 遵循 Checks-Effects-Interactions 模式
- 所有状态变更必须 emit event
- 使用 mapping 而非数组来避免 gas 问题"
Claude Code将生成类似如下的合约(核心片段):
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
/// @title DecentralizedVoting - 去中心化投票系统
/// @notice 支持Merkle白名单、防重放、自动计票
contract DecentralizedVoting is Ownable, ReentrancyGuard {
struct Proposal {
string title;
string description;
uint256 deadline;
uint256 forVotes;
uint256 againstVotes;
bool executed;
mapping(address => bool) hasVoted;
}
// Merkle root for voter whitelist
bytes32 public merkleRoot;
// Proposal count => Proposal
mapping(uint256 => Proposal) public proposals;
uint256 public proposalCount;
event ProposalCreated(uint256 indexed id, string title, uint256 deadline);
event Voted(uint256 indexed proposalId, address voter, bool support);
event MerkleRootUpdated(bytes32 newRoot);
constructor() Ownable(msg.sender) {}
/// @notice 更新白名单Merkle根
function setMerkleRoot(bytes32 _merkleRoot) external onlyOwner {
merkleRoot = _merkleRoot;
emit MerkleRootUpdated(_merkleRoot);
}
/// @notice 验证投票者在白名单中
function _verifyVoter(
address voter,
bytes32[] calldata proof
) internal view returns (bool) {
bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(voter))));
return MerkleProof.verify(proof, merkleRoot, leaf);
}
/// @notice 创建新提案
function createProposal(
string calldata _title,
string calldata _description,
uint256 _durationInMinutes
) external onlyOwner returns (uint256) {
require(bytes(_title).length > 0, "Title cannot be empty");
require(_durationInMinutes > 0, "Duration must be positive");
uint256 proposalId = proposalCount++;
Proposal storage proposal = proposals[proposalId];
proposal.title = _title;
proposal.description = _description;
proposal.deadline = block.timestamp + (_durationInMinutes * 1 minutes);
emit ProposalCreated(proposalId, _title, proposal.deadline);
return proposalId;
}
/// @notice 对提案投票
function castVote(
uint256 _proposalId,
bool _support,
bytes32[] calldata _merkleProof
) external nonReentrant {
Proposal storage proposal = proposals[_proposalId];
// Checks
require(block.timestamp < proposal.deadline, "Voting ended");
require(!proposal.hasVoted[msg.sender], "Already voted");
require(
_verifyVoter(msg.sender, _merkleProof),
"Not in whitelist"
);
// Effects
proposal.hasVoted[msg.sender] = true;
if (_support) {
proposal.forVotes++;
} else {
proposal.againstVotes++;
}
emit Voted(_proposalId, msg.sender, _support);
}
}
| 问题 | 原因 | 解决方案 |
|---|---|---|
Compilation error: unreachable statement |
Solidity 0.8.x不允许不可达代码 | 让Claude Code检查并修复逻辑分支 |
TypeError: AbiEncoder |
struct中包含mapping不能作为参数 | 使用单独的getter函数替代 |
| Gas估算过高 | 存储操作过多 | 让Claude Code优化为事件驱动模式 |
Claude Code特别擅长生成高覆盖率的合约测试:
claude -p "在 test/ 目录下创建 DecentralizedVoting.test.ts,覆盖以下场景:
1. 部署合约,验证owner
2. 创建提案,验证事件发射
3. Merkle白名单验证(使用 @openzeppelin/merkle-tree 生成proof)
4. 正常投票流程(赞成/反对)
5. 异常场景:重复投票、非白名单投票、过期投票
6. 提案结果统计
使用 Hardhat 的 ethers 工具,每个测试用例使用 describe/it 结构。
确保 beforeEach 中部署新合约实例。
要求覆盖率 > 90%。"
Claude Code生成的测试核心结构:
import { expect } from "chai";
import { ethers } from "hardhat";
import { DecentralizedVoting } from "../typechain-types";
import { StandardMerkleTree } from "@openzeppelin/merkle-tree";
describe("DecentralizedVoting", () => {
let voting: DecentralizedVoting;
let owner: any, voter1: any, voter2: any, nonVoter: any;
beforeEach(async () => {
[owner, voter1, voter2, nonVoter] = await ethers.getSigners();
const Factory = await ethers.getContractFactory("DecentralizedVoting");
voting = await Factory.deploy();
});
describe("创建提案", () => {
it("管理员应能创建提案并触发事件", async () => {
await expect(voting.createProposal("Test", "Desc", 60))
.to.emit(voting, "ProposalCreated")
.withArgs(0, "Test", anyValue);
});
it("非管理员不能创建提案", async () => {
await expect(
voting.connect(voter1).createProposal("Hack", "Nope", 60)
).to.be.reverted;
});
});
describe("投票流程", () => {
let merkleTree: StandardMerkleTree<string[]>;
beforeEach(async () => {
// 构建白名单Merkle树
merkleTree = StandardMerkleTree.of(
[[voter1.address], [voter2.address]],
["address"]
);
await voting.setMerkleRoot(merkleTree.root);
await voting.createProposal("Vote Test", "Description", 1440);
});
it("白名单用户可以投赞成票", async () => {
const proof = merkleTree.getProof([voter1.address]);
await expect(
voting.connect(voter1).castVote(0, true, proof)
).to.emit(voting, "Voted");
// 验证投票状态
const proposal = await voting.proposals(0);
expect(proposal.forVotes).to.equal(1);
});
it("重复投票应被拒绝", async () => {
const proof = merkleTree.getProof([voter1.address]);
await voting.connect(voter1).castVote(0, true, proof);
await expect(
voting.connect(voter1).castVote(0, false, proof)
).to.be.revertedWith("Already voted");
});
it("非白名单用户不能投票", async () => {
const fakeProof = merkleTree.getProof([voter1.address]);
await expect(
voting.connect(nonVoter).castVote(0, true, fakeProof)
).to.be.revertedWith("Not in whitelist");
});
});
});
运行测试:
npx hardhat test
# 预期:所有测试通过,覆盖率 > 90%
Web3项目最关键的环节。用Claude Code做第一轮自动化安全审计:
claude -p "对 contracts/DecentralizedVoting.sol 进行全面安全审计,检查以下项目:
1. 重入攻击(Reentrancy)—— 已有 ReentrancyGuard?
2. 整数溢出/下溢 —— Solidity 0.8 自动检查?
3. 访问控制 —— onlyOwner 覆盖所有管理函数?
4. 前端运行(Front-running)—— 投票是否可被抢跑?
5. 拒绝服务(DoS)—— 是否存在无限循环或阻塞?
6. 时间戳依赖 —— block.timestamp 是否可被矿工操控?
7. 短地址攻击 —— 外部输入是否正确校验?
8. Gas Limit —— 是否存在可能超出块Gas限制的操作?
输出格式:每个检查项给出 ✅安全 / ⚠️警告 / ❌危险,附代码位置和修复建议。"
Claude Code会输出结构化的审计报告。常见发现及修复:
flowchart LR
subgraph "审计流程"
A[源码分析] --> B[模式匹配]
B --> C[数据流追踪]
C --> D[生成报告]
end
subgraph "检查项"
E[重入攻击]
F[访问控制]
G[整数溢出]
H[Front-running]
I[时间戳依赖]
J[Gas限制]
end
B --> E & F & G & H & I & J
D --> K["✅ 通过"]
D --> L["⚠️ 警告"]
D --> M["❌ 需修复"]
# 在项目根目录下创建前端子目录
claude -p "在 frontend/ 目录下初始化一个 React + Vite + TypeScript 项目:
- 安装 @wagmi/core @wagmi/connectors viem @tanstack/react-query
- 安装 tailwindcss @tailwindcss/vite
- 配置 vite.config.ts 支持 wagmi
- 不要使用 create-react-app,用 npm create vite 手动创建所有文件"
创建 wagmi 配置连接 Sepolia 测试网:
// frontend/src/wagmi.config.ts
import { http, createConfig } from "wagmi";
import { sepolia } from "wagmi/chains";
import { injected, metaMask } from "wagmi/connectors";
export const config = createConfig({
chains: [sepolia],
connectors: [injected(), metaMask()],
transports: {
[sepolia.id]: http(
process.env.VITE_RPC_URL || "https://rpc.sepolia.org"
),
},
});
让Claude Code生成类型安全的合约交互代码:
claude -p "在 frontend/src/hooks/ 下创建 useVotingContract.ts:
1. 使用 wagmi v2 的 useReadContract 和 useWriteContract
2. 导入合约ABI(从 ../abi/DecentralizedVoting.json)
3. 封装以下hooks:
- useProposals() - 读取所有提案列表
- useCreateProposal() - 管理员创建提案
- useCastVote() - 投票(需要传入merkle proof)
- useProposalResult() - 获取投票结果
4. 所有hook返回 isLoading, error, data
5. 使用 TypeScript 严格类型
6. ABI中不包含mapping类型(无法从外部读取mapping)"
用Claude Code生成投票DApp的完整UI:
claude -p "创建以下React组件,使用TailwindCSS样式:
1. components/ConnectWallet.tsx - 钱包连接按钮
- 使用 wagmi 的 useAccount, useConnect, useDisconnect
- 显示连接地址的缩写形式 (0x1234...abcd)
- 未连接时显示「Connect Wallet」
2. components/ProposalCard.tsx - 单个提案卡片
- 显示标题、描述、截止时间倒计时
- 赞成/反对按钮 + 当前票数
- 已投票状态显示
- 进度条显示赞成比例
3. components/CreateProposal.tsx - 创建提案表单
- 标题、描述、投票时长输入
- 仅管理员可见(通过合约owner检查)
- 表单验证
4. components/VoteDashboard.tsx - 主面板
- 聚合以上组件
- 显示提案列表
- 投票统计总览
风格:深色主题,科技感,使用 indigo/cyan 配色。"
完整的前端项目结构:
frontend/
├── src/
│ ├── abi/
│ │ └── DecentralizedVoting.json
│ ├── components/
│ │ ├── ConnectWallet.tsx
│ │ ├── CreateProposal.tsx
│ │ ├── ProposalCard.tsx
│ │ └── VoteDashboard.tsx
│ ├── hooks/
│ │ └── useVotingContract.ts
│ ├── wagmi.config.ts
│ ├── App.tsx
│ └── main.tsx
├── index.html
├── vite.config.ts
├── tailwind.config.ts
└── package.json
# 终端1:启动本地Hardhat节点
npx hardhat node
# 终端2:部署合约
claude -p "创建 scripts/deploy.ts 部署脚本:
- 部署 DecentralizedVoting 合约到本地网络
- 部署后输出合约地址
- 将ABI复制到 frontend/src/abi/ 目录
- 将部署地址写入 .env.local"
npx hardhat run scripts/deploy.ts --network localhost
# 预期输出:DecentralizedVoting deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3
# 启动前端开发服务器
cd frontend && npm run dev
# 在浏览器中:
# 1. 打开 MetaMask,连接 localhost:8545 网络
# 2. 导入Hardhat测试账户的私钥
# 3. 连接钱包到DApp
# 4. 创建提案 → 投票 → 查看结果
# 获取Sepolia ETH(水龙头)
# https://sepoliafaucet.com 或 https://www.alchemy.com/faucets
# 配置环境变量
cat > .env << 'EOF'
SEPOLIA_RPC_URL=https://eth-sepolia.g.alchemy.com/v2/YOUR_KEY
PRIVATE_KEY=your_deployer_private_key
ETHERSCAN_API_KEY=your_etherscan_key
EOF
# 部署到Sepolia
npx hardhat run scripts/deploy.ts --network sepolia
# 验证合约源码
npx hardhat verify --network sepolia DEPLOYED_CONTRACT_ADDRESS
以下是从零到部署的完整时间线和工作流:
gantt
title Claude Code Web3 DApp 开发时间线
dateFormat X
axisFormat %H:%M
section 项目初始化
Hardhat + CLAUDE.md配置 :init1, 0, 15m
section 智能合约
合约编写与生成 :c1, 15m, 45m
单元测试编写 :t1, 45m, 80m
section 安全审计
自动化审计与修复 :a1, 80m, 100m
section DApp前端
React项目初始化 :f1, 100m, 115m
wagmi配置+合约Hook :f2, 115m, 140m
UI组件开发 :f3, 140m, 180m
section 部署联调
本地部署+联调 :d1, 180m, 200m
Sepolia部署+验证 :d2, 200m, 220m
Web3开发中,精确的提示词能显著提升代码质量:
# 不要这样问
claude -p "写一个ERC20代币合约"
# 要这样问
claude -p "写一个ERC20代币合约,继承OpenZeppelin的ERC20、Ownable、Pausable,
使用SafeERC20处理所有外部token转账,
禁止 tx.origin 做权限校验,
所有状态变更 emit event,
遵循 Checks-Effects-Interactions 模式"
# 第一步:只生成合约骨架
claude -p "生成 DecentralizedVoting.sol 的接口定义和状态变量声明,不写函数实现"
# 第二步:逐个实现函数
claude -p "为 DecentralizedVoting 实现 castVote 函数,要求防重入、白名单验证"
# 第三步:补充事件和辅助函数
claude -p "为 DecentralizedVoting 补充所有 event 声明和 getter 函数"
claude -p "审查 contracts/DecentralizedVoting.sol,找出所有潜在的安全漏洞,
对照 OWASP Smart Contract Top 10 逐项检查,
给出具体的代码行号和修复diff"
使用Claude Code进行Web3开发的典型Token消耗:
| 操作 | 输入Token | 输出Token | 预估费用(Sonnet) |
|---|---|---|---|
| 合约生成 | ~2,000 | ~3,000 | $0.02 |
| 测试套件生成 | ~3,000 | ~4,000 | $0.03 |
| 安全审计 | ~4,000 | ~5,000 | $0.04 |
| 前端组件 | ~5,000 | ~6,000 | $0.05 |
| 部署脚本 | ~1,500 | ~2,000 | $0.01 |
| 完整项目 | ~15,500 | ~20,000 | ~$0.15 |
优化建议:
- 使用 --model haiku 生成样板代码(部署脚本、配置文件)
- 安全审计和合约核心逻辑用默认的 Sonnet
- 合约ABI文件不要放入CLAUDE.md,用 @file 引用避免上下文浪费
社区已开发多个Claude Code Web3专用Skill,可直接安装使用:
# 安装 Solidity 安全审计 Skill
claude skill install solidity-security
# 安装 Web3 前端开发 Skill
claude skill install web3-frontend-dapp
# 安装 Hardhat 合约开发 Skill
claude skill install hardhat-smart-contract
安装后,这些Skill会在相关操作时自动激活,为Claude Code提供Web3领域专家知识。
# 现象
Error: Unsupported Solidity version: 0.8.28
# 原因:hardhat.config.ts 中的 compiler version 与合约 pragma 不一致
# 修复:让Claude Code统一检查
claude -p "检查 hardhat.config.ts 的 solidity compiler version 和所有 .sol 文件的 pragma,
确保版本一致,推荐使用 0.8.24"
# 现象:前端调用合约方法报错 "function selector mismatch"
# 根因:合约修改后未更新前端ABI
# 解决:在CLAUDE.md中添加规则
echo "- 每次合约修改后,运行 npx hardhat compile 并将新ABI复制到 frontend/src/abi/" >> CLAUDE.md
# 现象
Error: cannot estimate gas; transaction may fail
# 调试步骤
claude -p "分析 DecentralizedVoting.sol 的 castVote 函数,
列出所有可能导致 gas 估算失败的 require 语句,
给出每个条件的调试建议"
flowchart TD
A[项目初始化<br/>Hardhat + CLAUDE.md] --> B[编写智能合约<br/>claude -p]
B --> C[编写测试用例<br/>覆盖率 > 90%]
C --> D{测试通过?}
D -->|No| B
D -->|Yes| E[安全审计<br/>OWASP SC Top 10]
E --> F{发现漏洞?}
F -->|Yes| G[修复漏洞]
G --> C
F -->|No| H[构建DApp前端<br/>React + wagmi]
H --> I[本地联调<br/>Hardhat node]
I --> J{功能正常?}
J -->|No| H
J -->|Yes| K[部署Sepolia<br/>验证合约]
K --> L[生产就绪]
style A fill:#6366f1,color:#fff
style E fill:#f59e0b,color:#000
style K fill:#10b981,color:#fff
style L fill:#10b981,color:#fff
| 维度 | 评估 |
|---|---|
| 适用训练营类型 | Web3开发者训练营、区块链工程师培训、AI+Web3交叉课程 |
| 学员基础要求 | JavaScript/TypeScript中级,了解区块链基本概念 |
| 预计教学时长 | 4-6小时(含实操) |
| 硬件要求 | 8GB+ RAM,稳定网络,MetaMask钱包 |
| 课后产出 | 一个完整部署在Sepolia上的去中心化投票DApp |
| 难度评级 | ⭐⭐⭐ 中高级 |
[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。
