上一篇讲解以太猫的一些基础合约,包含权限控制和ERC721函数定义合约。本篇将重点介绍以太猫的基础数据合约和ERC721代币实现合约。我们先看以太猫基础数据合约。

以太猫基础数据合约

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;          // 母亲的IDuint32 sireId;            // 父亲的IDuint32 siringWithId;      // 如果正在繁殖期那么就是当前交配对象的ID,否则为0uint16 cooldownIndex;     // 繁殖冷却时间uint16 generation;        // 猫的代数  max(matron.generation, sire.generation) + 1)}// 数组,cooldownIndex 对应的冷却时间,// 随着猫的代数和生育次数的增加,猫进行交配的冷却时间也会逐渐增加// 最大冷却时间不会超过7天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)];// 生成一个区块的秒数uint256 public secondsPerBlock = 15;// 保存所有的喵的IDKitty[] kitties;  // 所有猫的ID对应地址的映射mapping (uint256 => address) public kittyIndexToOwner;  // 用户地址对应token数的映射mapping (address => uint256) ownershipTokenCount;  // 授权 ,把uint256(猫id)  授权给address(用户) 交易 ,先授权,然后才能交易mapping (uint256 => address) public kittyIndexToApproved; // 授权,把uint256(猫id)  授权给address(用户)交配,先授权,然后才能交配mapping (uint256 => address) public sireAllowedToAddress;  // 拍卖合约的地址,处理用户之间的交易和每隔15分钟系统生成的gen0代猫SaleClockAuction public saleAuction;  // 交配的合约地址,和上面拍卖的不同因为两者的处理方式不同SiringClockAuction public siringAuction; // 交易,把 _from 拥有的_tokenId 猫交易给 _tofunction _transfer(address _from, address _to, uint256 _tokenId) internal {ownershipTokenCount[_to]++;           // _to 用户拥有猫是数量 加 1 kittyIndexToOwner[_tokenId] = _to;    // _tokenId 猫的所有者 更改为 _toif (_from != address(0)) {            // 判断 _from 地址是否为空ownershipTokenCount[_from]--;     // _from 用户拥有猫是数量 减 1delete sireAllowedToAddress[_tokenId];   // 删除猫的出售信息delete kittyIndexToApproved[_tokenId];   // 删除猫的授权信息}Transfer(_from, _to, _tokenId);  // 触发交易事件}// 创建猫function _createKitty(uint256 _matronId,  // 母亲的IDuint256 _sireId,    // 父亲的ID uint256 _generation,// 猫的代数uint256 _genes,     // 猫的基因address _owner      // 猫的拥有者)internalreturns (uint){// 为了限制猫的数量  最多2^32次方只猫require(_matronId == uint256(uint32(_matronId)));require(_sireId == uint256(uint32(_sireId)));// 为了限制猫的代数 最多2^16 require(_generation == uint256(uint16(_generation)));// 繁殖冷却时间最多是 7天    cooldowns[13] = 7天uint16 cooldownIndex = uint16(_generation / 2);if (cooldownIndex > 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)});// 放入区块链(kitties)中,返回新生成的猫IDuint256 newKittenId = kitties.push(_kitty) - 1; // 判断,猫的ID不能大于2^32require(newKittenId == uint256(uint32(newKittenId)));// 触发Birth事件,发送给前端监听Birth(_owner,newKittenId,uint256(_kitty.matronId),uint256(_kitty.sireId),_kitty.genes);// 把猫 分配给 拥有者_owner_transfer(0, _owner, newKittenId);return newKittenId;}// 修改生成区块的秒数,只有 CEO CFO COO才能执行// 权限控制见下面function setSecondsPerBlock(uint256 secs) external onlyCLevel {require(secs < cooldowns[0]);secondsPerBlock = secs;}
}

ERC721合约函数的实现

contract KittyOwnership is KittyBase, ERC721 {string public constant name = "CryptoKitties";   // 代币的名字string public constant symbol = "CK";            // 代币的缩写ERC721Metadata public erc721Metadata;            // ERC721元数据bytes4 constant InterfaceSignature_ERC165 =bytes4(keccak256('supportsInterface(bytes4)'));   //验证是否支持 ERC165协议bytes4 constant InterfaceSignature_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)'));   //验证是否支持 ERC721协议// 实现ERC165 协议,作用是外部账户验证我们的合约是否实现我们想要的函数接口function supportsInterface(bytes4 _interfaceID) external view returns (bool){return ((_interfaceID == InterfaceSignature_ERC165) || (_interfaceID == InterfaceSignature_ERC721));}// 设置代币元数据,只有CEO才能执行function setMetadataAddress(address _contractAddress) public onlyCEO {erc721Metadata = ERC721Metadata(_contractAddress);}// 判断猫的主人是否为传递进来的地址 _claimantfunction _owns(address _claimant, uint256 _tokenId) internal view returns (bool) {return kittyIndexToOwner[_tokenId] == _claimant;}// 判断 _claimant 地址是否已经有了 猫_tokenId 的授权function _approvedFor(address _claimant, uint256 _tokenId) internal view returns (bool) {return kittyIndexToApproved[_tokenId] == _claimant;}// 把_tokenId授权_approved地址// 地址可以是买卖交易所合约地址 ,即把 _tokenId猫授权给买卖交易所进行拍卖function _approve(uint256 _tokenId, address _approved) internal {kittyIndexToApproved[_tokenId] = _approved;}// 返回地址(主人) 有多少只猫(代币)function balanceOf(address _owner) public view returns (uint256 count) {return ownershipTokenCount[_owner];}// 转移代币 ,只有当程序 notPaused 没有暂停时才能使用function transfer(address _to,uint256 _tokenId) external whenNotPaused{require(_to != address(0));    // 安全检查,_to 不能为0require(_to != address(this)); // 转账的地址不能为当前账户require(_to != address(saleAuction));    // 转账的地址不能为当前拍卖的合约地址,定义在 KittyBase 合约中require(_to != address(siringAuction));  // 转账的地址不能为当前交配的合约地址,定义在 KittyBase 合约中require(_owns(msg.sender, _tokenId));    // 当前的合约的调用者 是否 拥有这只猫_transfer(msg.sender, _to, _tokenId);    // 转账}// 授权代币,只有当程序 notPaused 没有暂停时才能使用function approve(address _to,uint256 _tokenId) external whenNotPaused{require(_owns(msg.sender, _tokenId));  // 只有拥有者才能授权_approve(_tokenId, _to);               // 函数调用,把_tokenId猫授权给_toApproval(msg.sender, _to, _tokenId);   // 触发授权事件}// 将  _from用户  的_tokenId猫  转移给  _to用户function transferFrom(address _from, address _to, uint256 _tokenId) external whenNotPaused{require(_to != address(0));     // 安全检查,判断_to 地址是否合法require(_to != address(this));  // 转账的地址不能为当前账户 require(_approvedFor(msg.sender, _tokenId));   // 检查权限,检查msg.sender是否获得了授权转移_tokenId猫require(_owns(_from, _tokenId));               // 检查_from 是否拥有 _tokenId猫_transfer(_from, _to, _tokenId);               // 调用函数_transfer 进行转移}// 查询当前猫的总数function totalSupply() public view returns (uint) {return kitties.length - 1;}// 返回_tokenId猫的所有者function ownerOf(uint256 _tokenId) external view returns (address owner){owner = kittyIndexToOwner[_tokenId];require(owner != address(0));}// 返回_owner所有者拥有的所有猫的idfunction tokensOfOwner(address _owner) external view returns(uint256[] ownerTokens) {// 查询_owner 有几只猫uint256 tokenCount = balanceOf(_owner);if (tokenCount == 0) {return new uint256[](0);} else {// 初始化一个长度为tokenCount的返回值resultuint256[] memory result = new uint256[](tokenCount);uint256 totalCats = totalSupply();uint256 resultIndex = 0;// 猫的id 从 1 递增到 totalCats uint256 catId;for (catId = 1; catId <= totalCats; catId++) {if (kittyIndexToOwner[catId] == _owner) {result[resultIndex] = catId;resultIndex++;}}return result;}}// 拷贝方法,Ref: https://github.com/Arachnid/solidity-stringutils/blob/2f6ca9accb48ae14c66f1437ec50ed19a0616f78/strings.solfunction _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))}}// 将_rawBytes中长度为_stringLength 转成string 并返回,https://github.com/Arachnid/solidity-stringutils/blob/2f6ca9accb48ae14c66f1437ec50ed19a0616f78/strings.solfunction _toString(bytes32[4] _rawBytes, uint256 _stringLength) private view returns (string) {var outputString = new string(_stringLength);uint256 outputPtr;uint256 bytesPtr;assembly {outputPtr := add(outputString, 32)bytesPtr := _rawBytes}_memcpy(outputPtr, bytesPtr, _stringLength);return outputString;}// 返回指向该元数据包的元数据的URIfunction tokenMetadata(uint256 _tokenId, string _preferredTransport) external view returns (string infoUrl) {require(erc721Metadata != address(0));bytes32[4] memory buffer;uint256 count;(buffer, count) = erc721Metadata.getMetadata(_tokenId, _preferredTransport);return _toString(buffer, count);}
}

ERC721Metadata合约

contract ERC721Metadata {/// @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;}}
}
在 KittyOwnership  合约中 tokenMetadata的实现调用该合约的 getMetadata 接口,暂不清楚调用这个接口的左右,待后续弄清楚再做说明。

