├── README.md ├── erc721.sol ├── zombieattack.sol ├── zombieownership.sol ├── zombiehelper.sol ├── zombiefactory.sol ├── zombiefeeding.sol ├── ownable.sol ├── safemath.sol ├── index.html └── cryptozombies_abi.js /README.md: -------------------------------------------------------------------------------- 1 | # Zombie-Game 2 | 3 | These all source code is based on https://cryptozombies.io/ 4 | 5 | This is good material for developers who want to learn Smart Contracts step by step. -------------------------------------------------------------------------------- /erc721.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0 <0.6.0; 2 | 3 | contract ERC721 { 4 | event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); 5 | event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); 6 | 7 | function balanceOf(address _owner) external view returns (uint256); 8 | function ownerOf(uint256 _tokenId) external view returns (address); 9 | function transferFrom(address _from, address _to, uint256 _tokenId) external payable; 10 | function approve(address _approved, uint256 _tokenId) external payable; 11 | } 12 | -------------------------------------------------------------------------------- /zombieattack.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0 <0.6.0; 2 | 3 | import "./zombiehelper.sol"; 4 | 5 | contract ZombieAttack is ZombieHelper { 6 | 7 | uint randNonce = 0; 8 | uint attackVictoryProbability = 70; 9 | 10 | function randMod(uint _modulus) internal returns(uint) { 11 | randNonce = randNonce.add(1); 12 | return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus; 13 | } 14 | 15 | function attack(uint _zombieId, uint _targetId) external onlyOwnerOf(_zombieId) { 16 | Zombie storage myZombie = zombies[_zombieId]; 17 | Zombie storage enemyZombie = zombies[_targetId]; 18 | uint rand = randMod(100); 19 | if (rand <= attackVictoryProbability) { 20 | myZombie.winCount = myZombie.winCount.add(1); 21 | myZombie.level = myZombie.level.add(1); 22 | enemyZombie.lossCount = enemyZombie.lossCount.add(1); 23 | feedAndMultiply(_zombieId, enemyZombie.dna, "zombie"); 24 | } else { 25 | myZombie.lossCount = myZombie.lossCount.add(1); 26 | enemyZombie.winCount = enemyZombie.winCount.add(1); 27 | _triggerCooldown(myZombie); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /zombieownership.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0 <0.6.0; 2 | 3 | import "./zombieattack.sol"; 4 | import "./erc721.sol"; 5 | import "./safemath.sol"; 6 | 7 | /// TODO: Replace this with natspec descriptions 8 | contract ZombieOwnership is ZombieAttack, ERC721 { 9 | 10 | using SafeMath for uint256; 11 | 12 | mapping (uint => address) zombieApprovals; 13 | 14 | function balanceOf(address _owner) external view returns (uint256) { 15 | return ownerZombieCount[_owner]; 16 | } 17 | 18 | function ownerOf(uint256 _tokenId) external view returns (address) { 19 | return zombieToOwner[_tokenId]; 20 | } 21 | 22 | function _transfer(address _from, address _to, uint256 _tokenId) private { 23 | ownerZombieCount[_to] = ownerZombieCount[_to].add(1); 24 | ownerZombieCount[msg.sender] = ownerZombieCount[msg.sender].sub(1); 25 | zombieToOwner[_tokenId] = _to; 26 | emit Transfer(_from, _to, _tokenId); 27 | } 28 | 29 | function transferFrom(address _from, address _to, uint256 _tokenId) external payable { 30 | require (zombieToOwner[_tokenId] == msg.sender || zombieApprovals[_tokenId] == msg.sender); 31 | _transfer(_from, _to, _tokenId); 32 | } 33 | 34 | function approve(address _approved, uint256 _tokenId) external payable onlyOwnerOf(_tokenId) { 35 | zombieApprovals[_tokenId] = _approved; 36 | emit Approval(msg.sender, _approved, _tokenId); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /zombiehelper.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0 <0.6.0; 2 | 3 | import "./zombiefeeding.sol"; 4 | 5 | contract ZombieHelper is ZombieFeeding { 6 | 7 | uint levelUpFee = 0.001 ether; 8 | 9 | modifier aboveLevel(uint _level, uint _zombieId) { 10 | require(zombies[_zombieId].level >= _level); 11 | _; 12 | } 13 | 14 | function withdraw() external onlyOwner { 15 | address _owner = owner(); 16 | _owner.transfer(address(this).balance); 17 | } 18 | 19 | function setLevelUpFee(uint _fee) external onlyOwner { 20 | levelUpFee = _fee; 21 | } 22 | 23 | function levelUp(uint _zombieId) external payable { 24 | require(msg.value == levelUpFee); 25 | zombies[_zombieId].level = zombies[_zombieId].level.add(1); 26 | } 27 | 28 | function changeName(uint _zombieId, string calldata _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) { 29 | zombies[_zombieId].name = _newName; 30 | } 31 | 32 | function changeDna(uint _zombieId, uint _newDna) external aboveLevel(20, _zombieId) onlyOwnerOf(_zombieId) { 33 | zombies[_zombieId].dna = _newDna; 34 | } 35 | 36 | function getZombiesByOwner(address _owner) external view returns(uint[] memory) { 37 | uint[] memory result = new uint[](ownerZombieCount[_owner]); 38 | uint counter = 0; 39 | for (uint i = 0; i < zombies.length; i++) { 40 | if (zombieToOwner[i] == _owner) { 41 | result[counter] = i; 42 | counter++; 43 | } 44 | } 45 | return result; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /zombiefactory.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0 <0.6.0; 2 | 3 | import "./ownable.sol"; 4 | import "./safemath.sol"; 5 | 6 | contract ZombieFactory is Ownable { 7 | 8 | using SafeMath for uint256; 9 | using SafeMath32 for uint32; 10 | using SafeMath16 for uint16; 11 | 12 | event NewZombie(uint zombieId, string name, uint dna); 13 | 14 | uint dnaDigits = 16; 15 | uint dnaModulus = 10 ** dnaDigits; 16 | uint cooldownTime = 1 days; 17 | 18 | struct Zombie { 19 | string name; 20 | uint dna; 21 | uint32 level; 22 | uint32 readyTime; 23 | uint16 winCount; 24 | uint16 lossCount; 25 | } 26 | 27 | Zombie[] public zombies; 28 | 29 | mapping (uint => address) public zombieToOwner; 30 | mapping (address => uint) ownerZombieCount; 31 | 32 | function _createZombie(string memory _name, uint _dna) internal { 33 | uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1; 34 | zombieToOwner[id] = msg.sender; 35 | ownerZombieCount[msg.sender] = ownerZombieCount[msg.sender].add(1); 36 | emit NewZombie(id, _name, _dna); 37 | } 38 | 39 | function _generateRandomDna(string memory _str) private view returns (uint) { 40 | uint rand = uint(keccak256(abi.encodePacked(_str))); 41 | return rand % dnaModulus; 42 | } 43 | 44 | function createRandomZombie(string memory _name) public { 45 | require(ownerZombieCount[msg.sender] == 0); 46 | uint randDna = _generateRandomDna(_name); 47 | randDna = randDna - randDna % 100; 48 | _createZombie(_name, randDna); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /zombiefeeding.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0 <0.6.0; 2 | 3 | import "./zombiefactory.sol"; 4 | 5 | contract KittyInterface { 6 | function getKitty(uint256 _id) external view returns ( 7 | bool isGestating, 8 | bool isReady, 9 | uint256 cooldownIndex, 10 | uint256 nextActionAt, 11 | uint256 siringWithId, 12 | uint256 birthTime, 13 | uint256 matronId, 14 | uint256 sireId, 15 | uint256 generation, 16 | uint256 genes 17 | ); 18 | } 19 | 20 | contract ZombieFeeding is ZombieFactory { 21 | 22 | KittyInterface kittyContract; 23 | 24 | modifier onlyOwnerOf(uint _zombieId) { 25 | require(msg.sender == zombieToOwner[_zombieId]); 26 | _; 27 | } 28 | 29 | function setKittyContractAddress(address _address) external onlyOwner { 30 | kittyContract = KittyInterface(_address); 31 | } 32 | 33 | function _triggerCooldown(Zombie storage _zombie) internal { 34 | _zombie.readyTime = uint32(now + cooldownTime); 35 | } 36 | 37 | function _isReady(Zombie storage _zombie) internal view returns (bool) { 38 | return (_zombie.readyTime <= now); 39 | } 40 | 41 | function feedAndMultiply(uint _zombieId, uint _targetDna, string memory _species) internal onlyOwnerOf(_zombieId) { 42 | Zombie storage myZombie = zombies[_zombieId]; 43 | require(_isReady(myZombie)); 44 | _targetDna = _targetDna % dnaModulus; 45 | uint newDna = (myZombie.dna + _targetDna) / 2; 46 | if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) { 47 | newDna = newDna - newDna % 100 + 99; 48 | } 49 | _createZombie("NoName", newDna); 50 | _triggerCooldown(myZombie); 51 | } 52 | 53 | function feedOnKitty(uint _zombieId, uint _kittyId) public { 54 | uint kittyDna; 55 | (,,,,,,,,,kittyDna) = kittyContract.getKitty(_kittyId); 56 | feedAndMultiply(_zombieId, kittyDna, "kitty"); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /ownable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0 <0.6.0; 2 | 3 | /** 4 | * @title Ownable 5 | * @dev The Ownable contract has an owner address, and provides basic authorization control 6 | * functions, this simplifies the implementation of "user permissions". 7 | */ 8 | contract Ownable { 9 | address private _owner; 10 | 11 | event OwnershipTransferred( 12 | address indexed previousOwner, 13 | address indexed newOwner 14 | ); 15 | 16 | /** 17 | * @dev The Ownable constructor sets the original `owner` of the contract to the sender 18 | * account. 19 | */ 20 | constructor() internal { 21 | _owner = msg.sender; 22 | emit OwnershipTransferred(address(0), _owner); 23 | } 24 | 25 | /** 26 | * @return the address of the owner. 27 | */ 28 | function owner() public view returns(address) { 29 | return _owner; 30 | } 31 | 32 | /** 33 | * @dev Throws if called by any account other than the owner. 34 | */ 35 | modifier onlyOwner() { 36 | require(isOwner()); 37 | _; 38 | } 39 | 40 | /** 41 | * @return true if `msg.sender` is the owner of the contract. 42 | */ 43 | function isOwner() public view returns(bool) { 44 | return msg.sender == _owner; 45 | } 46 | 47 | /** 48 | * @dev Allows the current owner to relinquish control of the contract. 49 | * @notice Renouncing to ownership will leave the contract without an owner. 50 | * It will not be possible to call the functions with the `onlyOwner` 51 | * modifier anymore. 52 | */ 53 | function renounceOwnership() public onlyOwner { 54 | emit OwnershipTransferred(_owner, address(0)); 55 | _owner = address(0); 56 | } 57 | 58 | /** 59 | * @dev Allows the current owner to transfer control of the contract to a newOwner. 60 | * @param newOwner The address to transfer ownership to. 61 | */ 62 | function transferOwnership(address newOwner) public onlyOwner { 63 | _transferOwnership(newOwner); 64 | } 65 | 66 | /** 67 | * @dev Transfers control of the contract to a newOwner. 68 | * @param newOwner The address to transfer ownership to. 69 | */ 70 | function _transferOwnership(address newOwner) internal { 71 | require(newOwner != address(0)); 72 | emit OwnershipTransferred(_owner, newOwner); 73 | _owner = newOwner; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /safemath.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0 <0.6.0; 2 | 3 | /** 4 | * @title SafeMath 5 | * @dev Math operations with safety checks that throw on error 6 | */ 7 | library SafeMath { 8 | 9 | /** 10 | * @dev Multiplies two numbers, throws on overflow. 11 | */ 12 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 13 | if (a == 0) { 14 | return 0; 15 | } 16 | uint256 c = a * b; 17 | assert(c / a == b); 18 | return c; 19 | } 20 | 21 | /** 22 | * @dev Integer division of two numbers, truncating the quotient. 23 | */ 24 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 25 | // assert(b > 0); // Solidity automatically throws when dividing by 0 26 | uint256 c = a / b; 27 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 28 | return c; 29 | } 30 | 31 | /** 32 | * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). 33 | */ 34 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 35 | assert(b <= a); 36 | return a - b; 37 | } 38 | 39 | /** 40 | * @dev Adds two numbers, throws on overflow. 41 | */ 42 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 43 | uint256 c = a + b; 44 | assert(c >= a); 45 | return c; 46 | } 47 | } 48 | 49 | /** 50 | * @title SafeMath32 51 | * @dev SafeMath library implemented for uint32 52 | */ 53 | library SafeMath32 { 54 | 55 | function mul(uint32 a, uint32 b) internal pure returns (uint32) { 56 | if (a == 0) { 57 | return 0; 58 | } 59 | uint32 c = a * b; 60 | assert(c / a == b); 61 | return c; 62 | } 63 | 64 | function div(uint32 a, uint32 b) internal pure returns (uint32) { 65 | // assert(b > 0); // Solidity automatically throws when dividing by 0 66 | uint32 c = a / b; 67 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 68 | return c; 69 | } 70 | 71 | function sub(uint32 a, uint32 b) internal pure returns (uint32) { 72 | assert(b <= a); 73 | return a - b; 74 | } 75 | 76 | function add(uint32 a, uint32 b) internal pure returns (uint32) { 77 | uint32 c = a + b; 78 | assert(c >= a); 79 | return c; 80 | } 81 | } 82 | 83 | /** 84 | * @title SafeMath16 85 | * @dev SafeMath library implemented for uint16 86 | */ 87 | library SafeMath16 { 88 | 89 | function mul(uint16 a, uint16 b) internal pure returns (uint16) { 90 | if (a == 0) { 91 | return 0; 92 | } 93 | uint16 c = a * b; 94 | assert(c / a == b); 95 | return c; 96 | } 97 | 98 | function div(uint16 a, uint16 b) internal pure returns (uint16) { 99 | // assert(b > 0); // Solidity automatically throws when dividing by 0 100 | uint16 c = a / b; 101 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 102 | return c; 103 | } 104 | 105 | function sub(uint16 a, uint16 b) internal pure returns (uint16) { 106 | assert(b <= a); 107 | return a - b; 108 | } 109 | 110 | function add(uint16 a, uint16 b) internal pure returns (uint16) { 111 | uint16 c = a + b; 112 | assert(c >= a); 113 | return c; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |