CryptoKitties源码阅读

CryptoKitties源码阅读:

CryptoKitties是非常知名的以太坊Dapp,使用了ERC721规范创造了一个在区块链上养小猫猫的游戏,该游戏上线时一度造成以太坊主网拥堵,还是比较厉害哒。
该应用的源码有非常丰富的注释,而且代码行数也不是特别多,建议有兴趣的小伙伴可以去读一下。(放出的只是部分代码,涉及基因的核心代码并未放出)
作者才疏学浅,看代码看得头疼。所以本文只是简单得对源码进行了自己的注释。

源码地址:https://etherscan.io/address/0x06012c8cf97bead5deae237070f9587f8e7a266d#code

有哪些合约?

contract Ownable
contract ERC721
contract GeneScienceInterface
contract KittyAccessControl 
contract KittyBase is KittyAccessControl
contract ERC721Metadata
contract KittyOwnership is KittyBase, ERC721
contract KittyBreeding is KittyOwnership
contract ClockAuctionBase
contract Pausable is Ownable
contract ClockAuction is Pausable, ClockAuctionBase
contract SiringClockAuction is ClockAuction 
contract SaleClockAuction is ClockAuction 
contract KittyAuction is KittyBreeding
contract KittyMinting is KittyAuction
contract KittyCore is KittyMinting 

contract Ownable

该合约设置了一个owner变量,通过设定owner来实现简单的认证,还提供了一个修改owner的函数。

contract Ownable {              //该合约主要起到设置一个owner,给整个合约提供基本的认证和用户权限的认证
  address public owner;

  function Ownable() {          //通过构造函数,设定初始化时的请求地址为owner,即第一个发布到链上的人
    owner = msg.sender;
  }


  modifier onlyOwner() {        //设定onlyOwner修饰符,为后面的身份验证提供支持
    require(msg.sender == owner);
    _;
  }


  function transferOwnership(address newOwner) onlyOwner {      //提供修改owner的功能,使用了onlyOwner修饰符,因此只有当前的owner有资格执行
    if (newOwner != address(0)) {
      owner = newOwner;
    }
  }
}

contract ERC721

该合约起到的作用是提供ERC721标准的接口,ERC721是不可互换通证。

contract ERC721 {

    function totalSupply() public view returns (uint256 total);
    function balanceOf(address _owner) public view returns (uint256 balance);
    function ownerOf(uint256 _tokenId) external view returns (address owner);
    function approve(address _to, uint256 _tokenId) external;
    function transfer(address _to, uint256 _tokenId) external;
    function transferFrom(address _from, address _to, uint256 _tokenId) external;

    event Transfer(address from, address to, uint256 tokenId);
    event Approval(address owner, address approved, uint256 tokenId);

    function supportsInterface(bytes4 _interfaceID) external view returns (bool);
}

contract GeneScienceInterface

该合约也只是提供了几个函数的接口

contract GeneScienceInterface {
    
    function isGeneScience() public pure returns (bool);
    function mixGenes(uint256 genes1, uint256 genes2, uint256 targetBlock) public returns (uint256);
}

contract KittyAccessControl

该合约提供的功能是定义了一个当合约升级时的事件、三个管理者的地址变量和一个控制合约启停状态的bool变量,还提供了几个对于身份进行验证的修饰符,以及CEO设置其他职位的函数、管理者修改停止状态的函数、CEO启动合约的函数。

contract KittyAccessControl {

    event ContractUpgrade(address newContract);         //定义了一个事件,顾名思义应该是当合约需要升级时触发

    address public ceoAddress;                          //定义了三个地址,分别是CEO、CFO、COO
    address public cfoAddress;
    address public cooAddress;

    bool public paused = false;                         //定义一个bool类型的变量pause,用来实现对合约的启停状态控制

    modifier onlyCEO() {                                //修饰符,判断请求者是不是CEO
        require(msg.sender == ceoAddress);
        _;
    }

    modifier onlyCFO() {                                 //修饰符,判断请求者是不是CFO
        require(msg.sender == cfoAddress);
        _;
    }

    modifier onlyCOO() {                                 //修饰符,判断请求者是不是COO
        require(msg.sender == cooAddress);
        _;
    }

    modifier onlyCLevel() {                                //修饰符,判断请求者中是否是CEO、CFO、COO中的任意一个
        require(
            msg.sender == cooAddress ||
            msg.sender == ceoAddress ||
            msg.sender == cfoAddress
        );
        _;
    }

    function setCEO(address _newCEO) external onlyCEO {             //设置新的CEO,只有CEO能调用,且传入地址不能是0地址,只能被外部合约调用
        require(_newCEO != address(0));

        ceoAddress = _newCEO;
    }

    function setCFO(address _newCFO) external onlyCEO {             //设置新的CFO,只有CEO能调用,且传入地址不能是0地址,只能被外部合约调用
        require(_newCFO != address(0));

        cfoAddress = _newCFO;
    }

    function setCOO(address _newCOO) external onlyCEO {             //设置新的COO,只有CEO能调用,且传入地址不能是0地址,只能被外部合约调用
        require(_newCOO != address(0));

        cooAddress = _newCOO;
    }

    modifier whenNotPaused() {                                      //修饰符,判断是否是暂停状态,当paused是false的时候能正常执行后面的程序
        require(!paused);
        _;
    }

    modifier whenPaused {                                           //修饰符,判断是否是暂停状态,当paused是True的时候能正常执行后面的程序
        require(paused);
        _;
    }

    function pause() external onlyCLevel whenNotPaused {            //通过函数来调整paused的状态为暂停,只能CEO\CFO\COO三人调整,且调整前paused的状态需要是false
        paused = true;
    }

    function unpause() public onlyCEO whenPaused {                 //通过函数来调整paused的状态为运行,只能CEO调整,且调整前paused的状态需要是True
        paused = false;
    }
}

contract KittyBase is KittyAccessControl

该合约是继承自KittyAccessControl,该合约主要时设定了小猫的属性和小猫的所属等一系列的存储,以及新小猫的诞生和小猫的交易部分。

contract KittyBase is KittyAccessControl {

    event Birth(address owner, uint256 kittyId, uint256 matronId, uint256 sireId, uint256 genes);       //定义了一个当新小猫出现时触发的事件

    event Transfer(address from, address to, uint256 tokenId);                                          //定义了一个交易的事件

    struct Kitty {                                     //定义一个小猫的结构体、其中包含了小猫的各种属性

        uint256 genes;      //基因(永远不会变的-源码备注)

        uint64 birthTime;       //出生事件的时间戳

        uint64 cooldownEndBlock;    //一个锁定的定时器、根据源码注释是用来控制小猫的繁殖的

        uint32 matronId;       //新小猫的妈妈的ID,对于初始gen0小猫为0
        uint32 sireId;          //新小猫的爸爸的ID,对于初始gen0小猫为0

        uint32 siringWithId;      //如果正在繁殖期则为对象的ID,否则为0

        uint16 cooldownIndex;   //定义冷却数组的下标

        uint16 generation;      //定义代号,第几代小猫
    }

    uint32[14] public cooldowns = [         //定义一个14个长度的数组,其中存储的是时间
        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)
    ];

    uint256 public secondsPerBlock = 15;        //两个区块之间的时间

    Kitty[] kitties;        //定义了一个存储所有猫的动态数组

    mapping (uint256 => address) public kittyIndexToOwner;      //猫的主人是谁

    mapping (address => uint256) ownershipTokenCount;       //一个地址拥有多少个小猫

    mapping (uint256 => address) public kittyIndexToApproved;       //定义批准小猫交易的地址

    mapping (uint256 => address) public sireAllowedToAddress;       //定义批准小猫交配的地址
    SaleClockAuction public saleAuction;         

    SiringClockAuction public siringAuction;       

    function _transfer(address _from, address _to, uint256 _tokenId) internal {     //定义函数将特定的小猫分配给特定的地址
        ownershipTokenCount[_to]++;    //_to地址的小猫数的++  
        kittyIndexToOwner[_tokenId] = _to;  //将小猫的id映射到_to地址
        if (_from != address(0)) {      //判断_from是否是0地址
            ownershipTokenCount[_from]--;       //从_from地址映射的小猫数量减掉1
            delete sireAllowedToAddress[_tokenId];  //删除这个小猫的繁殖的允许的地址
            delete kittyIndexToApproved[_tokenId];      //删除这个小猫交易的允许地址
        }
        Transfer(_from, _to, _tokenId);     //进行交易
    }

    function _createKitty(      //定义一个创建小猫的函数,需要提供五个参数且只能内部调用,返回一个uint的小猫id
        uint256 _matronId,  //母亲id
        uint256 _sireId,    //父亲id
        uint256 _generation,    //代数
        uint256 _genes, //基因
        address _owner  //拥有者
    )
        internal
        returns (uint)
    {
        require(_matronId == uint256(uint32(_matronId)));       //保证数据都在正常范围内
        require(_sireId == uint256(uint32(_sireId)));
        require(_generation == uint256(uint16(_generation)));

        uint16 cooldownIndex = uint16(_generation / 2);     //对应的冷却数组的下标应该是代数/2
        if (cooldownIndex > 13) {   //如果代数大于26,那么就给下标赋值最大的13,因为cooldownIndex是一个长度为14的定长数组,所以最大下标只能为13
            cooldownIndex = 13;
        }

        Kitty memory _kitty = Kitty({   //生成一个小猫的基本属性
            genes: _genes,
            birthTime: uint64(now),
            cooldownEndBlock: 0,
            matronId: uint32(_matronId),
            sireId: uint32(_sireId),
            siringWithId: 0,
            cooldownIndex: cooldownIndex,
            generation: uint16(_generation)
        }); 
        uint256 newKittenId = kitties.push(_kitty) - 1;    //将猫咪放入kitties数组,猫咪ID等于kitties数组中的顺序编号

        require(newKittenId == uint256(uint32(newKittenId)));   //确保小猫的id不会超过2**32只,因为当2**32是大于uint32的,那么uint256 newKittenID和uint256(uint32(newKittenId)是不会相等的
                                                                //如果newKittenID大于2**32  那么对其进行uint32会丢掉高位,只保留低位的32位。因此和uint256的newKittenID是不相等的
        Birth(                              //触发brith时间
            _owner,     
            newKittenId,
            uint256(_kitty.matronId),
            uint256(_kitty.sireId),
            _kitty.genes
        );

        _transfer(0, _owner, newKittenId);      //给小猫分配所属权

        return newKittenId;
    }

    function setSecondsPerBlock(uint256 secs) external onlyCLevel {             //定义一个生成区块的函数,CEO\CFO\COO可以控制   
        require(secs < cooldowns[0]);       //判断输入事件是否小于1分钟
        secondsPerBlock = secs;         //如果小于1分钟的话将两个区块时间设为输入的secs
    }
}

contract ERC721Metadata

contract ERC721Metadata {                                                                              //ERC721的非同质化代币标准,该部分为可选的元信息扩展
    /// @dev Given a token Id, returns a byte array that is supposed to be converted into string.
    function getMetadata(uint256 _tokenId, string) public view returns (bytes32[4] buffer, uint256 count) {
        if (_tokenId == 1) {
            buffer[0] = "Hello World! :D";
            count = 15;
        } else if (_tokenId == 2) {
            buffer[0] = "I would definitely choose a medi";
            buffer[1] = "um length string.";
            count = 49;
        } else if (_tokenId == 3) {
            buffer[0] = "Lorem ipsum dolor sit amet, mi e";
            buffer[1] = "st accumsan dapibus augue lorem,";
            buffer[2] = " tristique vestibulum id, libero";
            buffer[3] = " suscipit varius sapien aliquam.";
            count = 128;
        }
    }
}

contract KittyOwnership is KittyBase, ERC721

这个合约继承了一个kittyBase和ERC721,主要实现了合约中接口定义的一些方法和合约的名称、单位

