从头写一个solidity智能合约(三)代码实现

首先创建一个pet_token.sol文件,作为入口合约


pragma solidity ^0.4.4;
import "./pet_factory.sol";
import "./ecr712.sol";

// PET 宠物 version - 1.0
contract PetToken is PetFactory, ERC721{
    
    string public name = "Pet Token";  // token 名称
 
    string public symbol = "PET";    // token 简称
    
    uint8 public decimals = 0; //token小数点后几位,PET币不可分割,所以小数点后没有位
   
    mapping (address => mapping (address => uint256)) allowed;  // 地址 => ( 允许转账的地址 => 准许转账数量 )映射
    
    
    mapping (uint => address) petApprovals; //预授权转账地址
    
    
    // 遵守 ECR712协议
    
    // 获取某个账户的余额
    function balanceOf(address _owner) public view returns (uint256 _balance) {
        return balances[_owner];
    }
    
    // 获取某个token的地址
    function ownerOf(uint256 _tokenId) public view returns (address _owner) {
        return petToOwner[_tokenId];
    }  
    
    // 转账私有函数
    function _transfer(address _from, address _to, uint256 _tokenId) private {
        balances[_to] ++;
        balances[msg.sender] --;
        petToOwner[_tokenId] = _to;
        emit Transfer(_from, _to, _tokenId);
    }

    //转账
    function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) {
        _transfer(msg.sender, _to, _tokenId);
    }
    
    // 预授权
    function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) {
        petApprovals[_tokenId] = _to;
        emit Approval(msg.sender, _to, _tokenId);
    }
    
    // 行使授权
    function takeOwnership(uint256 _tokenId) public {
        require(petApprovals[_tokenId] == msg.sender);
        address owner = ownerOf(_tokenId);
        _transfer(owner, msg.sender, _tokenId);
    }
}
    

再创建一个pet_factory.sol

pragma solidity ^0.4.4;

import "github.com/Arachnid/solidity-stringutils/strings.sol";

