erc721.sol
pragma solidity ^0.4.25;
contract ERC721 {
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
function balanceOf(address _owner) external view returns (uint256);
function ownerOf(uint256 _tokenId) external view returns (address);
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
function approve(address _approved, uint256 _tokenId) external payable;
}
safemath.sol
pragma solidity ^0.4.25;
library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
assert(c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
library SafeMath32 {
function mul(uint32 a, uint32 b) internal pure returns (uint32) {
if (a == 0) {
return 0;
}
uint32 c = a * b;
assert(c / a == b);
return c;
}
function div(uint32 a, uint32 b) internal pure returns (uint32) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint32 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint32 a, uint32 b) internal pure returns (uint32) {
assert(b <= a);
return a - b;
}
function add(uint32 a, uint32 b) internal pure returns (uint32) {
uint32 c = a + b;
assert(c >= a);
return c;
}
}
library SafeMath16 {
function mul(uint16 a, uint16 b) internal pure returns (uint16) {
if (a == 0) {
return 0;
}
uint16 c = a * b;
assert(c / a == b);
return c;
}
function div(uint16 a, uint16 b) internal pure returns (uint16) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint16 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint16 a, uint16 b) internal pure returns (uint16) {
assert(b <= a);
return a - b;
}
function add(uint16 a, uint16 b) internal pure returns (uint16) {
uint16 c = a + b;
assert(c >= a);
return c;
}
}
zombieownership.sol
pragma solidity ^0.4.25;
import "./zombieattack.sol";
import "./erc721.sol";
import "./safemath.sol";
contract ZombieOwnership is ZombieAttack, ERC721 {
using SafeMath for uint256;
mapping (uint => address) zombieApprovals;
function balanceOf(address _owner) external view returns (uint256) {
return ownerZombieCount[_owner];
}
function ownerOf(uint256 _tokenId) external view returns (address) {
return zombieToOwner[_tokenId];
}
function _transfer(address _from, address _to, uint256 _tokenId) private {
ownerZombieCount[_to] = ownerZombieCount[_to].add(1);
ownerZombieCount[msg.sender] = ownerZombieCount[msg.sender].sub(1);
zombieToOwner[_tokenId] = _to;
emit Transfer(_from, _to, _tokenId);
}
function transferFrom(address _from, address _to, uint256 _tokenId) external payable {
require (zombieToOwner[_tokenId] == msg.sender || zombieApprovals[_tokenId] == msg.sender);
_transfer(_from, _to, _tokenId);
}
function approve(address _approved, uint256 _tokenId) external payable onlyOwnerOf(_tokenId) {
zombieApprovals[_tokenId] = _approved;
emit Approval(msg.sender, _approved, _tokenId);
}
}
ownable.sol
pragma solidity ^0.4.25;
contract Ownable {
address private _owner;
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
constructor() internal {
_owner = msg.sender;
emit OwnershipTransferred(address(0), _owner);
}
function owner() public view returns(address) {
return _owner;
}
modifier onlyOwner() {
require(isOwner());
_;
}
function isOwner() public view returns(bool) {
return msg.sender == _owner;
}
function renounceOwnership() public onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
function transferOwnership(address newOwner) public onlyOwner {
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal {
require(newOwner != address(0));
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
zombiefeeding.sol
pragma solidity ^0.4.25;
import "./zombiefactory.sol";
contract KittyInterface {
function getKitty(uint256 _id) external view returns (
bool isGestating,
bool isReady,
uint256 cooldownIndex,
uint256 nextActionAt,
uint256 siringWithId,
uint256 birthTime,
uint256 matronId,
uint256 sireId,
uint256 generation,
uint256 genes
);
}
contract ZombieFeeding is ZombieFactory {
KittyInterface kittyContract;
modifier onlyOwnerOf(uint _zombieId) {
require(msg.sender == zombieToOwner[_zombieId]);
_;
}
function setKittyContractAddress(address _address) external onlyOwner {
kittyContract = KittyInterface(_address);
}
function _triggerCooldown(Zombie storage _zombie) internal {
_zombie.readyTime = uint32(now + cooldownTime);
}
function _isReady(Zombie storage _zombie) internal view returns (bool) {
return (_zombie.readyTime <= now);
}
function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal onlyOwnerOf(_zombieId) {
Zombie storage myZombie = zombies[_zombieId];
require(_isReady(myZombie));
_targetDna = _targetDna % dnaModulus;
uint newDna = (myZombie.dna + _targetDna) / 2;
if (keccak256(abi.encodePacked(_species)) == keccak256(abi.encodePacked("kitty"))) {
newDna = newDna - newDna % 100 + 99;
}
_createZombie("NoName", newDna);
_triggerCooldown(myZombie);
}
function feedOnKitty(uint _zombieId, uint _kittyId) public {
uint kittyDna;
(,,,,,,,,,kittyDna) = kittyContract.getKitty(_kittyId);
feedAndMultiply(_zombieId, kittyDna, "kitty");
}
}
zombiehelper.sol
pragma solidity ^0.4.25
import "./zombiefeeding.sol"
contract ZombieHelper is ZombieFeeding {
uint levelUpFee = 0.001 ether
modifier aboveLevel(uint _level, uint _zombieId) {
require(zombies[_zombieId].level >= _level)
_
}
function withdraw() external onlyOwner {
address _owner = owner()
_owner.transfer(address(this).balance)
}
function setLevelUpFee(uint _fee) external onlyOwner {
levelUpFee = _fee
}
function levelUp(uint _zombieId) external payable {
require(msg.value == levelUpFee)
zombies[_zombieId].level = zombies[_zombieId].level.add(1)
}
function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) onlyOwnerOf(_zombieId) {
zombies[_zombieId].name = _newName
}
function changeDna(uint _zombieId, uint _newDna) external aboveLevel(20, _zombieId) onlyOwnerOf(_zombieId) {
zombies[_zombieId].dna = _newDna
}
function getZombiesByOwner(address _owner) external view returns(uint[]) {
uint[] memory result = new uint[](ownerZombieCount[_owner])
uint counter = 0
for (uint i = 0
if (zombieToOwner[i] == _owner) {
result[counter] = i
counter++
}
}
return result
}
}
zombiefactory.sol
pragma solidity ^0.4.25
import "./ownable.sol"
import "./safemath.sol"
contract ZombieFactory is Ownable {
using SafeMath for uint256
using SafeMath32 for uint32
using SafeMath16 for uint16
event NewZombie(uint zombieId, string name, uint dna)
uint dnaDigits = 16
uint dnaModulus = 10 ** dnaDigits
uint cooldownTime = 1 days
struct Zombie {
string name
uint dna
uint32 level
uint32 readyTime
uint16 winCount
uint16 lossCount
}
Zombie[] public zombies
mapping (uint => address) public zombieToOwner
mapping (address => uint) ownerZombieCount
function _createZombie(string _name, uint _dna) internal {
uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1
zombieToOwner[id] = msg.sender
ownerZombieCount[msg.sender] = ownerZombieCount[msg.sender].add(1)
emit NewZombie(id, _name, _dna)
}
function _generateRandomDna(string _str) private view returns (uint) {
uint rand = uint(keccak256(abi.encodePacked(_str)))
return rand % dnaModulus
}
function createRandomZombie(string _name) public {
require(ownerZombieCount[msg.sender] == 0)
uint randDna = _generateRandomDna(_name)
randDna = randDna - randDna % 100
_createZombie(_name, randDna)
}
}
zombieattack.sol
pragma solidity ^0.4.25
import "./zombiehelper.sol"
contract ZombieAttack is ZombieHelper {
uint randNonce = 0
uint attackVictoryProbability = 70
function randMod(uint _modulus) internal returns(uint) {
randNonce = randNonce.add(1)
return uint(keccak256(abi.encodePacked(now, msg.sender, randNonce))) % _modulus
}
function attack(uint _zombieId, uint _targetId) external onlyOwnerOf(_zombieId) {
Zombie storage myZombie = zombies[_zombieId]
Zombie storage enemyZombie = zombies[_targetId]
uint rand = randMod(100)
if (rand <= attackVictoryProbability) {
myZombie.winCount = myZombie.winCount.add(1)
myZombie.level = myZombie.level.add(1)
enemyZombie.lossCount = enemyZombie.lossCount.add(1)
feedAndMultiply(_zombieId, enemyZombie.dna, "zombie")
} else {
myZombie.lossCount = myZombie.lossCount.add(1)
enemyZombie.winCount = enemyZombie.winCount.add(1)
_triggerCooldown(myZombie)
}
}
}