contract KittyOwnership is KittyBase, ERC721 {                                                          //该合约是一个继承自kittyBase和ERC721的合约
 
    string public constant name = "CryptoKitties";              //定义token的名字
    string public constant symbol = "CK";           //定义token的符号

    ERC721Metadata public erc721Metadata;       

    bytes4 constant InterfaceSignature_ERC165 =         //定义常量用来保存ERC165的函数方法,
        bytes4(keccak256('supportsInterface(bytes4)'));

    bytes4 constant InterfaceSignature_ERC721 =         //定义常量用来保存ERC721的函数方法
        bytes4(keccak256('name()')) ^
        bytes4(keccak256('symbol()')) ^
        bytes4(keccak256('totalSupply()')) ^
        bytes4(keccak256('balanceOf(address)')) ^
        bytes4(keccak256('ownerOf(uint256)')) ^
        bytes4(keccak256('approve(address,uint256)')) ^
        bytes4(keccak256('transfer(address,uint256)')) ^
        bytes4(keccak256('transferFrom(address,address,uint256)')) ^
        bytes4(keccak256('tokensOfOwner(address)')) ^
        bytes4(keccak256('tokenMetadata(uint256,string)'));

    function supportsInterface(bytes4 _interfaceID) external view returns (bool)        //通过对函数方法进行判断,看是否满足ERC165和ERC721的标准
    {
        return ((_interfaceID == InterfaceSignature_ERC165) || (_interfaceID == InterfaceSignature_ERC721));
    }

    function setMetadataAddress(address _contractAddress) public onlyCEO {          //通过地址设置Matadata,仅限CEO调用
        erc721Metadata = ERC721Metadata(_contractAddress);
    }

    function _owns(address _claimant, uint256 _tokenId) internal view returns (bool) {      //验证小猫的所属者是否输入某个地址
        return kittyIndexToOwner[_tokenId] == _claimant;
    }

    function _approvedFor(address _claimant, uint256 _tokenId) internal view returns (bool) {          //验证某个待交易的小猫的允许交易的地址是否匹配
        return kittyIndexToApproved[_tokenId] == _claimant;
    }

    function _approve(uint256 _tokenId, address _approved) internal {           //给小猫设置一个允许交易的地址
        kittyIndexToApproved[_tokenId] = _approved;
    }

    function balanceOf(address _owner) public view returns (uint256 count) {        //返回某个地址拥有的小猫数量
        return ownershipTokenCount[_owner];
    }

    function transfer(                                      //交易函数,当合约没有暂停的时候可以执行
        address _to,
        uint256 _tokenId
    )
        external
        whenNotPaused
    {
        require(_to != address(0));         //判断要转到的地址不是零地址
        require(_to != address(this));      //判断要转到的地址不是合约的地址,address(this)为当前合约的地址
        require(_to != address(saleAuction));           //判断要转到的地址不是拍卖时钟的地址
        require(_to != address(siringAuction));    //判断要转到的地址不是繁殖时钟的地址
        require(_owns(msg.sender, _tokenId));       //判断小猫的所属者是不是当前请求的地址
        _transfer(msg.sender, _to, _tokenId);       //触发交易事件,从请求者将小猫_tokenId转移到_to
    }

    function approve(       //授权函数,当合约没被暂停的时候有效
        address _to,
        uint256 _tokenId
    )
        external
        whenNotPaused
    {
        require(_owns(msg.sender, _tokenId));       //判断请求者是否是小猫的所有者
        _approve(_tokenId, _to);        //将小猫授权给_to,该操作会覆盖掉之前的授权操作
        Approval(msg.sender, _to, _tokenId);    //触发授权事件
    }

    function transferFrom(      //实现一个取走小猫的函数,当合约没被暂停时使用
        address _from,
        address _to,
        uint256 _tokenId
    )
        external
        whenNotPaused
    {
        require(_to != address(0));     //判断不是零地址
        require(_to != address(this));  //判断不是合约地址
        require(_approvedFor(msg.sender, _tokenId));    //判断当前小猫的授权地址是否与请求者相匹配
        require(_owns(_from, _tokenId));        //判断小猫的所有者是不是_from地址

        _transfer(_from, _to, _tokenId);        //重新分配所有权,同时将清楚所有挂起的审批并触发交易事件
    }

    function totalSupply() public view returns (uint) {     //返回当前小猫的总数
        return kitties.length - 1;
    }

    function ownerOf(uint256 _tokenId)              //返回当前给定小猫的主人地址
        external
        view
        returns (address owner)
    {
        owner = kittyIndexToOwner[_tokenId];            //owner为mapping中小猫id对应的地址

        require(owner != address(0));       //判断不是零地址
    }

    function tokensOfOwner(address _owner) external view returns(uint256[] ownerTokens) {           //返回某个地址所拥有的所有小猫
        uint256 tokenCount = balanceOf(_owner);     //小猫的个数等于_owner的余额

        if (tokenCount == 0) {          //  如果小猫的数量等于零,直接返回一个空的数组
            return new uint256[](0);
        } else {        //如果不为零,执行下面的操作
            uint256[] memory result = new uint256[](tokenCount);        //定义一个存储类型为memory的数组,数组长度为拥有的小猫个数,memory可以减小gas的消耗且不会写到链上     
            uint256 totalCats = totalSupply();          //赋值一个最大的小猫的数量
            uint256 resultIndex = 0;        
            uint256 catId;

            for (catId = 1; catId <= totalCats; catId++) {      //通过一个for循环去便利每一个小猫的所有者,如果找到一个所有者为给出的地址的则将其写入到result数组中。resultIndex调整位置,顺序存储
                if (kittyIndexToOwner[catId] == _owner) {
                    result[resultIndex] = catId;
                    resultIndex++;
                }
            }

            return result;      //返回result数组得到某个人拥有的全部小猫
        }
    }

    function _memcpy(uint _dest, uint _src, uint _len) private view {     // 拷贝方法
        for(; _len >= 32; _len -= 32) {     
            assembly {
                mstore(_dest, mload(_src))
            }
            _dest += 32;
            _src += 32;
        }
        uint256 mask = 256 ** (32 - _len) - 1;
        assembly {
            let srcpart := and(mload(_src), not(mask))
            let destpart := and(mload(_dest), mask)
            mstore(_dest, or(destpart, srcpart))
        }
    }

    function _toString(bytes32[4] _rawBytes, uint256 _stringLength) private view returns (string) { // 将_rawBytes中长度为_stringLength转成string并返回
        var outputString = new string(_stringLength);
        uint256 outputPtr;
        uint256 bytesPtr;

        assembly {
            outputPtr := add(outputString, 32)
            bytesPtr := _rawBytes
        }

        _memcpy(outputPtr, bytesPtr, _stringLength);

        return outputString;
    }

    function tokenMetadata(uint256 _tokenId, string _preferredTransport) external view returns (string infoUrl) {       // 返回指向该元数据的元数据包的URI
        require(erc721Metadata != address(0));
        bytes32[4] memory buffer;
        uint256 count;
        (buffer, count) = erc721Metadata.getMetadata(_tokenId, _preferredTransport);

        return _toString(buffer, count);
    }
}

contract KittyBreeding is KittyOwnership

该部分合约主要是实现了小猫怀孕和诞生新小猫的功能,其中存在很多伦理关系的检查和怀孕逻辑的检查。是主要的功能点之一-繁殖。