以太猫合约之数据合约分析(二)相关推荐

  1. 数据包络分析-二阶段网络带feedback(第二篇)

    数据包络分析-二阶段网络带feedback(第二篇) 模型示意图 第一点:投入分配 第二点:只需要用一个 C h a r n e s C o o p e r Charnes\;Cooper Charn ...

  2. 数据包络分析--二阶段网络(考虑各阶段的公平性)

    DEA-关注公平的两阶段DEA模型:建模和计算方面 文献介绍 二阶段网络示意图 基础知识--合作和非合作模式 非合作模式(Non-cooperative mode) subDMU1dominatest ...

  3. 以太猫合约之基础合约分析(一)

    通过https://etherscan.io/查看部署在以太坊主链上的ERC721合约,排在第一位是代币名为CryptoKitties (CK)的合约,其合约地址为:0x06012c8cf97bead ...

  4. 以太猫游戏主合约(六)

    通过前述5篇博文的分析,分别介绍了以太猫的基础数据,权限控制,生产,拍卖,交易等相关合约代码分析,今天将介绍一下,以太猫游戏开始,宣传猫和一代猫的生成过程以及该休息的主合约. 宣传猫&一代猫 ...

  5. 3小时越洋电话,以太猫创始人Benny Giang首次向中国媒体全面透露以太猫的那些事(含独家原型手稿) | 人物志...

    一只猫把区块链游戏推上巅峰,在链圈路人皆知.一只只独一无二的小猫,凭借可爱.蠢萌的造型,一次次的刷新着成交的记录.在国内,大小公司布局区块链,养宠成为了「上链」的第一步,十二生肖都不够用了. 作为区块 ...

  6. Ethereum-ERC721智能合约和Dapp实践--以太猫CryptoKitties的简单实现

    一.概述 二.UI 三.设计目标 四.游戏系统设计 4.1 交易系统 4.1.1 帐号 4.1.2 产品 4.1.3 买卖交易 4.2 繁育系统 4.3 对战系统 4.4 喂养系统 4.5 升级系统 ...

  7. ENS最新合约源码分析二

    ENS(以太坊域名服务)智能合约源码分析二 0.简介 ​ 本次分享直接使用线上实际注册流程来分析最新注册以太坊域名的相关代码.本次主要分析最新的关于普通域名注册合约和普通域名迁移合约,短域名竞拍合约不 ...

  8. 区块链入门文章二《以太坊:下一代智能合约和去中心化应用平台》

    以太坊:下一代智能合约和去中心化应用平台 以太坊基金会 著 李志阔(网名:面神护法) 赵海涛 焦锋 译 中本聪2009年发明的比特币经常被视作货币和通货领域内一次激进的发展,这种激进首先表现为一种没有 ...

  9. 数据:以太坊2.0存款合约新增9.4万ETH

    据欧科云链OKLink数据显示,截至上午10时,以太坊2.0存款合约地址已收到178.88万ETH,近24小时新增9.4万ETH. 以太坊24h链上活跃地址数逾51.18万,环比上升1.76%:链上交 ...

最新文章

  1. 「深入浅出」了解语音识别的技术原理和应用价值?
  2. “TypeError: list indices must be integers or slices, not str”有关报错解决方案
  3. 转wordpress小工具制作前台后台全解析
  4. 8个前沿的 HTML5 CSS3 效果【附源码下载】
  5. MapReduce程序的优化
  6. 兼容IE和FF的JS HTMLEncode和HTMLDecode的完整实例[转]
  7. Boost库之function的使用
  8. C++-string常用函数整理(建议收藏)
  9. 自学python考哪些证书-学Python能挣多少钱?哪些人适合学Python?
  10. 【RLchina第五讲】Control as Inference
  11. Callnbsp;tonbsp;undefinednbsp;functionnbsp;mssql_connect()错误解决
  12. Cocos Creator | 碰撞检测优化-四叉树
  13. myql GROU_CONCAT 与FIND_IN_SET查询结果为空问题解决
  14. u盘启动计算机的几种方式,U盘各种启动模式方法介绍 六种U盘启动模式
  15. 设置来电铃声、卡2来电铃声、短信铃声、提示铃声、闹铃铃声
  16. 做完电商直播后,怎么做直播复盘?
  17. Photoshop设计精讲精练笔记(二)
  18. Lipschitz 条件
  19. 基于SpringBoot+EasyExcel+vue3实现excel表格的导入和导出
  20. HCNR200和HCNR201在电机驱动和电流回路中的应用

热门文章

  1. Qt获取本机IP、MAC地址、子网掩码、网卡名等函数设计
  2. 正则 验证密码(数字和英文同时存在)
  3. 智慧地铁内涵、特征与定义
  4. vue 引入 自定义字体文件
  5. HDU4262 Juggler 线段树
  6. linux 列转行函数,GP行转列、列转行函数
  7. [TYVJ] P1423 GF和猫咪的玩具
  8. Python循环结构基础-continu/break
  9. 必备小工具百度翻译桌面版,瞬时翻译
  10. html表盘的代码,表盘.html