CryptoKittes(加密猫,谜恋猫)智能合约结构和源码解析
CryptoKittes(加密猫、谜恋猫,https://www.cryptokitties.co/)是运行在以太坊上的一个游戏。 谜恋猫是世界首款架构在区块链技术上的数字猫收集与繁殖游戏,同样的技术突破使得比特币和以太坊的运作的基础。 具体可以参考如下两篇参考资料:【CryptoKitties源码解析】养猫的正确姿势!教程 | 如何在Ethereum上编写自己的CryptoKitties风
CryptoKittes(加密猫、谜恋猫,https://www.cryptokitties.co/)是运行在以太坊上的一个游戏。 谜恋猫是世界首款架构在区块链技术上的数字猫收集与繁殖游戏,同样的技术突破使得比特币和以太坊的运作的基础。
具体可以参考如下两篇参考资料:
查看代码两个地方都可以
- https://etherscan.io/address/0x06012c8cf97bead5deae237070f9587f8e7a266d#code
- https://ethfiddle.com/09YbyJRfiI
查看源码,我画了如下的图,主要结构如下:
- 猫的属性
- 主要逻辑就是从上到下继承关系
- 拍卖合约和繁殖合约
- 遵循ERC721协议和基因科学合约(源码未公布)
下面我阅读源码的笔记,没有贴源码,请参照如上地址,阅读源码:
一、合约部分
1、权限:交易需要本人账号操作,CEO/CFO/COO有特殊权限(onlyCLevel指CEO/CFO/COO皆可)1)onyCLLevel:设置区块产生速度(多少秒一个区块);提取拍卖所佣金到CFO账号;
2)CEO:暂停、启动整个合约、指定Kitty新合约地址、销售拍卖和交配权合约地址
3)COO: 生成宣传猫、初代猫,设置生育费
4)CFO: 提取佣金
2、基因科学合约(繁殖部分)未公布源码
3、主要合约分为:ERC271协议、权限控制、权属、繁殖、拍卖(猫交易、交配权拍卖)、创造(宣传猫、初代猫)
4、下面的代码是存储各种关系的数据结构,Kitty[] kitties是所有猫的数组,mapping我理解就是key-value的哈希表
// An approximation of currently how many seconds are in between blocks.
uint256 public secondsPerBlock = 15;
/*** STORAGE ***/
/// @dev An array containing the Kitty struct for all Kitties in existence. The ID
/// of each cat is actually an index into this array. Note that ID 0 is a negacat,
/// the unKitty, the mythical beast that is the parent of all gen0 cats. A bizarre
/// creature that is both matron and sire... to itself! Has an invalid genetic code.
/// In other words, cat ID 0 is invalid... ;-)
Kitty[] kitties;
/// @dev A mapping from cat IDs to the address that owns them. All cats have
/// some valid owner address, even gen0 cats are created with a non-zero owner.
mapping (uint256 => address) public kittyIndexToOwner;
// @dev A mapping from owner address to count of tokens that address owns.
// Used internally inside balanceOf() to resolve ownership count.
mapping (address => uint256) ownershipTokenCount;
/// @dev A mapping from KittyIDs to an address that has been approved to call
/// transferFrom(). Each Kitty can only have one approved address for transfer
/// at any time. A zero value means no approval is outstanding.
mapping (uint256 => address) public kittyIndexToApproved;
/// @dev A mapping from KittyIDs to an address that has been approved to use
/// this Kitty for siring via breedWith(). Each Kitty can only have one approved
/// address for siring at any time. A zero value means no approval is outstanding.
mapping (uint256 => address) public sireAllowedToAddress;
/// @dev The address of the ClockAuction contract that handles sales of Kitties. This
/// same contract handles both peer-to-peer sales as well as the gen0 sales which are
/// initiated every 15 minutes.
SaleClockAuction public saleAuction;
/// @dev The address of a custom ClockAuction subclassed contract that handles siring
/// auctions. Needs to be separate from saleAuction because the actions taken on success
/// after a sales and siring auction are quite different.
SiringClockAuction public siringAuction;
二、猫的属性
1、基因是256位标记,猫没有性别,既可以当母亲,也可以当父亲2、猫出生时间戳为代码执行系统时间
3、所有猫放在数组中,宣传猫和初代猫父母ID为0,怀孕的猫记录配偶的ID,用来判断是否怀孕,小猫出生后父亲ID就是母亲配偶ID
ID是数组的索引,猫的ID是uint32,共40亿的量,以太坊每年5亿的交易量,使用ID的地方都需要溢出检查
4、后代的代,父母的代中最大的一个加1,比如0代和1代生出的小猫代为2
5、冷却时间,1分钟-7天共14档,出生后初始值是代除以2[ floor(generation/2) ],比如2代出生后冷却就是1档,5代就是2档,以后每交配一次增加一档,最大是14档(7d)
14档{1m,2m,5m,10m,30m,1h,2h,4h,8h,16h,1d,2d,4d,7d}
/// @dev A lookup table indicating the cooldown duration after any successful
/// breeding action, called "pregnancy time" for matrons and "siring cooldown"
/// for sires. Designed such that the cooldown roughly doubles each time a cat
/// is bred, encouraging owners not to just keep breeding the same cat over
/// and over again. Caps out at one week (a cat can breed an unbounded number
/// of times, and the maximum cooldown is always seven days).
uint32[14] public cooldowns = [
uint32(1 minutes),
uint32(2 minutes),
uint32(5 minutes),
uint32(10 minutes),
uint32(30 minutes),
uint32(1 hours),
uint32(2 hours),
uint32(4 hours),
uint32(8 hours),
uint32(16 hours),
uint32(1 days),
uint32(2 days),
uint32(4 days),
uint32(7 days)
];
冷却时间确定了之后,会根据冷却时间除以区块的生成速度计算冷却区块索引
冷却时间的区块索引,这个是计算生猫后小猫记录区块的位置,防止溢出
交配后母猫冷却时间为怀孕时间,公猫也有相应的冷却时间
下面代码是Kitty的数据结构,好好理解一下
/// @dev The main Kitty struct. Every cat in CryptoKitties is represented by a copy
/// of this structure, so great care was taken to ensure that it fits neatly into
/// exactly two 256-bit words. Note that the order of the members in this structure
/// is important because of the byte-packing rules used by Ethereum.
/// Ref: http://solidity.readthedocs.io/en/develop/miscellaneous.html
struct Kitty {
// The Kitty's genetic code is packed into these 256-bits, the format is
// sooper-sekret! A cat's genes never change.
uint256 genes;
// The timestamp from the block when this cat came into existence.
uint64 birthTime;
// The minimum timestamp after which this cat can engage in breeding
// activities again. This same timestamp is used for the pregnancy
// timer (for matrons) as well as the siring cooldown.
uint64 cooldownEndBlock;
// The ID of the parents of this kitty, set to 0 for gen0 cats.
// Note that using 32-bit unsigned integers limits us to a "mere"
// 4 billion cats. This number might seem small until you realize
// that Ethereum currently has a limit of about 500 million
// transactions per year! So, this definitely won't be a problem
// for several years (even as Ethereum learns to scale).
uint32 matronId;
uint32 sireId;
// Set to the ID of the sire cat for matrons that are pregnant,
// zero otherwise. A non-zero value here is how we know a cat
// is pregnant. Used to retrieve the genetic material for the new
// kitten when the birth transpires.
uint32 siringWithId;
// Set to the index in the cooldown array (see below) that represents
// the current cooldown duration for this Kitty. This starts at zero
// for gen0 cats, and is initialized to floor(generation/2) for others.
// Incremented by one for each successful breeding action, regardless
// of whether this cat is acting as matron or sire.
uint16 cooldownIndex;
// The "generation number" of this cat. Cats minted by the CK contract
// for sale are called "gen0" and have a generation number of 0. The
// generation number of all other cats is the larger of the two generation
// numbers of their parents, plus one.
// (i.e. max(matron.generation, sire.generation) + 1)
uint16 generation;
}
三、繁殖
繁殖的过程分为:1)出售交配权(公猫),母猫主人拍卖,交配、怀孕、生产
2)相同账号的两只猫可以繁殖,只有后面三个过程
条件
1)母猫主人生育费是否够2 Finney(1 ETH=1000 Finney)
2)需要公猫的用户授权(拍卖)
3)母猫未怀孕,且双方过了冷却时间
4)是否可以交配,父母和子女,兄妹之间都不可以
怀孕
1)怀孕后,母猫和公猫都增加一档冷却时间,母猫的冷却时间就是怀孕时间
出生
1)检查怀孕时间超过冷却时间
2)新生猫的代是最大的父母代+1
3)基因由父母基因遗传+突变
4)出生的小猫归母猫主人所有
繁殖的逻辑比较复杂,我这里就不贴代码了
四、拍卖猫
价格单位//1: wei Wei Dai 戴伟 密码学家 ,发表 B-money
//10^3: lovelace Ada Lovelace 洛夫莱斯 世界上第一位程序员、诗人拜伦之女
//10^6: babbage Charles Babbage 巴贝奇 英国数学家、发明家兼机械工程师,提出了差分机与分析机的设计概念,被视为计算机先驱。
//10^9: shannon Claude Elwood Shannon 香农 美国数学家、电子工程师和密码学家,被誉为信息论的创始人
//10^12: szabo Nick Szabo 尼克萨博 密码学家、智能合约的提出者
//10^15: finney Hal Finney 芬尼 密码学家、工作量证明机制(POW)提出
//10^18: ether 以太
1)条件:猫没有在卖猫/交配权的拍卖中,没有怀孕,
2)有交易费率,交易税率以当前价格乘以税率,拍卖价格以wei为单位
3)添加拍卖后,猫的所属就交给拍卖合约了,猫不能做其他事情了
4)拍卖持续时间大于1分钟,起始价格一般(也可以低)比最后价格高,价格线性下降
5)买家出价不低于当前价格就能买下(比如初始100,最后50,100秒,在第20秒时,价格20*(100-50)/100+50=60,出价大于等于60即可)
真正扣费时是以交易时价格为准,剩余的金额会返回给买家
6)会记录0代猫的最新5只拍卖价格
五、拍卖交配权
1)条件:猫没有在猫交易/交配权的拍卖中,可以交配;符合交配规则2)固定交易费
3)拍卖成功了直接繁殖
六、宣传猫和初代猫(COO有权限)
1)宣传猫直接给账号,初代猫放到市场拍卖;宣传猫5000只,初代猫45000只2)初代猫默认价格10 Finney,默认拍卖时间1天
3)下一只初代猫开始价格为前五只猫的平均拍卖价格的1.5倍,如果小于默认价格,设为默认价格,最后价格为0,开始拍卖!
/// @dev we can create promo kittens, up to a limit. Only callable by COO
/// @param _genes the encoded genes of the kitten to be created, any value is accepted
/// @param _owner the future owner of the created kittens. Default to contract COO
function createPromoKitty(uint256 _genes, address _owner) external onlyCOO {
address kittyOwner = _owner;
if (kittyOwner == address(0)) {
kittyOwner = cooAddress;
}
require(promoCreatedCount < PROMO_CREATION_LIMIT);
promoCreatedCount++;
_createKitty(0, 0, 0, _genes, kittyOwner);
}
/// @dev Creates a new gen0 kitty with the given genes and
/// creates an auction for it.
function createGen0Auction(uint256 _genes) external onlyCOO {
require(gen0CreatedCount < GEN0_CREATION_LIMIT);
uint256 kittyId = _createKitty(0, 0, 0, _genes, address(this));
_approve(kittyId, saleAuction);
saleAuction.createAuction(
kittyId,
_computeNextGen0Price(),
0,
GEN0_AUCTION_DURATION,
address(this)
);
gen0CreatedCount++;
}
更多推荐
所有评论(0)