contract KittyBreeding is KittyOwnership {

    event Pregnant(address owner, uint256 matronId, uint256 sireId, uint256 cooldownEndBlock);      //创建怀孕的事件

    uint256 public autoBirthFee = 2 finney;     //出生的费用
    uint256 public pregnantKitties;     //怀孕的小猫

    GeneScienceInterface public geneScience;        //

    function setGeneScienceAddress(address _address) external onlyCEO {
        GeneScienceInterface candidateContract = GeneScienceInterface(_address);  //实例化GeneScienceInterface合约

        require(candidateContract.isGeneScience()); //该函数的具体实现逻辑不清楚,代码中未给出明确的执行逻辑,仅给出了接口,返回一个bool,且是pure类型,不对链上数据进行修改也不读取

        geneScience = candidateContract;
    }

    function _isReadyToBreed(Kitty _kit) internal view returns (bool) {         //检查小猫是否可以去繁殖
        return (_kit.siringWithId == 0) && (_kit.cooldownEndBlock <= uint64(block.number)); //需要检查两项,小猫的冷却时间和小猫是否有未出生的孩子,因为从孕育小猫到小猫出生还有一段时间
    }

    function _isSiringPermitted(uint256 _sireId, uint256 _matronId) internal view returns (bool) {          //对两个小猫的父母地址进行检查
        address matronOwner = kittyIndexToOwner[_matronId];         //获取母亲小猫的所有者
        address sireOwner = kittyIndexToOwner[_sireId];         //获取父亲小猫的所有者
        return (matronOwner == sireOwner || sireAllowedToAddress[_sireId] == matronOwner);          //如果父母相等或者允许父系小猫交配的地址是母系小猫所有者的地址则返回true
    }

    function _triggerCooldown(Kitty storage _kitten) internal {     //触发冷却的函数
        _kitten.cooldownEndBlock = uint64((cooldowns[_kitten.cooldownIndex]/secondsPerBlock) + block.number);   //小猫的冷却时间等于第几次触发冷却规定的时间/定义的secondsPerBlock+当前块的时间,次数越高时间越长
        if (_kitten.cooldownIndex < 13) {  //如果触发冷却的次数小于13,则每次执行该函数的时候都会使次数加1
            _kitten.cooldownIndex += 1;
        }
    }

    function approveSiring(address _addr, uint256 _sireId)      //授权进行繁殖的函数
        external
        whenNotPaused
    {
        require(_owns(msg.sender, _sireId));            //判断请求者是不是sireId的所有者,如果是的话就给SireId小猫授权给_addr繁殖
        sireAllowedToAddress[_sireId] = _addr;          
    }

    function setAutoBirthFee(uint256 val) external onlyCOO {        //设置繁殖的费用,只有COO能够调用
        autoBirthFee = val;         
    }

    function _isReadyToGiveBirth(Kitty _matron) private view returns (bool) {           //检查给定的小猫是否怀孕且孕期已过
        return (_matron.siringWithId != 0) && (_matron.cooldownEndBlock <= uint64(block.number));
    }

    function isReadyToBreed(uint256 _kittyId)       //实现功能检查给定的小猫是否能进行繁殖
        public
        view
        returns (bool)
    {
        require(_kittyId > 0);      //判断kittyid要是大于0的
        Kitty storage kit = kitties[_kittyId];  //取出小猫数组中对应的kittyId的小猫的信息
        return _isReadyToBreed(kit);        //然后调用函数判断是否能繁殖
    }

    function isPregnant(uint256 _kittyId)           //实现功能判断是否怀孕了的函数
        public
        view
        returns (bool)
    {
        require(_kittyId > 0);      //依旧是给定的id必须大于0
        return kitties[_kittyId].siringWithId != 0;         //siringWithId该参数正在繁殖期为对象ID,否则为0
    }

    function _isValidMatingPair(            //实现功能检查是否有效的配对
        Kitty storage _matron,
        uint256 _matronId,
        Kitty storage _sire,
        uint256 _sireId
    )
        private
        view
        returns(bool)
    {
        if (_matronId == _sireId) {         //首先父母不能是同一只小猫,必须是两个不同的小猫
            return false;
        }
            //小猫其实是没有性别的,在此处只是为了区分两个小猫所以有sireid和matronid,此处是限制小猫不能和自己的父母进行繁殖
        if (_matron.matronId == _sireId || _matron.sireId == _sireId) {     //母小猫的父母中的任意小猫都不能是对象小猫
            return false;
        }
        if (_sire.matronId == _matronId || _sire.sireId == _matronId) {     //父小猫的父母中的任意一个都不是能对象小猫
            return false;
        }
        if (_sire.matronId == 0 || _matron.matronId == 0) {     //如果夫母小猫是0的话是可以的,因为说明他们是1代小猫。
            return true;
        }
        if (_sire.matronId == _matron.matronId || _sire.matronId == _matron.sireId) {       //小猫不能与兄弟姐妹进行繁殖
            return false;
        }
        if (_sire.sireId == _matron.matronId || _sire.sireId == _matron.sireId) {   //小猫不能与兄弟姐妹进行繁殖
            return false;
        }
        return true;        //除上述条件外其他全为true
    }
    function _canBreedWithViaAuction(uint256 _matronId, uint256 _sireId)        //判断是否符合要求的函数
        internal
        view
        returns (bool)
    {
        Kitty storage matron = kitties[_matronId];
        Kitty storage sire = kitties[_sireId];
        return _isValidMatingPair(matron, _matronId, sire, _sireId);        //通过调用上面的函数来进行判断
    }
    function canBreedWith(uint256 _matronId, uint256 _sireId)       //依旧是进行判断
        external
        view
        returns(bool)
    {
        require(_matronId > 0);
        require(_sireId > 0);
        Kitty storage matron = kitties[_matronId];
        Kitty storage sire = kitties[_sireId];
        return _isValidMatingPair(matron, _matronId, sire, _sireId) &&      //血缘关系要满足伦理要求并且相关地址要得到了交配的授权
            _isSiringPermitted(_sireId, _matronId);
    }
    function _breedWith(uint256 _matronId, uint256 _sireId) internal {      //
        Kitty storage sire = kitties[_sireId];
        Kitty storage matron = kitties[_matronId];

        matron.siringWithId = uint32(_sireId);      //给siringWithId赋值为对象的id

        _triggerCooldown(sire);     //给双亲设置冷却时间
        _triggerCooldown(matron);      

        delete sireAllowedToAddress[_matronId];     //删除双亲小猫给定的授权进行交配的地址,即交配授权一次有效
        delete sireAllowedToAddress[_sireId];

        pregnantKitties++;      //怀孕的小猫数量+1

        Pregnant(kittyIndexToOwner[_matronId], _matronId, _sireId, matron.cooldownEndBlock);        //触发怀孕的事件
    }

    function breedWithAuto(uint256 _matronId, uint256 _sireId)      //函数功能实现了检查在怀孕过程中所有需要检查的,然后调用函数处理怀孕需要处理的
        external
        payable
        whenNotPaused
    {
        require(msg.value >= autoBirthFee);     //判断余额是否大于小猫出生的费用
        require(_owns(msg.sender, _matronId));      //判断请求者是否是母亲小猫的拥有者
        require(_isSiringPermitted(_sireId, _matronId));        //判断父母小猫的地址是否是同一个,或者是否得到了授权

        Kitty storage matron = kitties[_matronId];      //获取母亲小猫的信息

        require(_isReadyToBreed(matron));   //确保母亲是没有怀孕的或者在冷却期

        Kitty storage sire = kitties[_sireId];  //获取父亲的信息

        require(_isReadyToBreed(sire));     //确保父亲是没有怀孕的或者在冷却期
        require(_isValidMatingPair(     //通过调用函数检查是否满足伦理要求
            matron,
            _matronId,
            sire,
            _sireId
        ));
        _breedWith(_matronId, _sireId); //触发_breedWith,给双亲设置冷却,怀孕小猫队列增加,删除授权的交配信息
    }

    function giveBirth(uint256 _matronId)       //
        external
        whenNotPaused
        returns(uint256)
    {
        Kitty storage matron = kitties[_matronId];

        require(matron.birthTime != 0);     //出生事件不等于0
        require(_isReadyToGiveBirth(matron));   //检查小猫是否怀孕且孕期已过

        uint256 sireId = matron.siringWithId;   
        Kitty storage sire = kitties[sireId];

        uint16 parentGen = matron.generation;
        if (sire.generation > matron.generation) {              //如果父亲的代数高于母亲的代数
            parentGen = sire.generation;    //那么父母代数=父亲的代数
        }
        uint256 childGenes = geneScience.mixGenes(matron.genes, sire.genes, matron.cooldownEndBlock - 1);       //设置孩子的代数
        address owner = kittyIndexToOwner[_matronId];   //将新小猫的主人设置为母亲小猫的主人
        uint256 kittenId = _createKitty(_matronId, matron.siringWithId, parentGen + 1, childGenes, owner);  //创建新的小猫
        delete matron.siringWithId;     //删除母亲小猫的交配对象ID
        pregnantKitties--;  //怀孕的小猫减1
        msg.sender.send(autoBirthFee);      //消息的调用者支付费用
        return kittenId;    //返回新出生小猫的id
    }
}

contract ClockAuctionBase

该合约主要介绍了小猫的拍卖相关的函数,例如相关事件、拍卖收益的计算和一些价格浮动计算方面的函数。

