最近有点想转行做 Web3 之前在新一线某城市中厂做过几年后端的实习,家里催着考公,不是很想搞,但是工作又很烦,想曲线救国搞搞Web3。最近发现有个HackQuest的平台,上面有免费的课程。不管三七二十一,直接上去刷了一个项目课程,讲得还挺细致的,手把手教你怎么做。
我先试了个叫CryptoKitty的项目,CryptoKitty就是个基于区块链的数字猫,算是一种NFT。每只猫都有独特的基因组合和外观,可以买、可以养、还能繁殖生小猫。
然后这个课其实主要教你怎么用Solidity来写智能合约,教你把CryptoKitty的核心功能写出来,比如怎么生成一只小猫(铸造)、怎么让小猫繁殖,还能查询每只猫的具体信息啥的。基本上就是把区块链上数字猫的完整流程跑一遍。
课里讲了ERC721的标准,这个是做NFT的基础。按这个规则写代码,小猫就能作为NFT被创建、交易之类的。再往下就是学怎么用钱包发起交易,把代码真的部署到链上,还可以在链上查看自己创建的猫。之前觉得上链很高大上,学了才发现原来还挺有意思。顺便,这门课还带我们做了些‘初代小猫’的生成,就是给每只猫随机设定一套基因,后续可以通过繁殖功能来生小猫,基因会随机传给下一代。写这个功能的时候,感觉跟养成类游戏差不多,挺好玩。
我贴下简化版CryptoKitty合约的代码,大概梳理了下关键点。感兴趣的可以自己去扒项目的源代码或者跟着课程学
我贴下简化版CryptoKitty合约的代码,大概梳理了下关键点。感兴趣的可以自己去扒项目的源代码或者跟着HackQuest课程学
pragma solidity 0.8.17;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
contract SimpleCryptoKitties is ERC721 {
uint256 public _tokenIdCounter = 1;
struct Kitty {
uint256 genes;
uint256 birthTime;
uint256 momId;
uint256 dadId;
uint256 generation;
}
mapping(uint256 => Kitty) public kitties;
constructor() ERC721("SimpleCryptoKitties", "SCK") {}
function createKittyGen0() public returns (uint256) {
uint256 genes = uint256(
keccak256(abi.encodePacked(block.timestamp, _tokenIdCounter))
);
return _createKitty(0, 0, 0, genes, msg.sender);
}
function _createKitty(
uint256 momId,
uint256 dadId,
uint256 generation,
uint256 genes,
address owner
) private returns (uint256) {
kitties[_tokenIdCounter] = Kitty(
genes,
block.timestamp,
momId,
dadId,
generation
);
_mint(owner, _tokenIdCounter);
return _tokenIdCounter++;
}
function breed(uint256 momId, uint256 dadId) public returns (uint256) {
require(momId != dadId, "both ids are the same!");
require(ownerOf(momId) == msg.sender, "Not the owner of the mom kitty");
require(ownerOf(dadId) == msg.sender, "Not the owner of the dad kitty");
Kitty memory mom = kitties[momId];
Kitty memory dad = kitties[dadId];
uint256 newGeneration = (
mom.generation > dad.generation ? mom.generation : dad.generation
) + 1;
uint256 newGenes = (mom.genes + dad.genes) / 2;
return _createKitty(momId, dadId, newGeneration, newGenes, msg.sender);
}
}
基础设置
- 这个合约继承了
ERC721,所以每只猫都是一个NFT,独一无二的。 _tokenIdCounter是用来给每只猫分配唯一ID的,从1开始,每创建一只猫它就会加1。
生成初代小猫
有个createKittyGen0函数,用来生成初代小猫(Gen0)。Gen0猫没有父母,所以在调用这个函数时只用传给它一个随机基因genes。这里的genes是用当前时间戳和猫的ID生成的一个随机数,保证每只猫的基因都不同。
调用这个函数的时候会触发_createKitty函数,生成一只新的小猫,并将它分配给调用者。最后,它用_mint把这只猫真正“铸造”成NFT。
繁殖小猫
breed函数是用来繁殖两只猫的。你传入母猫和公猫的ID,合约会先检查几个条件:
- 父母ID不能相同,也就是不能自己和自己繁殖。
- 调用者必须是母猫和公猫的主人,所以只能繁殖自己拥有的猫。
之后,合约会取父母猫的基因,用一个简单的计算公式生成新猫的基因,生成的新猫属于下一代,generation自动加1。最后还是调用_createKitty来创建这只小猫。
这样下来,每只猫都有它独特的基因、出生时间、父母ID和世代信息。