contract PetFactory{
    
    using strings for *;

    event NewPet(uint petId, string name, uint dna, address master); // 新生成宠物事件
    event NewFeed(uint petId, address from, string message, uint32 time); // 新喂食事件
    event NewPeron(address person, string name);
    
    uint dnaModulus = 10 ** 16; // DNA位数 16位整型
    uint8 maxLevel = 99; // 宠物最大等级
    uint32 cooldownTime = 2 minutes; // 下次可捕获宠物间隔时间
    uint32 feedCooldownTime = 20 seconds; // 下次可喂食的间隔时间
    uint private randNonce = 0;
    
    // 宠物结构体
    struct Pet {
        string name; // 宠物名
        uint dna; // 宠物dna
        uint8 level; // 宠物等级 
        uint32 createTime; // 宠物创建时间
        uint32 readyTime; // 宠物喂食冻结时间
        uint feedCount; //喂养次数
    }
    
    // 用户(宠物主人)
    struct Person {
        string name; // 用户名
        uint32 readyTime; // 下次可捕获宠物时间
    }
    
    Pet[] public pets; // 所有宠物的数组
    
    //喂养记录结构体
    struct Feed {
        address from; // 喂养人的地址
        string message; //留言
        uint32 feedTime; //喂养时间
        uint8 levelCount;  //此次喂食的升级等级
    }
 
    mapping (uint => address) public petToOwner; // 宠物Id => 宠物主人地址的映射
    mapping (address => Person) public peoples;  // 地址 => 人的映射
    mapping (address => uint256) public balances;  // 地址 => token余额(拥有宠物数量)的映射
    mapping (uint => mapping(uint => Feed)) public myFeeds; // 宠物id => (喂食记录自增id,非喂食id => 喂食记录结构体)
    
    modifier onlyOwnerOf(uint _tokenId) {
        require(msg.sender == petToOwner[_tokenId]);
        _;
    }
    
    // 创建一个小宠物
    function _createPet(string _name, uint _dna, uint8 _level) internal {
        if(balances[msg.sender] == 0 && utilCompareInternal(peoples[msg.sender].name, "" ) ) {
            // 第一次创建宠物的情况下, 如果没有创建用户信息,则自动创建
            updateUser("");
        }
        uint id = pets.push(Pet(_name, _dna,_level, uint32(now), 0, 0)) - 1;  // 宠物数组里生成一个, id为宠物Id 默认一级
        petToOwner[id] = msg.sender; //宠物认主
        balances[msg.sender] ++; // 主人宠物数量 + 1
        emit NewPet(id, _name, _dna, msg.sender); // 发送事件
    }
    
    // 初始化一个用户或者更新用户名
    function updateUser(string _name) public {
        if(utilCompareInternal(peoples[msg.sender].name, "" ) ) {
            emit NewPeron(msg.sender, _name);
        } 
        string memory defalutName = "用户".toSlice().concat(toString(now ).toSlice()); // 如果没有传入name参数,则默认一个用户名
        peoples[msg.sender].name = utilCompareInternal(_name, "") ? defalutName : _name;
    }
    
    // 捕获宠物函数
    function capture(string _name) public returns(string){
        require(balances[msg.sender] == 0 || now >= peoples[msg.sender].readyTime);  // 保证这是第一次捕猎或者过了冷却时间
        uint randDna = _generateRandomDna(_name);
        randDna = randDna - randDna % 100;   //生成一个随机dna
        string memory defalutName = "宠物".toSlice().concat(toString(pets.length + 1).toSlice()); //如果没有传入宠物名称,则生成一个默认的宠物名
        _createPet(utilCompareInternal(_name, "") ? defalutName : _name, randDna, 1);
        peoples[msg.sender].readyTime = uint32(now + cooldownTime); //更新宠物冷却时间 
    }
    
    // 定制一个宠物
    function customPet(string _name, uint _dna) external payable {
        require(msg.value >= 0.001 ether);
        string memory defalutName = "宠物".toSlice().concat(toString(pets.length + 1).toSlice()); //如果没有传入宠物名称,则生成一个默认的宠物名
        uint dna;
        if(_dna < 1000000000) {  //输入的dna一定是个十位数以上的,否则新生成一个16位的dna
           dna = _generateRandomDna(defalutName);
        }else{
            dna =  _dna % dnaModulus;
        }
        _createPet(utilCompareInternal(_name, "") ? defalutName : _name, dna, uint8(20));
    }
    
    // 宠物喂养 _id => 宠物id, _message => 留言
    function feed(uint _id, string _message) public {
        require( now >= pets[_id].readyTime);
         uint8 rand = uint8(randMod(5)); // 1~5随机数
        //喂养后宠物升级 随机升个1到5级
        if(_upgrade(_id, rand)) {
            myFeeds[_id][pets[_id].feedCount] = Feed(msg.sender, _message, uint32(now), rand); // 将喂食记录的id指向给对应的宠物
            pets[_id].feedCount ++; //这个宠物喂养次数+1
            pets[_id].readyTime = uint32(now + feedCooldownTime); // 更新宠物下次可喂养时间 
            emit NewFeed(_id, msg.sender, _message, uint32(now));
            // 20级以上宠物喂食后 有30%的概率生成一个新宠物
            if( pets[_id].level >= 20) {
                if(randMod(100) <= 30) { 
                    string memory defalutName = "喂食生成宠物"; //如果没有传入宠物名称,则生成一个默认的宠物名
                    uint randDna = _generateRandomDna(defalutName);
                    randDna = randDna - randDna % 100;   //生成一个随机dna
                    _createPet(defalutName, randDna, uint8(1));
                }
            }
        }
    }
    
    // 宠物升级 
    // _id => 宠物id  _levelCount 升级级数
    function _upgrade(uint _id, uint8 _levelCount ) internal returns (bool) {
        if(pets[_id].level + _levelCount <= maxLevel) {  // 升级后的等级要小于最大等级
            pets[_id].level += _levelCount;
            return true;
        } 
        return false;
    }
    
    // 比对俩个字符串是否相等
    function utilCompareInternal(string a, string b) internal pure returns (bool) {
        if (bytes(a).length != bytes(b).length) {
            return false;
        }
        for (uint i = 0; i < bytes(a).length; i ++) {
            if(bytes(a)[i] != bytes(b)[i]) {
                return false;
            }
        }
        return true;
    }
    
    // 讲一个整数型转发为string型
    function toString(uint i) pure internal returns (string) {
      if (i == 0) return "0";
       uint j = i;
       uint length;
       while (j != 0){
           length++;
           j /= 10;
       }
       bytes memory bstr = new bytes(length);
       uint k = length - 1;
       while (i != 0){
           bstr[k--] = byte(48 + i % 10);
           i /= 10;
       }
       return string(bstr); 
    }
    
    // 创建一个随机Dna
    function _generateRandomDna(string _str) private view returns (uint) {
        uint rand = uint(keccak256(bytes(_str.toSlice().concat(toString(now).toSlice()))));
        return rand % dnaModulus;
    }
    
    //生成一个随机数
    function randMod(uint _modulus) internal returns(uint num) {
        randNonce++;
        num = uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus;
        if(num == 0) {
            num = 1;
        } 
    }

}

此合约符合ECR712标准,再创建一个ecr712.sol文件

pragma solidity ^0.4.4;
contract ERC721 {
  event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);
  event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId);

  function balanceOf(address _owner) public view returns (uint256 _balance);
  function ownerOf(uint256 _tokenId) public view returns (address _owner);
  function transfer(address _to, uint256 _tokenId) public;
  function approve(address _to, uint256 _tokenId) public;
  function takeOwnership(uint256 _tokenId) public;
}

以上即为合约的代码实现部分

发布了4 篇原创文章 · 获赞 5 · 访问量 6688

猜你喜欢

转载自blog.csdn.net/qq_30113287/article/details/103955671