contract ClockAuctionBase {         

    struct Auction {        //定义一个结构体,主要包含的参数有,售卖者,起拍价格,拍卖结束价格,拍卖持续时间,拍卖开始时间
        address seller;
        uint128 startingPrice;
        uint128 endingPrice;
        uint64 duration;
        uint64 startedAt;   //开始拍卖的时间,如果拍卖已结束则为0 
    }
    ERC721 public nonFungibleContract;      //实例化一个ERC721
    uint256 public ownerCut;        //定义一个涨幅

    mapping (uint256 => Auction) tokenIdToAuction;      //定义一个从小猫id到拍卖信息结构体的映射

    event AuctionCreated(uint256 tokenId, uint256 startingPrice, uint256 endingPrice, uint256 duration);        //三个事件,分别是创建拍卖和拍卖成功和流派的事件
    event AuctionSuccessful(uint256 tokenId, uint256 totalPrice, address winner);
    event AuctionCancelled(uint256 tokenId);

    function _owns(address _claimant, uint256 _tokenId) internal view returns (bool) {      //判断小猫的主人是否是传入的地址,返回bool类型
        return (nonFungibleContract.ownerOf(_tokenId) == _claimant);
    }

    function _escrow(address _owner, uint256 _tokenId) internal {       //将小猫托管给拍卖系统,托管失败会抛出异常
        nonFungibleContract.transferFrom(_owner, this, _tokenId);
    }

    function _transfer(address _receiver, uint256 _tokenId) internal {      //实现拍卖的交易系统,将小猫发送给买的人,失败也会抛出异常
        nonFungibleContract.transfer(_receiver, _tokenId);
    }

    function _addAuction(uint256 _tokenId, Auction _auction) internal {     //该函数实现将拍卖加入队列,并且触发AuctionCreated事件
        require(_auction.duration >= 1 minutes);    //要求所有的拍卖时间必须大于等于1分钟

        tokenIdToAuction[_tokenId] = _auction;  //将该小猫加入拍卖队列

        AuctionCreated(         //触发AuctionCreated事件    
            uint256(_tokenId),
            uint256(_auction.startingPrice),    
            uint256(_auction.endingPrice),
            uint256(_auction.duration)
        );
    }

    function _cancelAuction(uint256 _tokenId, address _seller) internal {       //实现无条件的取消拍卖
        _removeAuction(_tokenId);               //从拍卖队列中删除tokenid对应的小猫
        _transfer(_seller, _tokenId);           //将tokenid对应的小猫退回给出售者
        AuctionCancelled(_tokenId);         //触发事件取消拍卖
    }

    function _bid(uint256 _tokenId, uint256 _bidAmount)     //  该函数主要是实现投标
        internal
        returns (uint256)
    {
        Auction storage auction = tokenIdToAuction[_tokenId];     //获取某个小猫的拍卖信息  
        require(_isOnAuction(auction));         //判断该拍卖是还在进行中
        uint256 price = _currentPrice(auction);     //给price赋予起拍价
        require(_bidAmount >= price);   //判断出价是否大于或等于起拍价
        address seller = auction.seller;        //给seller地址赋值,避免拍卖结束后删除相关拍卖队列值丢失
        _removeAuction(_tokenId);   //从拍卖队列中删除小猫

        if (price > 0) {        //如果价格大于0
            uint256 auctioneerCut = _computeCut(price);     //计算拍卖师的收益
            uint256 sellerProceeds = price - auctioneerCut; //计算拍卖者的收益
            seller.transfer(sellerProceeds);        //拍卖者拿走自己的收益
        }
        uint256 bidExcess = _bidAmount - price;     //bidexces= 投标金额-起拍价,前方已经限制了_bidAmount>=price 所以不存在下溢
        msg.sender.transfer(bidExcess); //归还资金
        AuctionSuccessful(_tokenId, price, msg.sender);         //触发拍卖成功的事件

        return price;
    }

    function _removeAuction(uint256 _tokenId) internal {            //从拍卖队列中删除tokenid对应的小猫
        delete tokenIdToAuction[_tokenId];  
    }

    function _isOnAuction(Auction storage _auction) internal view returns (bool) {      //判断是否在拍卖中
        return (_auction.startedAt > 0);    //判断拍卖时间是否大于0,因为拍卖如果结束或者流拍都会变成0
    }

    function _currentPrice(Auction storage _auction)        //一个实现计算当前价格功能的函数
        internal
        view
        returns (uint256)
    {
        uint256 secondsPassed = 0;
        if (now > _auction.startedAt) {         //如果现在的时间大于拍卖开始时间,那么secondsPassed等于二者的差值
            secondsPassed = now - _auction.startedAt;   
        }

        return _computeCurrentPrice(
            _auction.startingPrice,
            _auction.endingPrice,
            _auction.duration,
            secondsPassed
        );
    }

    function _computeCurrentPrice(          //该函数实现了计算当前价格的功能,可以看到拍卖的加价不是固定的,是根据短期类加价的幅度来计算
        uint256 _startingPrice,
        uint256 _endingPrice,
        uint256 _duration,
        uint256 _secondsPassed
    )
        internal
        pure
        returns (uint256)
    {

        if (_secondsPassed >= _duration) {      //如果现在时间和起拍时间的差值大于等于持续时间

            return _endingPrice;        //那么返回拍卖的最终价格
        } else {

            int256 totalPriceChange = int256(_endingPrice) - int256(_startingPrice);    //总价格变动等于成交价格减去起拍价格
            int256 currentPriceChange = totalPriceChange * int256(_secondsPassed) / int256(_duration);  //价格变化等于总的价格变动*出价时间/持续时间
            int256 currentPrice = int256(_startingPrice) + currentPriceChange;      //现在的价格等于开始的价格加上当前价格变化
            return uint256(currentPrice);       //返回一个现在的价格
        }
    }

    function _computeCut(uint256 _price) internal view returns (uint256) {   //计算拍卖师的收益  
        return _price * ownerCut / 10000;               //价格*涨幅/10000
    }

}

contract Pausable is Ownable

该合约实现的是对合约暂停运行状态的改变,继承自Ownable来进行权限控制。通过一个变量来控制运行,只有owner可以修改状态,但是前面KittyAccessControl也实现了合约的启停,暂时不理解重写的作用是什么

contract Pausable is Ownable {      //一个继承自Ownable的合约
  event Pause();        //定义事件暂停和解除暂停
  event Unpause();

  bool public paused = false;    

  modifier whenNotPaused() {       //创建修饰符,当paused为false的时候为whenNotPause触发
    require(!paused);
    _;
  }

  modifier whenPaused {     //创建修饰符,当paused为true时whenPaused触发
    require(paused);
    _;
  }

  function pause() onlyOwner whenNotPaused returns (bool) {     //实现改变暂停状态为暂停的函数,只能Owner使用,返回bool变量
    paused = true;  //改变paused状态,触发Pause()事件
    Pause();            
    return true;
  }

  function unpause() onlyOwner whenPaused returns (bool) {      //实现改变状态为运行的函数,只能Owner使用,返回bool变量
    paused = false;     
    Unpause();  
    return true;
  }
}

contract ClockAuction is Pausable, ClockAuctionBase

该合约主要是实现了交易过程中上拍、取拍、获取拍卖信息、取出合约余额、初始化拍卖合约的地址和涨幅

