第十五天:课程收官——端到端做一个链上投票 DApp
十四天前我们还在讲什么是区块链,今天做收官:把全部知识点串成一个完整的链上投票 DApp——合约(第四天语法 + 第六天测试)、部署(第九天 Sepolia)、前端(第十一天 wagmi)。这不是新知识,是一次全流程的”组装验收”。
第一步:合约——功能最小闭环
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
contract Ballot is Ownable {
error AlreadyVoted();
error WrongPhase();
struct Candidate { string name; uint256 votes; }
Candidate[] public candidates;
mapping(address => uint256) public voteOf;
bool public open;
constructor() Ownable(msg.sender) {}
function openBallot() external onlyOwner { open = true; }
function closeBallot() external onlyOwner { open = false; }
function addCandidate(string calldata _name) external onlyOwner {
candidates.push(Candidate(_name, 0));
}
function vote(uint256 _id) external {
if (!open) revert WrongPhase();
if (voteOf[msg.sender] != type(uint256).max) revert AlreadyVoted(); // max = 未投票标记
voteOf[msg.sender] = _id;
candidates[_id].votes += 1;
}
}注意这次的工程细节:继承 Ownable(第四天手写过逻辑,现在换 OZ 标准件)、自定义 error(WrongPhase/AlreadyVoted)、未投票标记用 type(uint256).max。先在本地 forge test 全绿,再走第九天流程部署到 Sepolia 并验证源码。
第二步:前端——三个组件
- Connect 按钮:wagmi 连接组件,第十一天现成代码;
- 候选人列表:
useReadContract读 candidates + 每项的 votes,一键刷新; - 投票按钮:
useWriteContract发起 → 等待签名 →useWaitForTransactionReceipt等回执 → 刷新列表;phase 未开启时按钮禁用并提示”投票未开始”。
错误处理要接住合约的自定义 error:viem 会把 revert 解码成 AlreadyVoted() 对象,前端按 errorName 展示中文提示——这是第十一天没细讲、但真实项目必备的一环。
第三步:验收清单
- forge test 全绿、forge coverage 达标;
- Sepolia 上源码已验证,地址固定在前端配置里;
- 前端三态反馈齐全(签名中 / 确认中 / 已完成);
- Slither 扫描无高危项。
结课:接下来怎么走
十五天的课程覆盖了”环境 → 语言 → 工程 → 标准 → 部署 → 交互 → 前端 → 协议层 → 安全 → L2 → 项目”的完整闭环。之后的路线图建议:读一份真实协议的合约源码(推荐从 Uniswap V2 的 200 行核心开始)、关注 EIP 流程(学协议怎么演进)、把毕业项目开源到 GitHub 并写一篇复盘。链上世界更新很快,但底层的账户模型、签名、Gas、安全思维十年不变——这正是这门课反复强调的部分。感谢追更,评论区见。
读完了点一下,作者能得积分
赞赏
如果这篇内容帮到了你,不妨请作者喝杯咖啡
赞赏
如果这篇内容帮到了你,不妨请作者喝杯咖啡
选个金额
微信扫码扫一下,金额 ¥6
- 扫码后按所选金额支付即可
- 赞赏完全自愿,与积分、红包互不影响
发表评论