极客出发Web3:从零构建Mark loves cat DApp实战

发布时间:2026/10/17 23:58:37
极客出发Web3:从零构建Mark loves cat DApp实战 1. 从标题拆解这个项目的真实意图1.1 标题里的三个信号极客、Web3、猫第一次看到极客出发 web3_Mark loves cat这个标题我的直觉是这不是一个正经的商业项目更像是一个开发者出于兴趣做的实验性作品。为什么这么说极客出发这四个字本身就带着一种玩票性质——它不是某某平台正式上线也不是某某系统技术方案而是出发意味着这是一个起点、一次探索、一个从零到一的过程。再看web3_Mark loves cat这里的信息量其实很大。Web3 是技术方向Mark 大概率是项目发起者或者核心角色的代号loves cat 则是情感线索。把这三者拼在一起我判断这是一个以猫为主题、用 Web3 技术栈搭建的小型去中心化应用DApp可能包含数字藏品、链上互动、或者某种趣味性的宠物养成逻辑。为什么我这么判断因为 Web3 领域的个人项目有一个很明显的特征技术选型偏前沿但业务逻辑往往非常简单直接甚至带着强烈的个人趣味。一个开发者如果要做正经的商业项目不会把loves cat写进标题里。这就像你在 GitHub 上看到一个人把仓库命名为my-awesome-project和命名为i-just-want-to-feed-my-cat的区别——后者明显是带着情绪和故事在做东西。1.2 这个项目适合谁来参考我在实际接触这类项目的过程中发现它最适合三类人第一类是想入门 Web3 开发但不知道从什么项目练手的前端工程师第二类是对智能合约有兴趣、想看看一个完整 DApp 长什么样的产品经理第三类是做技术内容创作、需要找一个有话题性案例来拆解的博主。如果你已经是有多年经验的区块链开发者这个项目的技术深度可能不够你看但它的项目组织方式、合约设计思路、以及前端与链交互的处理手法仍然有参考价值。特别是对于如何用最低成本验证一个 Web3 想法这个问题这类小项目给出的答案往往比大型开源项目更实用。1.3 我为什么愿意花时间拆解它说实话Web3 领域现在充斥着大量同质化的项目分析动不动就是深度解析某公链生态或者某 DeFi 协议架构拆解。但真正让开发者成长的往往是那些小而美的个人项目。它们没有复杂的代币经济模型没有多层治理结构就是一个人、一个想法、一堆代码把东西跑起来。Mark loves cat这个标题让我想起自己早期做过的那些实验项目——功能简单但每一个技术决策都是自己做的每一个坑都是自己踩的。这种项目拆解起来反而更有意思因为你能看到真实的思考过程而不是经过包装的最佳实践。2. 核心技术点与方案选型背后的逻辑2.1 为什么是 Web3 而不是传统 Web 应用这个问题看起来简单但值得认真想。如果只是做一个Mark 爱猫的展示页面用传统技术栈一天就能搞定。为什么要引入 Web3我的判断是这个项目的核心诉求不在于展示而在于确权和互动。具体来说如果项目涉及猫的数字形象、猫的成长记录、或者猫相关的某种收藏品那么 Web3 提供的能力就变得有意义了。链上记录意味着这些数据不可篡改、公开可查而且可以跨平台流转。举个例子如果 Mark 在链上有一只猫这只猫的每一次喂食、每一次互动都记录在区块链上那么这只猫就不仅仅是一个数据库里的记录而是一个有独立生命周期的数字资产。从技术选型角度看我推测这个项目大概率选择了以太坊或者某个 EVM 兼容链作为底层。原因有三第一EVM 生态的工具链最成熟Hardhat、Foundry、Remix 这些工具让个人开发者能快速上手第二Solidity 的学习资料最多遇到问题容易找到答案第三测试网水龙头充足不需要花真金白银就能跑通全流程。2.2 智能合约的设计思路基于Mark loves cat这个主题我推测合约层至少包含以下几个核心结构猫的实体定义每只猫有唯一的 tokenId以及一组属性比如名字、年龄、毛色、性格等。这些属性可能部分上链部分存在 IPFS 或链下数据库中。互动记录Mark 与猫的互动行为比如喂食、抚摸、玩耍每次互动都产生一笔链上交易记录时间戳和互动类型。所有权或关联关系Mark 与猫之间的绑定关系可能是通过 NFT 持有来实现也可能是通过一个映射表来记录。这里有一个关键的设计决策哪些数据上链哪些数据不上链。我的经验是链上存储成本极高所以只有最核心的状态才应该上链。比如猫的归属关系、互动次数这种需要公开验证的数据适合上链而猫的图片、详细描述这种大体积数据应该放在 IPFS 或者中心化服务器上链上只存一个哈希值或 URL。注意很多新手会把所有数据都往链上塞结果部署一个合约花掉几个 ETH 的 gas 费。正确的做法是区分状态和内容状态上链内容链下。2.3 前端与链交互的技术栈选择前端部分我推测项目使用了 React 或者 Next.js 作为框架配合 ethers.js 或 wagmi 来做链交互。为什么这么判断因为这是目前 Web3 前端开发的主流组合社区支持最好遇到问题最容易找到解决方案。具体来说ethers.js 负责合约调用、签名、事件监听这些底层操作wagmi 则提供了更高层的 React Hooks比如 useAccount、useContractRead、useContractWrite让前端代码更简洁。如果项目还涉及钱包连接那大概率用了 RainbowKit 或者 ConnectKit 这类现成的组件库省去自己写连接逻辑的麻烦。这里我想特别提一点很多个人项目在钱包连接这一步就卡住了因为涉及多种钱包、多个链、多种账户状态。我的建议是初期直接用 RainbowKit它把 MetaMask、WalletConnect、Coinbase Wallet 这些主流钱包都封装好了你只需要配置一下项目 ID 就能用。2.4 存储方案IPFS 还是中心化服务器这是一个容易被忽视但很重要的决策点。如果猫的图片、元数据存在 IPFS 上好处是去中心化、永久可用坏处是上传和读取速度可能不稳定而且需要自己跑节点或者用第三方 pinning 服务。如果存在中心化服务器上好处是快、便宜、可控坏处是违背了 Web3 的去中心化精神而且服务器一挂前端就显示不出图片了。我的实际经验是对于个人项目混合方案最务实核心元数据比如猫的名字、属性用 IPFS 存保证不可篡改图片资源可以用中心化 CDN 加速同时在 IPFS 上保留一份备份。这样既保证了核心数据的去中心化又兼顾了用户体验。3. 从零搭建的完整实操流程3.1 环境准备与工具链配置假设你现在要从零开始复现这个项目第一步是搭环境。我把自己常用的工具链列一下Node.js建议用 v18 或 v20 的 LTS 版本太新的版本有时候会和某些包冲突。包管理器pnpm 比 npm 快而且对 monorepo 支持更好。如果你不熟悉 pnpm用 npm 也行不影响功能。Hardhat智能合约开发框架编译、测试、部署一条龙。Foundry如果你更喜欢用 Solidity 写测试Foundry 是更好的选择。我个人现在更倾向 Foundry因为测试跑得快。MetaMask浏览器钱包开发阶段用来连接测试网。安装命令大概是这样# 初始化项目 mkdir mark-loves-cat cd mark-loves-cat pnpm init # 安装 Hardhat pnpm add -D hardhat npx hardhat init初始化的时候选择 Create a JavaScript project 或者 Create a TypeScript project看你自己的偏好。我建议选 TypeScript虽然初期麻烦一点但后期维护成本低很多。3.2 智能合约的编写与测试合约部分我以一个简化的 Cat 合约为例展示核心逻辑// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; contract MarkLovesCat { struct Cat { string name; uint256 birthTime; uint256 interactionCount; string imageURI; } mapping(uint256 Cat) public cats; mapping(uint256 address) public catOwner; uint256 public nextCatId; event CatCreated(uint256 indexed catId, string name, address owner); event Interacted(uint256 indexed catId, string action, uint256 timestamp); function createCat(string memory _name, string memory _imageURI) external returns (uint256) { uint256 catId nextCatId; cats[catId] Cat({ name: _name, birthTime: block.timestamp, interactionCount: 0, imageURI: _imageURI }); catOwner[catId] msg.sender; emit CatCreated(catId, _name, msg.sender); return catId; } function interact(uint256 _catId, string memory _action) external { require(catOwner[_catId] msg.sender, Not your cat); cats[_catId].interactionCount; emit Interacted(_catId, _action, block.timestamp); } function getCat(uint256 _catId) external view returns (Cat memory) { return cats[_catId]; } }这个合约虽然简单但包含了几个关键设计结构体定义猫的属性、映射记录所有权、事件用于前端监听、交互函数更新状态。测试的时候我建议至少覆盖以下几个场景创建猫、非所有者尝试交互应该失败、交互后计数正确增加、事件是否正确触发。用 Hardhat 写测试大概是这样const { expect } require(chai); describe(MarkLovesCat, function () { it(Should create a cat and emit event, async function () { const [owner] await ethers.getSigners(); const Cat await ethers.getContractFactory(MarkLovesCat); const cat await Cat.deploy(); await expect(cat.createCat(Whiskers, ipfs://...)) .to.emit(cat, CatCreated) .withArgs(0, Whiskers, owner.address); const catData await cat.getCat(0); expect(catData.name).to.equal(Whiskers); }); });3.3 部署到测试网测试网我推荐 Sepolia因为它是目前以太坊主推的测试网水龙头比较多工具支持也好。部署脚本大概长这样async function main() { const [deployer] await ethers.getSigners(); console.log(Deploying with:, deployer.address); const Cat await ethers.getContractFactory(MarkLovesCat); const cat await Cat.deploy(); await cat.waitForDeployment(); console.log(Contract deployed to:, await cat.getAddress()); } main().catch((error) { console.error(error); process.exitCode 1; });部署之前记得在 hardhat.config.js 里配置好网络和私钥。私钥不要硬编码在文件里用环境变量或者 dotenv 来管理。提示测试网的 ETH 不值钱但也不要随便泄露私钥。我见过有人把带私钥的配置文件传到 GitHub 上结果测试网资产被扫走。养成好习惯从第一天就用 .env 和 .gitignore。3.4 前端页面与链交互实现前端部分我用 Next.js wagmi 来演示核心逻辑。首先是配置 wagmiimport { createConfig, http } from wagmi; import { sepolia } from wagmi/chains; import { injected } from wagmi/connectors; export const config createConfig({ chains: [sepolia], connectors: [injected()], transports: { [sepolia.id]: http(), }, });然后是一个简单的创建猫的组件import { useWriteContract, useWaitForTransactionReceipt } from wagmi; import { abi } from ./abi; function CreateCat() { const { writeContract, data: hash } useWriteContract(); const { isLoading, isSuccess } useWaitForTransactionReceipt({ hash }); const handleCreate () { writeContract({ address: 0x..., abi, functionName: createCat, args: [Whiskers, ipfs://...], }); }; return ( button onClick{handleCreate} disabled{isLoading} {isLoading ? Creating... : Create Cat} /button ); }这里的关键点是writeContract 发起交易useWaitForTransactionReceipt 等待交易确认。实际项目中你还需要处理用户拒绝签名、gas 不足、网络切换等各种异常情况。3.5 数据读取与展示读取链上数据用 useReadContract 或者 useContractReadimport { useReadContract } from wagmi; function CatDisplay({ catId }) { const { data: cat, isLoading } useReadContract({ address: 0x..., abi, functionName: getCat, args: [catId], }); if (isLoading) return divLoading.../div; if (!cat) return divCat not found/div; return ( div h2{cat.name}/h2 pInteractions: {cat.interactionCount.toString()}/p img src{cat.imageURI} alt{cat.name} / /div ); }这里有一个细节链上返回的 uint256 是 BigInt 类型直接渲染会报错需要先 toString() 或者用 formatUnits 转换。我见过不少新手在这里卡住控制台报 Objects are not valid as a React child其实就是没处理 BigInt。4. 实操中踩过的坑与排查技巧4.1 合约部署失败gas 估算错误这是最常见的问题之一。表现是部署脚本报 cannot estimate gas 或者 transaction may fail。原因通常有三种合约构造函数里有 require 条件没满足、gas limit 设得太低、或者网络拥堵导致估算不准。我的排查顺序是先看合约构造函数有没有参数校验再看 hardhat.config.js 里的 gas 配置最后尝试手动指定 gasLimit。如果是测试网可以直接把 gasLimit 设大一点比如 3000000先跑通再说。4.2 前端连接钱包后链 ID 不对用户连接钱包后如果钱包当前网络不是 Sepolia合约调用会失败。解决方案是在前端加一个网络切换的提示或者用 wagmi 的 useChainId 和 useSwitchChain 来自动处理。import { useChainId, useSwitchChain } from wagmi; import { sepolia } from wagmi/chains; function NetworkCheck() { const chainId useChainId(); const { switchChain } useSwitchChain(); if (chainId ! sepolia.id) { return ( button onClick{() switchChain({ chainId: sepolia.id })} Switch to Sepolia /button ); } return null; }4.3 IPFS 图片加载不出来这个问题我遇到过很多次。原因可能是 IPFS 网关不稳定、pin 服务过期、或者 URL 格式不对。我的做法是用 Pinata 或者 NFT.Storage 做 pinning然后在合约里存 ipfs:// 开头的 URI前端渲染时替换成可用的网关地址。function ipfsToHttp(uri) { if (uri.startsWith(ipfs://)) { return uri.replace(ipfs://, https://ipfs.io/ipfs/); } return uri; }但要注意ipfs.io 这个公共网关有时候很慢生产环境建议用自己的网关或者付费网关。4.4 交易一直 pending测试网有时候会拥堵交易可能卡很久。我的经验是如果超过 5 分钟还没确认可以在钱包里尝试加速交易用更高的 gas price 替换或者直接放弃这笔交易重新发起。在代码层面可以加一个超时提示避免用户一直等。4.5 常见问题速查表问题现象可能原因排查方法解决方案合约部署失败gas 不足或构造函数报错查看 Hardhat 报错详情提高 gasLimit检查构造函数参数前端调用合约报错链 ID 不匹配或 ABI 不对检查钱包网络和 ABI 文件切换网络重新导出 ABI图片不显示IPFS 网关问题浏览器直接访问 IPFS URL更换网关或重新 pin交易 pending网络拥堵区块浏览器查看交易状态加速交易或重新发起BigInt 渲染报错未转换类型查看控制台报错用 toString() 转换5. 这个项目还能怎么扩展5.1 加入猫的繁殖逻辑如果想让项目更有趣可以加入繁殖功能两只猫可以生成一只新猫新猫的属性由父母猫的属性决定。这涉及随机数生成链上随机数可以用 Chainlink VRF虽然成本高一点但公平性有保障。5.2 引入互动积分系统每次互动给猫增加经验值经验值累积到一定程度可以升级解锁新的外观或技能。这个逻辑可以完全放在链上也可以部分放在链下用签名来验证。5.3 多用户社交功能目前项目是单用户的如果加入多用户比如可以访问别人的猫、给别人的猫喂食、或者猫与猫之间互动那就变成了一个社交游戏。这时候需要考虑权限控制、防刷机制、以及 gas 成本分摊。5.4 部署到主网或 L2测试网跑通后如果想让真实用户使用可以考虑部署到 L2比如 Arbitrum、Optimism 或者 Base。L2 的 gas 费低很多用户体验会好很多。部署流程和测试网基本一致只是需要配置对应的网络参数和 RPC。我个人在实际操作中的体会是Web3 个人项目最大的价值不在于技术有多复杂而在于你能不能把一个想法完整地跑通。从合约编写、测试、部署到前端交互、异常处理、用户体验每一个环节都有坑但每一个坑踩过去之后你对整个技术栈的理解就会深一层。Mark loves cat这个项目虽然小但它涵盖了一个 DApp 从零到一的完整流程非常适合作为入门练手或者技术分享的案例。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询