contract ClockAuction is Pausable, ClockAuctionBase {       //合约clockAuction 继承自Pausable和ClockAuctionBase

    bytes4 constant InterfaceSignature_ERC721 = bytes4(0x9a20483d);     //ERC721接口的加密byte为(0x9a20483d)

    function ClockAuction(address _nftAddress, uint256 _cut) public {       //构造函数,用于创建合约,初始化拍卖合约地址和增幅
        require(_cut <= 10000);     //判断每次涨幅的百分比是否小于10000%,小于等于则ownerCut=_cut
        ownerCut = _cut;

        ERC721 candidateContract = ERC721(_nftAddress);        //使用拍卖地址初始化ERC721合约
        require(candidateContract.supportsInterface(InterfaceSignature_ERC721));        //对该对象的接口进行检查看是否满足ERC721标准
        nonFungibleContract = candidateContract;       
    }

    function withdrawBalance() external {
        address nftAddress = address(nonFungibleContract);      //将拍卖合约的地址赋给nftaddress

        require(           //验证如果请求者等于owner或者请求者等于拍卖合约地址
            msg.sender == owner ||
            msg.sender == nftAddress
        );
        bool res = nftAddress.send(this.balance);       //转走合约的余额,通过将其设置为bool变量使得不管成功失败都不会对程序运行造成影响
    }

    function createAuction(         //创建拍卖的函数
        uint256 _tokenId,
        uint256 _startingPrice,
        uint256 _endingPrice,
        uint256 _duration,
        address _seller
    )
        external
        whenNotPaused
    {
        require(_startingPrice == uint256(uint128(_startingPrice)));            //通过变量转换来使得限制数量的大小,如果_startingPrice是大于2**128则该等式不会成立
        require(_endingPrice == uint256(uint128(_endingPrice)));    
        require(_duration == uint256(uint64(_duration)));   //不大于2**64

        require(_owns(msg.sender, _tokenId));       //判断请求者是否是小猫的拥有者
        _escrow(msg.sender, _tokenId);      //托管小猫
        Auction memory auction = Auction(   //新实例化一个拍卖
            _seller,
            uint128(_startingPrice),
            uint128(_endingPrice),
            uint64(_duration),
            uint64(now)
        );
        _addAuction(_tokenId, auction);     //执行函数,加入拍卖队列并触发创建拍卖的事件
    }

    function bid(uint256 _tokenId)          //投标函数 可外部调用 payable
        external
        payable
        whenNotPaused
    {

        _bid(_tokenId, msg.value);      //对tokenid进行投标,投标金额为发送的金额
        _transfer(msg.sender, _tokenId);        //将小猫分配给出价的人
    }

    function cancelAuction(uint256 _tokenId)        //实现取消拍卖的功能
        external
    {
        Auction storage auction = tokenIdToAuction[_tokenId];       //获取小猫的拍卖信息
        require(_isOnAuction(auction));     //判断是否在拍卖中
        address seller = auction.seller;    //seller赋值,避免拍卖销毁后失去seller
        require(msg.sender == seller);  //判断请求者是否是seller
        _cancelAuction(_tokenId, seller);   //取消拍卖,删除信息、退货、触发取消的事件
    }

    function cancelAuctionWhenPaused(uint256 _tokenId)  //当合约暂停的时候取消拍卖。只有合约的拥有者能调用
        whenPaused
        onlyOwner
        external
    {
        Auction storage auction = tokenIdToAuction[_tokenId];       
        require(_isOnAuction(auction));     
        _cancelAuction(_tokenId, auction.seller);
    }

    function getAuction(uint256 _tokenId)       //获取拍卖信息
        external
        view
        returns
    (
        address seller,
        uint256 startingPrice,
        uint256 endingPrice,
        uint256 duration,
        uint256 startedAt
    ) {
        Auction storage auction = tokenIdToAuction[_tokenId];        //获取小猫的拍卖信息
        require(_isOnAuction(auction));     //判断交易状态
        return (    //返回信息
            auction.seller, 
            auction.startingPrice,
            auction.endingPrice,
            auction.duration,
            auction.startedAt
        );
    }

    function getCurrentPrice(uint256 _tokenId)      //获取当前价格
        external
        view
        returns (uint256)
    {
        Auction storage auction = tokenIdToAuction[_tokenId];           //获取小猫的拍卖信息
        require(_isOnAuction(auction));     //判断交易状态
        return _currentPrice(auction);  //返回当前价格
    }
}

contract SiringClockAuction is ClockAuction

该部分合约实现的是创建繁殖的合约

contract SiringClockAuction is ClockAuction {       //拍卖

    // @dev Sanity check that allows us to ensure that we are pointing to the
    //  right auction in our setSiringAuctionAddress() call.
    bool public isSiringClockAuction = true;

    // Delegate constructor
    function SiringClockAuction(address _nftAddr, uint256 _cut) public          //构造函数,直接使用了contract ClockAuction的构造函数
        ClockAuction(_nftAddr, _cut) {}

    /// @dev Creates and begins a new auction. Since this function is wrapped,
    /// require sender to be KittyCore contract.
    /// @param _tokenId - ID of token to auction, sender must be owner.
    /// @param _startingPrice - Price of item (in wei) at beginning of auction.
    /// @param _endingPrice - Price of item (in wei) at end of auction.
    /// @param _duration - Length of auction (in seconds).
    /// @param _seller - Seller, if not the message sender
    function createAuction(     //创建拍卖
        uint256 _tokenId,
        uint256 _startingPrice,
        uint256 _endingPrice,
        uint256 _duration,
        address _seller
    )
        external
    {
        // Sanity check that no inputs overflow how many bits we've allocated
        // to store them in the auction struct.
        require(_startingPrice == uint256(uint128(_startingPrice)));        //通过变量进制变化实现数据大小控制,避免溢出
        require(_endingPrice == uint256(uint128(_endingPrice)));
        require(_duration == uint256(uint64(_duration)));

        require(msg.sender == address(nonFungibleContract));        //构造函数中会对_nftAddr进行验证看是否满足ERC721标准,然后将其赋值给nonFungibleContract
        _escrow(_seller, _tokenId);                          //托管小猫 
        Auction memory auction = Auction(       //实例化一个拍卖
            _seller,
            uint128(_startingPrice),
            uint128(_endingPrice),
            uint64(_duration),
            uint64(now)
        );
        _addAuction(_tokenId, auction);         //将tokenId加入拍卖队列
    }

    /// @dev Places a bid for siring. Requires the sender
    /// is the KittyCore contract because all bid methods
    /// should be wrapped. Also returns the kitty to the
    /// seller rather than the winner.
    function bid(uint256 _tokenId)      //投标
        external
        payable
    {
        require(msg.sender == address(nonFungibleContract));        
        address seller = tokenIdToAuction[_tokenId].seller;            
        // _bid checks that token ID is valid and will throw if bid fails
        _bid(_tokenId, msg.value);
        // We transfer the kitty back to the seller, the winner will get
        // the offspring
        _transfer(seller, _tokenId);
    }

}

contract SaleClockAuction is ClockAuction

该部分合约实现售卖的合约并且计算售卖gen0小猫时的价格

contract SaleClockAuction is ClockAuction {
    // 当我们调用setSaleAuctionAddress()方法时,用于确认指向了正确的拍卖合约地址
    bool public isSaleClockAuction = true;

    // 记录最后5只0代猫售价
    uint256 public gen0SaleCount;
    uint256[5] public lastGen0SalePrices;

    // Delegate constructor
    function SaleClockAuction(address _nftAddr, uint256 _cut) public
        ClockAuction(_nftAddr, _cut) {}

    // 项目方发起拍卖,创建拍卖合约,创建成功后,token拥有者地址变更至拍卖行地址
    function createAuction(
        uint256 _tokenId,
        uint256 _startingPrice,
        uint256 _endingPrice,
        uint256 _duration,
        address _seller
    )
        external
    {
        // Sanity check that no inputs overflow how many bits we've allocateds
        // to store them in the auction struct.
        require(_startingPrice == uint256(uint128(_startingPrice)));
        require(_endingPrice == uint256(uint128(_endingPrice)));
        require(_duration == uint256(uint64(_duration)));

        require(msg.sender == address(nonFungibleContract));
        _escrow(_seller, _tokenId);
        Auction memory auction = Auction(
            _seller,
            uint128(_startingPrice),
            uint128(_endingPrice),
            uint64(_duration),
            uint64(now)
        );
        _addAuction(_tokenId, auction);
    }

    // 用户竞标
    function bid(uint256 _tokenId)
        external
        payable
    {
        // 项目方与拍卖行分账
        address seller = tokenIdToAuction[_tokenId].seller;
        uint256 price = _bid(_tokenId, msg.value);
        _transfer(msg.sender, _tokenId);

        // 记录最后5只0代猫售价
        if (seller == address(nonFungibleContract)) {
            // Track gen0 sale prices
            lastGen0SalePrices[gen0SaleCount % 5] = price;
            gen0SaleCount++;
        }
    }

    //根据最后5只0代猫售价,计算平均价格
    function averageGen0SalePrice() external view returns (uint256) {
        uint256 sum = 0;
        for (uint256 i = 0; i < 5; i++) {
            sum += lastGen0SalePrices[i];
        }
        return sum / 5;
    }
}

contract KittyAuction is KittyBreeding

这部分合约主要是实现设置售卖合约和繁殖拍卖合约的地址,售卖合约和拍卖合约的初始化

contract KittyAuction is KittyBreeding {

    // @notice The auction contract variables are defined in KittyBase to allow
    //  us to refer to them in KittyOwnership to prevent accidental transfers.
    // `saleAuction` refers to the auction for gen0 and p2p sale of kitties.
    // `siringAuction` refers to the auction for siring rights of kitties.

    /// @dev Sets the reference to the sale auction.
    /// @param _address - Address of sale contract.
    function setSaleAuctionAddress(address _address) external onlyCEO {     //设置售卖合约的地址,仅CEO可以调用
        SaleClockAuction candidateContract = SaleClockAuction(_address);        //通过SaleClockAuction(_address来实例化一个合约)

        // NOTE: verify that a contract is what we expect - https://github.com/Lunyr/crowdsale-contracts/blob/cfadd15986c30521d8ba7d5b6f57b4fefcc7ac38/contracts/LunyrToken.sol#L117
        require(candidateContract.isSaleClockAuction());     //确认合同地址符合预期

        // Set the new contract address
        saleAuction = candidateContract;        //设置新的合约地址
    }

    /// @dev Sets the reference to the siring auction.
    /// @param _address - Address of siring contract.
    function setSiringAuctionAddress(address _address) external onlyCEO {       //设置繁殖合约的地址,仅CEO可以调用
        SiringClockAuction candidateContract = SiringClockAuction(_address);    //_address来实例化一个合约

        // NOTE: verify that a contract is what we expect - https://github.com/Lunyr/crowdsale-contracts/blob/cfadd15986c30521d8ba7d5b6f57b4fefcc7ac38/contracts/LunyrToken.sol#L117
        require(candidateContract.isSiringClockAuction());

        // Set the new contract address
        siringAuction = candidateContract;
    }

    /// @dev Put a kitty up for auction.
    ///  Does some ownership trickery to create auctions in one tx.
    function createSaleAuction(     //创建一个售卖合约
        uint256 _kittyId,
        uint256 _startingPrice,
        uint256 _endingPrice,
        uint256 _duration
    )
        external
        whenNotPaused
    {
        // Auction contract checks input sizes
        // If kitty is already on any auction, this will throw
        // because it will be owned by the auction contract.
        require(_owns(msg.sender, _kittyId));           
        // Ensure the kitty is not pregnant to prevent the auction
        // contract accidentally receiving ownership of the child.
        // NOTE: the kitty IS allowed to be in a cooldown.
        require(!isPregnant(_kittyId));     //要没有怀孕才能卖,防止意外获得孩子
        _approve(_kittyId, saleAuction);    //将小猫授权给售卖合约
        // Sale auction throws if inputs are invalid and clears
        // transfer and sire approval after escrowing the kitty.
        saleAuction.createAuction(      //创建拍卖
            _kittyId,
            _startingPrice,
            _endingPrice,
            _duration,
            msg.sender
        );
    }

    /// @dev Put a kitty up for auction to be sire.
    ///  Performs checks to ensure the kitty can be sired, then
    ///  delegates to reverse auction.
    function createSiringAuction(   //创建交配合约
        uint256 _kittyId,
        uint256 _startingPrice,
        uint256 _endingPrice,
        uint256 _duration
    )
        external
        whenNotPaused
    {
        // Auction contract checks input sizes
        // If kitty is already on any auction, this will throw
        // because it will be owned by the auction contract.
        require(_owns(msg.sender, _kittyId));   //判断请求者是否拥有
        require(isReadyToBreed(_kittyId));      //是否可以准备好了繁殖
        _approve(_kittyId, siringAuction);      //授权小猫给合约
        // Siring auction throws if inputs are invalid and clears
        // transfer and sire approval after escrowing the kitty.
        siringAuction.createAuction(        //创建交配拍卖
            _kittyId,
            _startingPrice,
            _endingPrice,
            _duration,
            msg.sender
        );
    }

    /// @dev Completes a siring auction by bidding.
    ///  Immediately breeds the winning matron with the sire on auction.
    /// @param _sireId - ID of the sire on auction.
    /// @param _matronId - ID of the matron owned by the bidder.
    function bidOnSiringAuction(        //给交配合约投标
        uint256 _sireId,        //定义父母id
        uint256 _matronId
    )
        external
        payable
        whenNotPaused
    {
        // Auction contract checks input sizes
        require(_owns(msg.sender, _matronId));      //判断权限,判断是否准备好繁殖、判断是否符合伦理要求
        require(isReadyToBreed(_matronId));
        require(_canBreedWithViaAuction(_matronId, _sireId));

        // Define the current price of the auction.
        uint256 currentPrice = siringAuction.getCurrentPrice(_sireId);      //获取当前价格
        require(msg.value >= currentPrice + autoBirthFee);          //判断发送的数量是否大于等于当前价格+出生费用

        // Siring auction will throw if the bid fails.
        siringAuction.bid.value(msg.value - autoBirthFee)(_sireId);     //投标的钱数等于消息的金额总数减去生孩子的小费
        _breedWith(uint32(_matronId), uint32(_sireId));     //修改双亲冷却事件、清除双亲的授权状态、触发怀孕事件
    }

    /// @dev Transfers the balance of the sale auction contract
    /// to the KittyCore contract. We use two-step withdrawal to
    /// prevent two transfer calls in the auction bid function.
    function withdrawAuctionBalances() external onlyCLevel {        //取出合约的钱,只能CEO\CFO\COO调用
        saleAuction.withdrawBalance();          //取出售卖拍卖合约的钱
        siringAuction.withdrawBalance();        //取出繁殖拍卖合约的钱
    }
}

contract KittyMinting is KittyAuction

该部分合约主要是实现在程序运行初期赠送引流的小猫的创建和gen0代的小猫的上市销售。

contract KittyMinting is KittyAuction {         //该合约主要是实现在合约刚被创立初期,这些小猫猫怎么来的

    // Limits the number of cats the contract owner can ever create.
    uint256 public constant PROMO_CREATION_LIMIT = 5000;        //限制合同所有者可以创建猫的数量
    uint256 public constant GEN0_CREATION_LIMIT = 45000;

    // Constants for gen0 auctions.
    uint256 public constant GEN0_STARTING_PRICE = 10 finney;        //
    uint256 public constant GEN0_AUCTION_DURATION = 1 days;

    // Counts the number of cats the contract owner has created.
    uint256 public promoCreatedCount;
    uint256 public gen0CreatedCount;

    /// @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)) {     //如果小猫的主人地址为0,就给COO
             kittyOwner = cooAddress;
        }
        require(promoCreatedCount < PROMO_CREATION_LIMIT);      //判断是不是小于5000

        promoCreatedCount++;            //宣传阶段建立的小猫数量加1
        _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 {           //创建0代小猫,也只有COO能执行
        require(gen0CreatedCount < GEN0_CREATION_LIMIT);        //数量不能大于45000

        uint256 kittyId = _createKitty(0, 0, 0, _genes, address(this));     //创建小猫
        _approve(kittyId, saleAuction);     //将小猫上架

        saleAuction.createAuction(      //创建售卖的合约
            kittyId,
            _computeNextGen0Price(),
            0,
            GEN0_AUCTION_DURATION,
            address(this)
        );

        gen0CreatedCount++; //0代数量增加
    }

    /// @dev Computes the next gen0 auction starting price, given
    ///  the average of the past 5 prices + 50%.
    function _computeNextGen0Price() internal view returns (uint256) {      //计算下一个gen0拍卖起始价格,假设过去5个价格的平均值+50%。
        uint256 avePrice = saleAuction.averageGen0SalePrice();          //获取最近5个G0小猫的售价

        // Sanity check to ensure we don't overflow arithmetic
        require(avePrice == uint256(uint128(avePrice)));        //确保数不会太大

        uint256 nextPrice = avePrice + (avePrice / 2);      //在原价的基础上涨价%50

        // We never auction for less than starting price
        if (nextPrice < GEN0_STARTING_PRICE) {      //判断下次的价格和起拍价的大小关系,不能低于起拍价,如果低于则设置下次拍卖价格为起拍价,不便宜甩卖
            nextPrice = GEN0_STARTING_PRICE;
        }

        return nextPrice;
    }
}

contract KittyCore is KittyMinting

系统的主合约,通过该合约对其他合约进行调用从而实现整个程序的运行,分开各个功能部分到不同的合约上有助于系统部分功能的更新,而且也避免了主合约过于臃肿的问题。

contract KittyCore is KittyMinting {                //该合约为主合约,负责将其他合约联系起来实现整个系统的运行

    // This is the main CryptoKitties contract. In order to keep our code seperated into logical sections,
    // we've broken it up in two ways. First, we have several seperately-instantiated sibling contracts
    // that handle auctions and our super-top-secret genetic combination algorithm. The auctions are
    // seperate since their logic is somewhat complex and there's always a risk of subtle bugs. By keeping
    // them in their own contracts, we can upgrade them without disrupting the main contract that tracks
    // kitty ownership. The genetic combination algorithm is kept seperate so we can open-source all of
    // the rest of our code without making it _too_ easy for folks to figure out how the genetics work.
    // Don't worry, I'm sure someone will reverse engineer it soon enough!
    //
    // Secondly, we break the core contract into multiple files using inheritence, one for each major
    // facet of functionality of CK. This allows us to keep related code bundled together while still
    // avoiding a single giant file with everything in it. The breakdown is as follows:
    //
    //      - KittyBase: This is where we define the most fundamental code shared throughout the core
    //             functionality. This includes our main data storage, constants and data types, plus
    //             internal functions for managing these items.
    //
    //      - KittyAccessControl: This contract manages the various addresses and constraints for operations
    //             that can be executed only by specific roles. Namely CEO, CFO and COO.
    //
    //      - KittyOwnership: This provides the methods required for basic non-fungible token
    //             transactions, following the draft ERC-721 spec (https://github.com/ethereum/EIPs/issues/721).
    //
    //      - KittyBreeding: This file contains the methods necessary to breed cats together, including
    //             keeping track of siring offers, and relies on an external genetic combination contract.
    //
    //      - KittyAuctions: Here we have the public methods for auctioning or bidding on cats or siring
    //             services. The actual auction functionality is handled in two sibling contracts (one
    //             for sales and one for siring), while auction creation and bidding is mostly mediated
    //             through this facet of the core contract.
    //
    //      - KittyMinting: This final facet contains the functionality we use for creating new gen0 cats.
    //             We can make up to 5000 "promo" cats that can be given away (especially important when
    //             the community is new), and all others can only be created and then immediately put up
    //             for auction via an algorithmically determined starting price. Regardless of how they
    //             are created, there is a hard limit of 50k gen0 cats. After that, it's all up to the
    //             community to breed, breed, breed!

    // Set in case the core contract is broken and an upgrade is required
    address public newContractAddress;      //

    /// @notice Creates the main CryptoKitties smart contract instance.
    function KittyCore() public {       //构造函数,初始化状态
        // Starts paused.
        paused = true;      //初始为暂停状态

        // the creator of the contract is the initial CEO
        ceoAddress = msg.sender;            //CEO为合约创建者

        // the creator of the contract is also the initial COO
        cooAddress = msg.sender;    //COO也是合约创建者

        // start with the mythical kitten 0 - so we don't have generation-0 parent issues
        _createKitty(0, 0, 0, uint256(-1), address(0));     //创建一个kitty0
    }

    /// @dev Used to mark the smart contract as upgraded, in case there is a serious
    ///  breaking bug. This method does nothing but keep track of the new contract and
    ///  emit a message indicating that the new address is set. It's up to clients of this
    ///  contract to update to the new contract address in that case. (This contract will
    ///  be paused indefinitely if such an upgrade takes place.)
    /// @param _v2Address new address
    function setNewAddress(address _v2Address) external onlyCEO whenPaused {        //合约更新,设置新的地址,只有CEO可以在暂停合约的情况下执行
        // See README.md for updgrade plan
        newContractAddress = _v2Address;    
        ContractUpgrade(_v2Address);    
    }

    /// @notice No tipping!
    /// @dev Reject all Ether from being sent here, unless it's from one of the
    ///  two auction contracts. (Hopefully, we can prevent user accidents.)
    function() external payable {       //fallback函数
        require(
            msg.sender == address(saleAuction) ||       //判断调用者是不是售卖合约或者繁殖拍卖合约
            msg.sender == address(siringAuction)
        );
    }

    /// @notice Returns all the relevant information about a specific kitty.
    /// @param _id The ID of the kitty of interest.
    function getKitty(uint256 _id)              //根据id获取猫猫的信息
        external
        view
        returns (
        bool isGestating,
        bool isReady,
        uint256 cooldownIndex,
        uint256 nextActionAt,
        uint256 siringWithId,
        uint256 birthTime,
        uint256 matronId,
        uint256 sireId,
        uint256 generation,
        uint256 genes
    ) {
        Kitty storage kit = kitties[_id];

        // if this variable is 0 then it's not gestating
        isGestating = (kit.siringWithId != 0);
        isReady = (kit.cooldownEndBlock <= block.number);
        cooldownIndex = uint256(kit.cooldownIndex);
        nextActionAt = uint256(kit.cooldownEndBlock);
        siringWithId = uint256(kit.siringWithId);
        birthTime = uint256(kit.birthTime);
        matronId = uint256(kit.matronId);
        sireId = uint256(kit.sireId);
        generation = uint256(kit.generation);
        genes = kit.genes;
    }

    /// @dev Override unpause so it requires all external contract addresses
    ///  to be set before contract can be unpaused. Also, we can't have
    ///  newContractAddress set either, because then the contract was upgraded.
    /// @notice This is public rather than external so we can call super.unpause
    ///  without using an expensive CALL.
    function unpause() public onlyCEO whenPaused {      //解锁函数
        require(saleAuction != address(0));     //判断地址是不是0
        require(siringAuction != address(0));
        require(geneScience != address(0));
        require(newContractAddress == address(0));

        // Actually unpause the contract.
        super.unpause();
    }

    // @dev Allows the CFO to capture the balance available to the contract.
    function withdrawBalance() external onlyCFO {           //取走合约的余额,只有CFO能执行
        uint256 balance = this.balance;     //当前合约余额
        // Subtract all the currently pregnant kittens we have, plus 1 of margin.
        uint256 subtractFees = (pregnantKitties + 1) * autoBirthFee;        //要留下一部分怀孕的小猫生小小猫的费用

        if (balance > subtractFees) {   //如果余额大于生小小猫的费用,就提走剩下的
            cfoAddress.send(balance - subtractFees);
        }
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值