Contract Address Details

0xc80ACe0aC969397F96a8E1c97D21B4759fAFeB1E

Token
My DeFi Pet (MDP)
Creator
0xc0e944–d90e0c at 0x72d621–57807a
Balance
0 KAI ($0.00 USD)
Tokens
Fetching tokens...
Transactions
632,321 Transactions
Transfers
350,795 Transfers
Gas Used
Fetching gas used...
Last Balance Update
28042425
Contract name:
PetCore




Optimization enabled
true
Compiler version
v0.5.17+commit.d19bba13




Optimization runs
200
EVM Version
default




Verified at
2022-06-24T07:09:17.706904Z

Contract source code

/**
 *Submitted for verification at BscScan.com on 2021-04-27
*/

pragma solidity ^0.5.0;


library SafeMath {

    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        uint256 c = a - b;

        return c;
    }
}

/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
contract Ownable {
  address public owner;

  /**
   * @dev The Ownable constructor sets the original `owner` of the contract to the sender
   * account.
   */
  constructor() public {
    owner = msg.sender;
  }

  /**
   * @dev Throws if called by any account other than the owner.
   */
  modifier onlyOwner() {
    require(msg.sender == owner, "Ownable: caller is not the owner");
    _;
  }

  /**
   * @dev Allows the current owner to transfer control of the contract to a newOwner.
   * @param newOwner The address to transfer ownership to.
   */
  function transferOwnership(address newOwner) external onlyOwner {
    if (newOwner != address(0)) {
      owner = newOwner;
    }
  }

}

contract KRC721 {
    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;

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

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

interface IGeneScience {

    /// @dev given genes of pet 1 & 2, return a genetic combination - may have a random factor
    /// @param genes1 genes of mom
    /// @param genes2 genes of sire
    /// @return the genes that are supposed to be passed down the child
    function mixGenes(uint256 genes1, uint256 genes2, uint256 targetBlock) external view returns (uint256);
}

interface IKRC20 {
    function balanceOf(address owner) external view returns (uint);
    function allowance(address owner, address spender) external view returns (uint);

    function approve(address spender, uint value) external returns (bool);
    function transfer(address to, uint value) external returns (bool);
    function transferFrom(address from, address to, uint value) external returns (bool);
}

interface IPetCore {
    function createPet(address _owner) external;
}


contract PetAccessControl is Ownable {

    // @dev Keeps track whether the contract is paused. When that is true, most actions are blocked
    bool public paused = false;

    modifier whenNotPaused() {
        require(!paused);
        _;
    }

    modifier whenPaused {
        require(paused);
        _;
    }

    function pause() external onlyOwner whenNotPaused {
        paused = true;
    }

    function unpause() external onlyOwner whenPaused {
        // can't unpause if contract was upgraded
        paused = false;
    }
}

contract PetBase is PetAccessControl {

    /// @dev The Birth event is fired whenever a new pet comes into existence.
    event Birth(address owner, uint256 PetId, uint256 matronId, uint256 sireId, uint256 genes);

    /// @dev Transfer event as defined in current draft of KRC721.
    event Transfer(address from, address to, uint256 tokenId);

    /*** DATA TYPES ***/
    struct Pet {
        // The Pet's genetic code is packed into these 256-bits
        uint256 genes;

        // The timestamp from the block when this pet came into existence.
        uint64 birthTime;

        // The minimum timestamp after which this pet can engage in breeding
        // activities again.
        uint64 cooldownEndBlock;

        uint256 matronId;
        uint256 sireId;

        // Set to the ID of the sire pet for matrons that are pregnant,
        // zero otherwise. A non-zero value here is how we know a pet
        // is pregnant. Used to retrieve the genetic material for the new
        // pet when the birth transpires.
        uint256 siringWithId;

        // Set to the index in the cooldown array that represents
        // the current cooldown duration for this Pet. This starts at zero
        // for gen0 pets, and is initialized to floor(generation/2) for others.
        // Incremented by one for each successful breeding action, regardless
        // of whether this pet is acting as matron or sire.
        uint16 cooldownIndex;

        // The "generation number" of this pet. pets minted by the CP contract
        // for sale are called "gen0" and have a generation number of 0. The
        // generation number of all other pets is the larger of the two generation
        // numbers of their parents, plus one.
        // (i.e. max(matron.generation, sire.generation) + 1)
        uint16 generation;
        
        // The stages of this pet, starts from the junior stage, when feeding on, the pet grows to adulthood and middle-Age
        uint16 stages;
    }

    /*** CONSTANTS ***/

    /// @dev A lookup table indipeting the cooldown duration after any successful
    ///  breeding action, called "pregnancy time" for matrons and "siring cooldown"
    ///  for sires. Designed such that the cooldown roughly doubles each time a pet
    ///  is bred, encouraging owners not to just keep breeding the same pet over
    ///  and over again. Caps out at one week (a pet can breed an unbounded number
    ///  of times, and the maximum cooldown is always seven days).
    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)
    ];

    // An approximation of currently how many seconds are in between blocks.
    uint256 public secondsPerBlock = 6;

    /*** STORAGE ***/

    /// @dev An array containing the Pet struct for all pets in existence. The ID
    ///  of each pet is actually an index into this array. Note that ID 0 is a negapet,
    ///  the unPet, the mythical beast that is the parent of all gen0 pets.
    Pet[] pets;

    mapping (uint256 => address) public PetIndexToOwner;

    // Used internally inside balanceOf() to resolve ownership count.
    mapping (address => uint256) ownershipTokenCount;

    /// @dev A mapping from PetIDs to an address that has been approved to call
    ///  transferFrom().
    mapping (uint256 => address) public PetIndexToApproved;

    /// @dev A mapping from PetIDs to an address that has been approved to use
    ///  this Pet for siring via breedWith().
    mapping (uint256 => address) public sireAllowedToAddress;

    SaleClockAuction public saleAuction;

    /// @dev The address of a custom ClockAuction subclassed contract that handles siring
    ///  auctions. Needs to be separate from saleAuction because the actions taken on success
    ///  after a sales and siring auction are quite different.
    SiringClockAuction public siringAuction;

    /// @dev Assigns ownership of a specific Pet to an address.
    function _transfer(address _from, address _to, uint256 _tokenId) internal {
        ownershipTokenCount[_to]++;
        PetIndexToOwner[_tokenId] = _to;
        if (_from != address(0)) {
            ownershipTokenCount[_from]--;
            delete sireAllowedToAddress[_tokenId];
            delete PetIndexToApproved[_tokenId];
        }
        emit Transfer(_from, _to, _tokenId);
    }

    /// @dev An internal method that creates a new Pet and stores it.
    /// @param _matronId The Pet ID of the matron of this pet (zero for gen0)
    /// @param _sireId The Pet ID of the sire of this pet (zero for gen0)
    /// @param _generation The generation number of this pet.
    /// @param _genes The Pet's genetic code.
    /// @param _owner The inital owner of this pet, must be non-zero (except for the unPet, ID 0)
    function _createPet(
        uint256 _matronId,
        uint256 _sireId,
        uint256 _generation,
        uint256 _genes,
        address _owner
    )
        internal
        returns (uint)
    {
        // New Pet starts with the same cooldown as parent gen/2
        uint16 cooldownIndex = uint16(_generation / 2);
        if (cooldownIndex > 13) {
            cooldownIndex = 13;
        }

        Pet memory _Pet = Pet({
            genes: _genes,
            birthTime: uint64(now),
            cooldownEndBlock: 0,
            matronId: uint32(_matronId),
            sireId: uint32(_sireId),
            siringWithId: 0,
            cooldownIndex: cooldownIndex,
            generation: uint16(_generation),
            stages: uint16(1)
        });
        uint256 newpetId = pets.push(_Pet) - 1;

        emit Birth(
            _owner,
            newpetId,
            uint256(_Pet.matronId),
            uint256(_Pet.sireId),
            _Pet.genes
        );

        _transfer(address(0), _owner, newpetId);

        return newpetId;
    }

    function setSecondsPerBlock(uint256 secs) external onlyOwner {
        require(secs < cooldowns[0]);
        secondsPerBlock = secs;
    }
}


contract PetOwnership is PetBase, KRC721 {

    string public constant name = "My DeFi Pet";
    string public constant symbol = "MDP";

    bytes4 constant InterfaceSignature_KRC165 =
        bytes4(keccak256('supportsInterface(bytes4)'));

    bytes4 constant InterfaceSignature_KRC721 =
        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)
    {

        return ((_interfaceID == InterfaceSignature_KRC165) || (_interfaceID == InterfaceSignature_KRC721));
    }

    /// @dev Checks if a given address is the current owner of a particular Pet.
    /// @param _claimant the address we are validating against.
    /// @param _tokenId pet id, only valid when > 0
    function _owns(address _claimant, uint256 _tokenId) internal view returns (bool) {
        return PetIndexToOwner[_tokenId] == _claimant;
    }

    /// @dev Checks if a given address currently has transferApproval for a particular Pet.
    /// @param _claimant the address we are confirming pet is approved for.
    /// @param _tokenId pet id, only valid when > 0
    function _approvedFor(address _claimant, uint256 _tokenId) internal view returns (bool) {
        return PetIndexToApproved[_tokenId] == _claimant;
    }

    function _approve(uint256 _tokenId, address _approved) internal {
        PetIndexToApproved[_tokenId] = _approved;
    }

    /// @notice Returns the number of pets owned by a specific address.
    /// @param _owner The owner address to check.
    function balanceOf(address _owner) public view returns (uint256 count) {
        return ownershipTokenCount[_owner];
    }

    /// @notice Transfers a Pet to another address
    /// @param _to The address of the recipient, can be a user or contract.
    /// @param _tokenId The ID of the Pet to transfer.
    function transfer(
        address _to,
        uint256 _tokenId
    )
        external
        whenNotPaused
    {
        require(_to != address(0));
        require(_to != address(this));
        require(_to != address(saleAuction));
        require(_to != address(siringAuction));

        require(_owns(msg.sender, _tokenId));

        _transfer(msg.sender, _to, _tokenId);
    }

    /// @param _to The address to be granted transfer approval. Pass address(0) to
    ///  clear all approvals.
    /// @param _tokenId The ID of the Pet that can be transferred if this call succeeds.
    function approve(
        address _to,
        uint256 _tokenId
    )
        external
        whenNotPaused
    {
        require(_owns(msg.sender, _tokenId));

        _approve(_tokenId, _to);

        emit Approval(msg.sender, _to, _tokenId);
    }

    /// @param _from The address that owns the Pet to be transfered.
    /// @param _to The address that should take ownership of the Pet. Can be any address,
    ///  including the caller.
    /// @param _tokenId The ID of the Pet to be transferred.
    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));

        _transfer(_from, _to, _tokenId);
    }

    /// @notice Returns the total number of pets currently in existence.
    function totalSupply() public view returns (uint) {
        return pets.length - 1;
    }

    /// @notice Returns the address currently assigned ownership of a given Pet.
    function ownerOf(uint256 _tokenId)
        external
        view
        returns (address owner)
    {
        owner = PetIndexToOwner[_tokenId];

        require(owner != address(0));
    }

    /// @notice Returns a list of all Pet IDs assigned to an address.
    /// @param _owner The owner whose pets we are interested in.
    function tokensOfOwner(address _owner) external view returns(uint256[] memory ownerTokens) {
        uint256 tokenCount = balanceOf(_owner);

        if (tokenCount == 0) {
            return new uint256[](0);
        } else {
            uint256[] memory result = new uint256[](tokenCount);
            uint256 totalpets = totalSupply();
            uint256 resultIndex = 0;

            uint256 petId;

            for (petId = 1; petId <= totalpets; petId++) {
                if (PetIndexToOwner[petId] == _owner) {
                    result[resultIndex] = petId;
                    resultIndex++;
                }
            }

            return result;
        }
    }
}

/// @title A facet of PetCore that manages Pet siring, gestation, and birth.
contract PetBreeding is PetOwnership {
    
    address public dpetToken = 0xfb62AE373acA027177D1c18Ee0862817f9080d08;

    /// @dev The Pregnant event is fired when two pets successfully breed and the pregnancy
    ///  timer begins for the matron.
    event Pregnant(address owner, uint256 matronId, uint256 sireId, uint256 cooldownEndBlock);

    uint256 public autoBirthFee = 1*10**18; // pet token

    // Keeps track of number of pregnant pets.
    uint256 public pregnantpets;

    address public geneScience;

    function setGeneScienceAddress(address _address) external onlyOwner {
        geneScience = _address;
    }

    /// @dev Checks that a given pet is able to breed. Requires that the
    ///  current cooldown is finished (for sires) and also checks that there is
    ///  no pending pregnancy.
    function _isReadyToBreed(Pet memory _pet) internal view returns (bool) {
        return (_pet.siringWithId == 0) && (_pet.cooldownEndBlock <= uint64(block.number));
    }

    /// @dev Check if a sire has authorized breeding with this matron. True if both sire
    ///  and matron have the same owner, or if the sire has given siring permission to
    ///  the matron's owner (via approveSiring()).
    function _isSiringPermitted(uint256 _sireId, uint256 _matronId) internal view returns (bool) {
        address matronOwner = PetIndexToOwner[_matronId];
        address sireOwner = PetIndexToOwner[_sireId];

        return (matronOwner == sireOwner || sireAllowedToAddress[_sireId] == matronOwner);
    }

    /// @dev Set the cooldownEndTime for the given Pet, based on its current cooldownIndex.
    /// @param _pet A reference to the Pet in storage which needs its timer started.
    function _triggerCooldown(Pet storage _pet) internal {
        _pet.cooldownEndBlock = uint64((cooldowns[_pet.cooldownIndex]/secondsPerBlock) + block.number);

        if (_pet.cooldownIndex < 13) {
            _pet.cooldownIndex += 1;
        }
    }

    /// @notice Grants approval to another user to sire with one of your pets.
    /// @param _addr The address that will be able to sire with your Pet. Set to
    ///  address(0) to clear all siring approvals for this Pet.
    /// @param _sireId A Pet that you own that _addr will now be able to sire with.
    function approveSiring(address _addr, uint256 _sireId)
        external
        whenNotPaused
    {
        require(_owns(msg.sender, _sireId));
        sireAllowedToAddress[_sireId] = _addr;
    }

    function setAutoBirthFee(uint256 val) external onlyOwner {
        autoBirthFee = val;
    }

    function _isReadyToGiveBirth(Pet memory _matron) private view returns (bool) {
        return (_matron.siringWithId != 0) && (_matron.cooldownEndBlock <= uint64(block.number));
    }

    /// @notice Checks that a given pet is able to breed
    /// @param _PetId reference the id of the pet
    function isReadyToBreed(uint256 _PetId)
        public
        view
        returns (bool)
    {
        require(_PetId > 0);
        Pet storage pet = pets[_PetId];
        return _isReadyToBreed(pet);
    }

    /// @dev Checks whether a Pet is currently pregnant.
    /// @param _PetId reference the id of the pet
    function isPregnant(uint256 _PetId)
        public
        view
        returns (bool)
    {
        require(_PetId > 0);
        return pets[_PetId].siringWithId != 0;
    }

    /// @param _matron A reference to the Pet struct of the potential matron.
    /// @param _matronId The matron's ID.
    /// @param _sire A reference to the Pet struct of the potential sire.
    /// @param _sireId The sire's ID
    function _isValidMatingPair(
        Pet storage _matron,
        uint256 _matronId,
        Pet storage _sire,
        uint256 _sireId
    )
        private
        view
        returns(bool)
    {
        // A Pet can't breed with itself!
        if (_matronId == _sireId) {
            return false;
        }

        // pets can't breed with their parents.
        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) {
            return true;
        }

        // pets can't breed with full or half siblings.
        if (_sire.matronId == _matron.matronId || _sire.matronId == _matron.sireId) {
            return false;
        }
        if (_sire.sireId == _matron.matronId || _sire.sireId == _matron.sireId) {
            return false;
        }

        return true;
    }

    /// @dev Internal check to see if a given sire and matron are a valid mating pair for
    ///  breeding via auction.
    function _canBreedWithViaAuction(uint256 _matronId, uint256 _sireId)
        internal
        view
        returns (bool)
    {
        Pet storage matron = pets[_matronId];
        Pet storage sire = pets[_sireId];
        return _isValidMatingPair(matron, _matronId, sire, _sireId);
    }

    /// @param _matronId The ID of the proposed matron.
    /// @param _sireId The ID of the proposed sire.
    function canBreedWith(uint256 _matronId, uint256 _sireId)
        external
        view
        returns(bool)
    {
        require(_matronId > 0);
        require(_sireId > 0);
        Pet storage matron = pets[_matronId];
        Pet storage sire = pets[_sireId];
        return _isValidMatingPair(matron, _matronId, sire, _sireId) &&
            _isSiringPermitted(_sireId, _matronId);
    }

    function _breedWith(uint256 _matronId, uint256 _sireId) internal {
        // Grab a reference to the pets from storage.
        Pet storage sire = pets[_sireId];
        Pet storage matron = pets[_matronId];

        // Mark the matron as pregnant, keeping track of who the sire is.
        matron.siringWithId = uint32(_sireId);

        // Trigger the cooldown for both parents.
        _triggerCooldown(sire);
        _triggerCooldown(matron);

        delete sireAllowedToAddress[_matronId];
        delete sireAllowedToAddress[_sireId];

        pregnantpets++;

        emit Pregnant(PetIndexToOwner[_matronId], _matronId, _sireId, matron.cooldownEndBlock);
    }

    /// @param _matronId The ID of the Pet acting as matron
    /// @param _sireId The ID of the Pet acting as sire
    function breedWithAuto(uint256 _matronId, uint256 _sireId, uint256 _amount)
        external
        whenNotPaused
    {
        // Checks for .
        require(_amount >= autoBirthFee, "Must payment");
        require(IKRC20(dpetToken).transferFrom(msg.sender, address(this), _amount));
        // Caller must own the matron.
        require(_owns(msg.sender, _matronId));
        require(_isSiringPermitted(_sireId, _matronId));

        // Grab a reference to the potential matron
        Pet storage matron = pets[_matronId];

        // Make sure matron isn't pregnant, or in the middle of a siring cooldown
        require(_isReadyToBreed(matron));

        // Grab a reference to the potential sire
        Pet storage sire = pets[_sireId];

        // Make sure sire isn't pregnant, or in the middle of a siring cooldown
        require(_isReadyToBreed(sire));

        require(_isValidMatingPair(
            matron,
            _matronId,
            sire,
            _sireId
        ));

        _breedWith(_matronId, _sireId);
    }

    /// @notice Have a pregnant Pet give birth!
    /// @param _matronId A Pet ready to give birth.
    /// @return The Pet ID of the new pet.
    function giveBirth(uint256 _matronId)
        external
        whenNotPaused
        returns(uint256)
    {
        Pet storage matron = pets[_matronId];

        // Check that the matron is a valid pet.
        require(matron.birthTime != 0, "Invalid pet");

        require(_isReadyToGiveBirth(matron), "Not ready birth");

        uint256 sireId = matron.siringWithId;
        Pet storage sire = pets[sireId];

        uint16 parentGen = matron.generation;
        if (sire.generation > matron.generation) {
            parentGen = sire.generation;
        }

        uint256 childGenes = IGeneScience(geneScience).mixGenes(matron.genes, sire.genes, matron.cooldownEndBlock - 1);

        address owner = PetIndexToOwner[_matronId];
        uint256 petId = _createPet(_matronId, matron.siringWithId, parentGen + 1, childGenes, owner);

        delete matron.siringWithId;

        pregnantpets--;

        return petId;
    }
}

/// @title Auction Core
contract ClockAuctionBase {
    using SafeMath for uint256;
     
    address public dpetToken = 0xfb62AE373acA027177D1c18Ee0862817f9080d08;

    // Represents an auction on an NFT
    struct Auction {
        // Current owner of NFT
        address seller;
        // Price at beginning of auction
        uint128 startingPrice;
        // Price at end of auction
        uint128 endingPrice;
        // Duration (in seconds) of auction
        uint64 duration;
        // Time when auction started
        uint64 startedAt;
    }

    // Reference to contract tracking NFT ownership
    KRC721 public nonFungibleContract;

    uint256 public ownerCut;
    mapping (uint256 => Auction) tokenIdToAuction;

    event AuctionCreated(uint256 tokenId, uint256 startingPrice, uint256 endingPrice, uint256 duration);
    event AuctionSuccessful(uint256 tokenId, uint256 totalPrice, address winner);
    event AuctionCancelled(uint256 tokenId);

    /// @dev Returns true if the claimant owns the token.
    /// @param _claimant - Address claiming to own the token.
    /// @param _tokenId - ID of token whose ownership to verify.
    function _owns(address _claimant, uint256 _tokenId) internal view returns (bool) {
        return (nonFungibleContract.ownerOf(_tokenId) == _claimant);
    }

    /// @dev Escrows the NFT, assigning ownership to this contract.
    /// @param _owner - Current owner address of token to escrow.
    /// @param _tokenId - ID of token whose approval to verify.
    function _escrow(address _owner, uint256 _tokenId) internal {
        // it will throw if transfer fails
        nonFungibleContract.transferFrom(_owner, address(this), _tokenId);
    }

    /// @dev Transfers an NFT owned by this contract to another address.
    /// @param _receiver - Address to transfer NFT to.
    /// @param _tokenId - ID of token to transfer.
    function _transfer(address _receiver, uint256 _tokenId) internal {
        nonFungibleContract.transfer(_receiver, _tokenId);
    }

    /// @dev Adds an auction to the list of open auctions.
    /// @param _tokenId The ID of the token to be put on auction.
    /// @param _auction Auction to add.
    function _addAuction(uint256 _tokenId, Auction memory _auction) internal {
        require(_auction.duration >= 1 minutes);

        tokenIdToAuction[_tokenId] = _auction;

        emit AuctionCreated(
            uint256(_tokenId),
            uint256(_auction.startingPrice),
            uint256(_auction.endingPrice),
            uint256(_auction.duration)
        );
    }

    /// @dev Cancels an auction unconditionally.
    function _cancelAuction(uint256 _tokenId, address _seller) internal {
        _removeAuction(_tokenId);
        _transfer(_seller, _tokenId);
        emit AuctionCancelled(_tokenId);
    }

    /// @dev Computes the price and transfers winnings.
    function _bid(uint256 _tokenId, uint256 _bidAmount)
        internal
        returns (uint256)
    {
        // Get a reference to the auction struct
        Auction storage auction = tokenIdToAuction[_tokenId];
        require(_isOnAuction(auction));

        // Check that the bid is greater than or equal to the current price
        uint256 price = _currentPrice(auction);
        require(_bidAmount >= price);

        address seller = auction.seller;

        // The bid is good! Remove the auction before sending the fees
        // to the sender so we can't have a reentrancy attack.
        _removeAuction(_tokenId);

        if (price > 0) {
            uint256 auctioneerCut = _computeCut(price);
            uint256 sellerProceeds = price - auctioneerCut;

            require(IKRC20(dpetToken).transfer(seller, sellerProceeds));
        }

        uint256 bidExcess = _bidAmount - price;

        require(IKRC20(dpetToken).transfer(msg.sender, bidExcess));

        emit AuctionSuccessful(_tokenId, price, msg.sender);

        return price;
    }

    /// @dev Removes an auction from the list of open auctions.
    /// @param _tokenId - ID of NFT on auction.
    function _removeAuction(uint256 _tokenId) internal {
        delete tokenIdToAuction[_tokenId];
    }

    /// @dev Returns true if the NFT is on auction.
    /// @param _auction - Auction to check.
    function _isOnAuction(Auction storage _auction) internal view returns (bool) {
        return (_auction.startedAt > 0);
    }

    function _currentPrice(Auction storage _auction)
        internal
        view
        returns (uint256)
    {
        uint256 secondsPassed = 0;

        if (now > _auction.startedAt) {
            secondsPassed = now - _auction.startedAt;
        }

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

    /// @dev Computes the current price of an auction.
    function _computeCurrentPrice(
        uint256 _startingPrice,
        uint256 _endingPrice,
        uint256 _duration,
        uint256 _secondsPassed
    )
        internal
        pure
        returns (uint256)
    {
        if (_secondsPassed >= _duration) {
            return _endingPrice;
        } else {
            uint256 totalPriceChange = _endingPrice.sub(_startingPrice);

            uint256 currentPriceChange = totalPriceChange * _secondsPassed / _duration;

            uint256 currentPrice = _startingPrice + currentPriceChange;

            return currentPrice;
        }
    }

    /// @dev Computes owner's cut of a sale.
    /// @param _price - Sale price of NFT.
    function _computeCut(uint256 _price) internal view returns (uint256) {
        return _price * ownerCut / 10000;
    }

}


/**
 * @title Pausable
 * @dev Base contract which allows children to implement an emergency stop mechanism.
 */
contract Pausable is Ownable {
  event Pause();
  event Unpause();

  bool public paused = false;


  /**
   * @dev modifier to allow actions only when the contract IS paused
   */
  modifier whenNotPaused() {
    require(!paused);
    _;
  }

  /**
   * @dev modifier to allow actions only when the contract IS NOT paused
   */
  modifier whenPaused {
    require(paused);
    _;
  }

  /**
   * @dev called by the owner to pause, triggers stopped state
   */
  function pause() external onlyOwner whenNotPaused returns (bool) {
    paused = true;
    emit Pause();
    return true;
  }

  /**
   * @dev called by the owner to unpause, returns to normal state
   */
  function unpause() external onlyOwner whenPaused returns (bool) {
    paused = false;
    emit Unpause();
    return true;
  }
}


/// @title Clock auction for non-fungible tokens.
contract ClockAuction is Pausable, ClockAuctionBase {

    bytes4 constant InterfaceSignature_KRC721 = bytes4(0x9a20483d);

    /// @param _nftAddress - address of a deployed contract implementing
    ///  the Nonfungible Interface.
    /// @param _cut - percent cut the owner takes on each auction, must be
    ///  between 0-10,000.
    constructor(address _nftAddress, uint256 _cut) public {
        require(_cut <= 10000);
        ownerCut = _cut;

        KRC721 candidateContract = KRC721(_nftAddress);
        require(candidateContract.supportsInterface(InterfaceSignature_KRC721));
        nonFungibleContract = candidateContract;
    }

    function withdrawBalance() external onlyOwner {
        address(uint160(owner)).transfer(address(this).balance);
        IKRC20(dpetToken).transfer(owner, getBalance());
    }
    
    function changeCut(uint256 _cut) external onlyOwner {
        require(_cut <= 10000);
        ownerCut = _cut;
    }
    
    function getBalance() view public returns(uint256) {
        return IKRC20(dpetToken).balanceOf(address(this));
    }

    /// @dev Creates and begins a new auction.
    /// @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 time to move between starting
    ///  price and ending price (in seconds).
    /// @param _seller - Seller, if not the message sender
    function createAuction(
        uint256 _tokenId,
        uint256 _startingPrice,
        uint256 _endingPrice,
        uint256 _duration,
        address _seller
    )
        external
        whenNotPaused
    {
        require(_startingPrice == uint256(uint128(_startingPrice)));
        require(_endingPrice == uint256(uint128(_endingPrice)));
        require(_duration == uint256(uint64(_duration)));

        require(_owns(msg.sender, _tokenId), "Not PetId owner");
        _escrow(msg.sender, _tokenId);
        Auction memory auction = Auction(
            _seller,
            uint128(_startingPrice),
            uint128(_endingPrice),
            uint64(_duration),
            uint64(now)
        );
        _addAuction(_tokenId, auction);
    }

    /// @dev Bids on an open auction, completing the auction and transferring
    ///  ownership of the NFT if enough KAI is supplied.
    /// @param _tokenId - ID of token to bid on.
    function bid(uint256 _tokenId, uint256 _amount)
        external
        whenNotPaused
    {
        // require(IKRC20(dpetToken).transfer(address(this), _amount));
        // _bid will throw if the bid or funds transfer fails
        _bid(_tokenId, _amount);
        _transfer(msg.sender, _tokenId);
    }

    /// @dev Cancels an auction that hasn't been won yet.
    ///  Returns the NFT to original owner.
    /// @notice This is a state-modifying function that can
    ///  be called while the contract is paused.
    /// @param _tokenId - ID of token on auction
    function cancelAuction(uint256 _tokenId)
        external
    {
        Auction storage auction = tokenIdToAuction[_tokenId];
        require(_isOnAuction(auction), "TokenID is a must on auction");
        address seller = auction.seller;
        require(msg.sender == seller);
        _cancelAuction(_tokenId, seller);
    }

    /// @dev Cancels an auction when the contract is paused.
    ///  Only the owner may do this, and NFTs are returned to
    ///  the seller. This should only be used in emergencies.
    /// @param _tokenId - ID of the NFT on auction to cancel.
    function cancelAuctionWhenPaused(uint256 _tokenId)
        whenPaused
        onlyOwner
        external
    {
        Auction storage auction = tokenIdToAuction[_tokenId];
        require(_isOnAuction(auction), "TokenID is a must on auction");
        _cancelAuction(_tokenId, auction.seller);
    }

    /// @dev Returns auction info for an NFT on auction.
    /// @param _tokenId - ID of NFT on auction.
    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), "TokenID is a must on auction");
        return (
            auction.seller,
            auction.startingPrice,
            auction.endingPrice,
            auction.duration,
            auction.startedAt
        );
    }

    /// @dev Returns the current price of an auction.
    /// @param _tokenId - ID of the token price we are checking.
    function getCurrentPrice(uint256 _tokenId)
        external
        view
        returns (uint256)
    {
        Auction storage auction = tokenIdToAuction[_tokenId];
        require(_isOnAuction(auction), "TokenID is a must on auction");
        return _currentPrice(auction);
    }

}


/// @title Reverse auction modified for siring
/// @notice We omit a fallback function to prevent accidental sends to this contract.
contract SiringClockAuction is ClockAuction {

    bool public isSiringClockAuction = true;

    constructor(address _nftAddr, uint256 _cut) public
        ClockAuction(_nftAddr, _cut) {}

    /// @dev Creates and begins a new auction.
    /// @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
    {
        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);
    }

    /// @dev Places a bid for siring. Requires the sender
    /// is the PetCore contract because all bid methods
    /// should be wrapped. Also returns the Pet to the
    /// seller rather than the winner.
    function bid(uint256 _tokenId, uint256 _amount)
        external
    {   
        // require(IKRC20(dpetToken).transferFrom(msg.sender, address(this), _amount));
        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, _amount);
        // We transfer the Pet back to the seller, the winner will get
        // the offspring
        _transfer(seller, _tokenId);
    }

}


/// @title Clock auction modified for sale of pets
contract SaleClockAuction is ClockAuction {

    bool public isSaleClockAuction = true;

    // Tracks last 5 sale price of gen0 Pet sales
    uint256 public gen0SaleCount;
    uint256[5] public lastGen0SalePrices;

    constructor(address _nftAddr, uint256 _cut) public
        ClockAuction(_nftAddr, _cut) {}

    /// @dev Creates and begins a new auction.
    /// @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
    {
        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);
    }

    /// @dev Updates lastSalePrice if seller is the nft contract
    /// Otherwise, works the same as default bid method.
    function bid(uint256 _tokenId, uint256 _amount)
        external
    {
        require(IKRC20(dpetToken).transferFrom(msg.sender, address(this), _amount));

        // _bid verifies token ID size
        address seller = tokenIdToAuction[_tokenId].seller;
        uint256 price = _bid(_tokenId, _amount);
        _transfer(msg.sender, _tokenId);

        // If not a gen0 auction, exit
        if (seller == address(nonFungibleContract)) {
            // Track gen0 sale prices
            lastGen0SalePrices[gen0SaleCount % 5] = price;
            gen0SaleCount++;
        }
    }

    function averageGen0SalePrice() external view returns (uint256) {
        uint256 sum = 0;
        for (uint256 i = 0; i < 5; i++) {
            sum += lastGen0SalePrices[i];
        }
        return sum / 5;
    }

}


/// @title all functions related to creating pets
contract PetMinting is PetBreeding, IPetCore {

    // Counts the number of pets the contract owner has created.
    uint256 public gen0CreatedCount;
    uint256 public gen0Price = 1* 10**18;
    address public stakingContract;
    
    uint256 private nonce;
    
    /**
     * @dev Throws if called by any account other than the staking contract.
     */
    modifier onlyStakingContract() {
        require(msg.sender == stakingContract, "Ownable: caller is not the staking contract");
        _;
    }


    /// @param _owner the future owner of the created pets.
    function createPromoPet(address _owner, uint256 _amount) external  {
        require(_amount >= gen0Price, "INVALID AMOUNT");
        require(IKRC20(dpetToken).transferFrom(msg.sender, address(this), _amount));

        gen0CreatedCount++;
        uint256 genes = _randomPetGenes();
        _createPet(0, 0, 0, genes, _owner);
    }
    
    function createPet(address _owner) external onlyStakingContract {
        gen0CreatedCount++;
        uint256 genes = _randomPetGenes();
        _createPet(0, 0, 0, genes, _owner);
    }
    
    function createGen0Auction(address _owner, uint256 _genes) external onlyOwner {
        gen0CreatedCount++;
        _createPet(0, 0, 0, _genes, _owner);
    }
    
    function updateGen0Price(uint256 _gen0Price) external onlyOwner {
        gen0Price = _gen0Price;
    }
    
    function setStakingContract(address _stakingContract) external onlyOwner {
        stakingContract = _stakingContract;
    }

    function _randomPetGenes() internal returns (uint256) {
        uint256 randomN = uint256(blockhash(block.number));
        uint256 genes = uint256(keccak256(abi.encodePacked(randomN, block.timestamp, nonce))) % (10 **72) + 1*10**71;
        nonce++;
        
        return genes;
    }
}

contract PetCore is PetMinting {
    
    uint256 public amountToAdulthood = 10 * 10**18;
    uint256 public amountToMiddleAge = 15 * 10**18;
    address public siringAuctionAddr;
    address public saleAuctionAddr;


    constructor() public {
        paused = false;

        // start with the mythical pet 0 - so we don't have generation-0 parent issues
        _createPet(0, 0, 0, uint256(-1), address(0));
    }
    
    /// @dev Reject all KAI from being sent here, unless it's from one of the
    ///  two auction contracts.
    function() external payable {
        require(
            msg.sender == address(saleAuction) ||
            msg.sender == address(siringAuction)
        );
    }

    /// @dev Sets the reference to the sale auction.
    /// @param _address - Address of sale contract.
    function setSaleAuctionAddress(address _address) external onlyOwner {
        SaleClockAuction candidateContract = SaleClockAuction(_address);

        require(candidateContract.isSaleClockAuction());

        // Set the new contract address
        saleAuction = candidateContract;
        saleAuctionAddr = _address;
    }

    function setSiringAuctionAddress(address _address) external  onlyOwner {
        SiringClockAuction candidateContract = SiringClockAuction(_address);

        require(candidateContract.isSiringClockAuction());

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

    function createSaleAuction(
        uint256 _PetId,
        uint256 _startingPrice,
        uint256 _endingPrice,
        uint256 _duration
    )
        external
        whenNotPaused
    {
        require(_owns(msg.sender, _PetId), "Not PetId owner");

        require(!isPregnant(_PetId), "Pet is pregnant");
        _approve(_PetId, address(saleAuction));
        saleAuction.createAuction(
            _PetId,
            _startingPrice,
            _endingPrice,
            _duration,
            msg.sender
        );
    }

    function createSiringAuction(
        uint256 _PetId,
        uint256 _startingPrice,
        uint256 _endingPrice,
        uint256 _duration
    )
        external
        whenNotPaused
    {
        // Auction contract checks input sizes
        // If Pet is already on any auction, this will throw
        // because it will be owned by the auction contract.
        require(_owns(msg.sender, _PetId), "Not PetId owner");
        require(isReadyToBreed(_PetId), "Not ready to breed");
        _approve(_PetId, address(siringAuction));
        // Siring auction throws if inputs are invalid and clears
        // transfer and sire approval after escrowing the Pet.
        siringAuction.createAuction(
            _PetId,
            _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,
        uint256 _matronId,
        uint256 _amount
    )
        external
        whenNotPaused
    {
        require(IKRC20(dpetToken).transferFrom(msg.sender, address(this), _amount));
        // Auction contract checks input sizes
        require(_owns(msg.sender, _matronId), "Not matron owner");
        require(isReadyToBreed(_matronId), "Not ready to breed");
        require(_canBreedWithViaAuction(_matronId, _sireId), "Can't breed with via auction");
        
        // Define the current price of the auction.
        uint256 currentPrice = siringAuction.getCurrentPrice(_sireId);
        require(_amount >= currentPrice + autoBirthFee);

        // // Siring auction will throw if the bid fails.
        require(IKRC20(dpetToken).transfer(siringAuctionAddr, _amount));
        siringAuction.bid(_sireId, _amount);
        _breedWith(uint32(_matronId), uint32(_sireId));
    }

    /// @notice Returns all the relevant information about a specific Pet.
    /// @param _id The ID of the Pet of interest.
    function getPet(uint256 _id)
        public
        view
        returns (
        bool isGestating,
        bool isReady,
        uint256 cooldownIndex,
        uint256 nextActionAt,
        uint256 siringWithId,
        uint256 birthTime,
        uint256 matronId,
        uint256 sireId,
        uint256 generation,
        string memory genes,
        uint256 stages
    ) {
        Pet storage pet = pets[_id];

        isGestating = (pet.siringWithId != 0);
        isReady = (pet.cooldownEndBlock <= block.number);
        cooldownIndex = uint256(pet.cooldownIndex);
        nextActionAt = uint256(pet.cooldownEndBlock);
        siringWithId = uint256(pet.siringWithId);
        birthTime = uint256(pet.birthTime);
        matronId = uint256(pet.matronId);
        sireId = uint256(pet.sireId);
        generation = uint256(pet.generation);
        genes = _uintToStr(pet.genes);
        stages = uint256(pet.stages);
    }
    
    /// @notice feed on a specific Pet.
    /// @param _petId The ID of the Pet of interest.
    /// @param _amount.
    function feedOnPet(uint256 _petId, uint256 _amount) external {
        require(IKRC20(dpetToken).transferFrom(msg.sender, address(this), _amount));
        
        Pet storage pet = pets[_petId];
        if (_amount == amountToAdulthood) {
            require(pet.stages == 1, "INVALID STAGE 1");
            pet.stages += 1;
        }
        
        if (_amount == amountToMiddleAge) {
            require(pet.stages == 2, "INVALID STAGE 2");
            pet.stages += 1;
        }
    }
    
    function setAmountToAdulthood(uint256 _amountToAdulthood) external onlyOwner {
        amountToAdulthood = _amountToAdulthood;
    }
    
    function setAmountToMiddleAge(uint256 _amountToMiddleAge) external onlyOwner {
        amountToMiddleAge = _amountToMiddleAge;
    }
    
    function getBalance() public view returns(uint256) {
        return IKRC20(dpetToken).balanceOf(address(this));
    }
    
    function withdrawBalance() external onlyOwner {
        IKRC20(dpetToken).transfer(owner, getBalance());
    }
    
    function _uintToStr(uint _i) private pure returns (string memory _uintAsString) {
        uint number = _i;
        if (number == 0) {
            return "0";
        }
        uint j = number;
        uint len;
        while (j != 0) {
            len++;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint k = len - 1;
        while (number != 0) {
            bstr[k--] = byte(uint8(48 + number % 10));
            number /= 10;
        }
        return string(bstr);
    }
}


contract GeneScience is IGeneScience {

    uint256 internal constant maskLast8Bits = uint256(0xff);
    uint256 internal constant maskFirst248Bits = uint256(~0xff);

    /// @dev given a characteristic and 2 genes (unsorted) - returns > 0 if the genes ascended, that's the value
    /// @param trait1 any trait of that characteristic
    /// @param trait2 any trait of that characteristic
    /// @param rand is expected to be a 3 bits number (0~7)
    /// @return -1 if didnt match any ascention, OR a number from 0 to 30 for the ascended trait
    function _ascend(uint8 trait1, uint8 trait2, uint256 rand) internal pure returns(uint8 ascension) {
        ascension = 0;

        uint8 smallT = trait1;
        uint8 bigT = trait2;

        if (smallT > bigT) {
            bigT = trait1;
            smallT = trait2;
        }

        if ((bigT - smallT == 1) && smallT % 2 == 0) {

            // The rand argument is expected to be a random number 0-7.
            // 1st and 2nd tier: 1/4 chance (rand is 0 or 1)
            // 3rd and 4th tier: 1/8 chance (rand is 0)

            // must be at least this much to ascend
            uint256 maxRand;
            if (smallT < 23) maxRand = 1;
            else maxRand = 0;

            if (rand <= maxRand ) {
                ascension = (smallT / 2) + 16;
            }
        }
    }

    /// @dev given a number get a slice of any bits, at certain offset
    /// @param _n a number to be sliced
    /// @param _nbits how many bits long is the new number
    /// @param _offset how many bits to skip
    function _sliceNumber(uint256 _n, uint256 _nbits, uint256 _offset) private pure returns (uint256) {
        // mask is made by shifting left an offset number of times
        uint256 mask = uint256((2**_nbits) - 1) << _offset;
        // AND n with mask, and trim to max of _nbits bits
        return uint256((_n & mask) >> _offset);
    }

    /// @dev Get a 5 bit slice from an input as a number
    /// @param _input bits, encoded as uint
    /// @param _slot from 0 to 50
    function _get5Bits(uint256 _input, uint256 _slot) internal pure returns(uint8) {
        return uint8(_sliceNumber(_input, uint256(5), _slot * 5));
    }

    /// @dev Parse a pet gene and returns all of 12 "trait stack" that makes the characteristics
    /// @param _genes pet gene
    /// @return the 48 traits that composes the genetic code, logically divided in stacks of 4, where only the first trait of each stack may express
    function decode(uint256 _genes) public pure returns(uint8[] memory) {
        uint8[] memory traits = new uint8[](48);
        uint256 i;
        for(i = 0; i < 48; i++) {
            traits[i] = _get5Bits(_genes, i);
        }
        return traits;
    }

    /// @dev Given an array of traits return the number that represent genes
    function encode(uint8[] memory _traits) public pure returns (uint256 _genes) {
        _genes = 0;
        for(uint256 i = 0; i < 48; i++) {
            _genes = _genes << 5;
            // bitwise OR trait with _genes
            _genes = _genes | _traits[47 - i];
        }
        return _genes;
    }

    /// @dev return the expressing traits
    /// @param _genes the long number expressing pet genes
    function expressingTraits(uint256 _genes) public pure returns(uint8[12] memory) {
        uint8[12] memory express;
        for(uint256 i = 0; i < 12; i++) {
            express[i] = _get5Bits(_genes, i * 4);
        }
        return express;
    }

    /// @dev the function as defined in the breeding contract - as defined in CK bible
    function mixGenes(uint256 _genes1, uint256 _genes2, uint256 _targetBlock) public view returns (uint256) {
        // require(block.number > _targetBlock);

        uint256 randomN = uint256(blockhash(_targetBlock));
        uint256 rand;

        if (randomN == 0) {

            _targetBlock = (block.number & maskFirst248Bits) + (_targetBlock & maskLast8Bits);

            // The computation above could result in a block LARGER than the current block,
            // if so, subtract 256.
            if (_targetBlock >= block.number) _targetBlock -= 256;

            randomN = uint256(blockhash(_targetBlock));
        }

        // generate 256 bits of random, using as much entropy as we can from
        // sources that can't change between calls.
        randomN = uint256(keccak256(abi.encodePacked(randomN, _genes1, _genes2, _targetBlock)));
        uint256 randomIndex = 0;

        uint8[] memory genes1Array = decode(_genes1);
        uint8[] memory genes2Array = decode(_genes2);
        // All traits that will belong to baby
        uint8[] memory babyArray = new uint8[](48);
        // A pointer to the trait we are dealing with currently
        uint256 traitPos;
        // Trait swap value holder
        uint8 swap;
        // iterate all 12 characteristics
        for(uint256 i = 0; i < 12; i++) {
            // pick 4 traits for characteristic i
            uint256 j;
            // store the current random value
            // uint256 rand;
            for(j = 3; j >= 1; j--) {
                traitPos = (i * 4) + j;

                rand = _sliceNumber(randomN, 2, randomIndex); // 0~3
                randomIndex += 2;

                // 1/4 of a chance of gene swapping forward towards expressing.
                if (rand == 0) {
                    // do it for parent 1
                    swap = genes1Array[traitPos];
                    genes1Array[traitPos] = genes1Array[traitPos - 1];
                    genes1Array[traitPos - 1] = swap;

                }

                rand = _sliceNumber(randomN, 2, randomIndex); // 0~3
                randomIndex += 2;

                if (rand == 0) {
                    // do it for parent 2
                    swap = genes2Array[traitPos];
                    genes2Array[traitPos] = genes2Array[traitPos - 1];
                    genes2Array[traitPos - 1] = swap;
                }
            }
        }

        // We have 256 - 144 = 112 bits of randomness left at this point. We will use up to
        // four bits for the first slot of each trait (three for the possible ascension, one
        // to pick between mom and dad if the ascension fails, for a total of 48 bits. The other
        // traits use one bit to pick between parents (36 gene pairs, 36 genes), leaving us
        // well within our entropy budget.

        // done shuffling parent genes, now let's decide on choosing trait and if ascending.
        // NOTE: Ascensions ONLY happen in the "top slot" of each characteristic. This saves
        //  gas and also ensures ascensions only happen when they're visible.
        for(traitPos = 0; traitPos < 48; traitPos++) {

            // See if this trait pair should ascend
            uint8 ascendedTrait = 0;

            // There are two checks here. The first is straightforward, only the trait
            // in the first slot can ascend. The first slot is zero mod 4.
            //
            // The second check is more subtle: Only values that are one apart can ascend,
            // which is what we check inside the _ascend method. However, this simple mask
            // and compare is very cheap (9 gas) and will filter out about half of the
            // non-ascending pairs without a function call.
            //
            // The comparison itself just checks that one value is even, and the other
            // is odd.
            if ((traitPos % 4 == 0) && (genes1Array[traitPos] & 1) != (genes2Array[traitPos] & 1)) {
                rand = _sliceNumber(randomN, 3, randomIndex);
                randomIndex += 3;

                ascendedTrait = _ascend(genes1Array[traitPos], genes2Array[traitPos], rand);
            }

            if (ascendedTrait > 0) {
                babyArray[traitPos] = uint8(ascendedTrait);
            } else {
                // did not ascend, pick one of the parent's traits for the baby
                // We use the top bit of rand for this (the bottom three bits were used
                // to check for the ascension itself).
                rand = _sliceNumber(randomN, 1, randomIndex);
                randomIndex += 1;

                if (rand == 0) {
                    babyArray[traitPos] = uint8(genes1Array[traitPos]);
                } else {
                    babyArray[traitPos] = uint8(genes2Array[traitPos]);
                }
            }
        }

        return encode(babyArray);
    }
}
        
>

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","payable":false,"inputs":[]},{"type":"event","name":"Approval","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":false},{"type":"address","name":"approved","internalType":"address","indexed":false},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Birth","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":false},{"type":"uint256","name":"PetId","internalType":"uint256","indexed":false},{"type":"uint256","name":"matronId","internalType":"uint256","indexed":false},{"type":"uint256","name":"sireId","internalType":"uint256","indexed":false},{"type":"uint256","name":"genes","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Pregnant","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":false},{"type":"uint256","name":"matronId","internalType":"uint256","indexed":false},{"type":"uint256","name":"sireId","internalType":"uint256","indexed":false},{"type":"uint256","name":"cooldownEndBlock","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","internalType":"address","indexed":false},{"type":"address","name":"to","internalType":"address","indexed":false},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"fallback","stateMutability":"payable","payable":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"PetIndexToApproved","inputs":[{"type":"uint256","name":"","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"PetIndexToOwner","inputs":[{"type":"uint256","name":"","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"amountToAdulthood","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"amountToMiddleAge","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"approve","inputs":[{"type":"address","name":"_to","internalType":"address"},{"type":"uint256","name":"_tokenId","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"approveSiring","inputs":[{"type":"address","name":"_addr","internalType":"address"},{"type":"uint256","name":"_sireId","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"autoBirthFee","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"count","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"_owner","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"bidOnSiringAuction","inputs":[{"type":"uint256","name":"_sireId","internalType":"uint256"},{"type":"uint256","name":"_matronId","internalType":"uint256"},{"type":"uint256","name":"_amount","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"breedWithAuto","inputs":[{"type":"uint256","name":"_matronId","internalType":"uint256"},{"type":"uint256","name":"_sireId","internalType":"uint256"},{"type":"uint256","name":"_amount","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"canBreedWith","inputs":[{"type":"uint256","name":"_matronId","internalType":"uint256"},{"type":"uint256","name":"_sireId","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"cooldowns","inputs":[{"type":"uint256","name":"","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"createGen0Auction","inputs":[{"type":"address","name":"_owner","internalType":"address"},{"type":"uint256","name":"_genes","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"createPet","inputs":[{"type":"address","name":"_owner","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"createPromoPet","inputs":[{"type":"address","name":"_owner","internalType":"address"},{"type":"uint256","name":"_amount","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"createSaleAuction","inputs":[{"type":"uint256","name":"_PetId","internalType":"uint256"},{"type":"uint256","name":"_startingPrice","internalType":"uint256"},{"type":"uint256","name":"_endingPrice","internalType":"uint256"},{"type":"uint256","name":"_duration","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"createSiringAuction","inputs":[{"type":"uint256","name":"_PetId","internalType":"uint256"},{"type":"uint256","name":"_startingPrice","internalType":"uint256"},{"type":"uint256","name":"_endingPrice","internalType":"uint256"},{"type":"uint256","name":"_duration","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"dpetToken","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"feedOnPet","inputs":[{"type":"uint256","name":"_petId","internalType":"uint256"},{"type":"uint256","name":"_amount","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"gen0CreatedCount","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"gen0Price","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"geneScience","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getBalance","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"isGestating","internalType":"bool"},{"type":"bool","name":"isReady","internalType":"bool"},{"type":"uint256","name":"cooldownIndex","internalType":"uint256"},{"type":"uint256","name":"nextActionAt","internalType":"uint256"},{"type":"uint256","name":"siringWithId","internalType":"uint256"},{"type":"uint256","name":"birthTime","internalType":"uint256"},{"type":"uint256","name":"matronId","internalType":"uint256"},{"type":"uint256","name":"sireId","internalType":"uint256"},{"type":"uint256","name":"generation","internalType":"uint256"},{"type":"string","name":"genes","internalType":"string"},{"type":"uint256","name":"stages","internalType":"uint256"}],"name":"getPet","inputs":[{"type":"uint256","name":"_id","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"giveBirth","inputs":[{"type":"uint256","name":"_matronId","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isPregnant","inputs":[{"type":"uint256","name":"_PetId","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isReadyToBreed","inputs":[{"type":"uint256","name":"_PetId","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"owner","internalType":"address"}],"name":"ownerOf","inputs":[{"type":"uint256","name":"_tokenId","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"pause","inputs":[],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"paused","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"pregnantpets","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"contract SaleClockAuction"}],"name":"saleAuction","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"saleAuctionAddr","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"secondsPerBlock","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setAmountToAdulthood","inputs":[{"type":"uint256","name":"_amountToAdulthood","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setAmountToMiddleAge","inputs":[{"type":"uint256","name":"_amountToMiddleAge","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setAutoBirthFee","inputs":[{"type":"uint256","name":"val","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setGeneScienceAddress","inputs":[{"type":"address","name":"_address","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setSaleAuctionAddress","inputs":[{"type":"address","name":"_address","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setSecondsPerBlock","inputs":[{"type":"uint256","name":"secs","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setSiringAuctionAddress","inputs":[{"type":"address","name":"_address","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setStakingContract","inputs":[{"type":"address","name":"_stakingContract","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"sireAllowedToAddress","inputs":[{"type":"uint256","name":"","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"contract SiringClockAuction"}],"name":"siringAuction","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"siringAuctionAddr","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"stakingContract","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"supportsInterface","inputs":[{"type":"bytes4","name":"_interfaceID","internalType":"bytes4"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"string","name":"","internalType":"string"}],"name":"symbol","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256[]","name":"ownerTokens","internalType":"uint256[]"}],"name":"tokensOfOwner","inputs":[{"type":"address","name":"_owner","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSupply","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transfer","inputs":[{"type":"address","name":"_to","internalType":"address"},{"type":"uint256","name":"_tokenId","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferFrom","inputs":[{"type":"address","name":"_from","internalType":"address"},{"type":"address","name":"_to","internalType":"address"},{"type":"uint256","name":"_tokenId","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"unpause","inputs":[],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"updateGen0Price","inputs":[{"type":"uint256","name":"_gen0Price","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"withdrawBalance","inputs":[],"constant":false}]
              

Deployed ByteCode

0x6080604052600436106103815760003560e01c80636fbde40d116101d1578063a376af0f11610102578063e6cbe351116100a0578063f2fde38b1161006f578063f2fde38b14610d98578063f35f7a2614610dcb578063fcca3daa14610df5578063fee983d614610e0a57610381565b8063e6cbe35114610d44578063ee99205c14610d59578063f1ca941014610d6e578063f2b47d5214610d8357610381565b8063b4a31a07116100dc578063b4a31a0714610ca8578063be61219114610cbd578063d3e6f49f14610ce7578063d58d0e1b14610d1157610381565b8063a376af0f14610c45578063a9059cbb14610c5a578063b0c35c0514610c9357610381565b806388c2a0bf1161016f57806395d89b411161014957806395d89b4114610b8a57806399d5175e14610b9f5780639d6fac6f14610bcf5780639dd373b914610c1257610381565b806388c2a0bf14610b155780638da5cb5b14610b3f57806392f64cce14610b5457610381565b80637a7d4937116101ab5780637a7d493714610a535780637d9b6a1514610a685780638456cb5914610a7d5780638462151c14610a9257610381565b80636fbde40d146109b457806370a08231146109e7578063795e153514610a1a57610381565b8063388d67be116102b65780634dfff04f116102545780635c975abb116102235780635c975abb1461094b5780635fd8c710146109605780636352211e146109755780636bbb0f0e1461099f57610381565b80634dfff04f146107ce5780635663896e1461080757806359d55194146108315780635c295f5a1461092157610381565b806346116e6f1161029057806346116e6f1461070e57806346d22c70146107385780634ad8c938146107685780634b85fd55146107a457610381565b8063388d67be146106a85780633d7d3f5a146106bd5780633f4ba83a146106f957610381565b806314001f4c116103235780631ee12453116102fd5780631ee12453146105f357806321717ebf1461061d57806323b872dd1461063257806324e7a38a1461067557610381565b806314001f4c1461058157806318160ddd146105b45780631940a936146105c957610381565b8063095ea7b31161035f578063095ea7b3146104ba5780630d39f99e146104f35780630f47ec221461052457806312065fe01461055a57610381565b8063012a4d80146103af57806301ffc9a7146103e857806306fdde0314610430575b6009546001600160a01b03163314806103a45750600a546001600160a01b031633145b6103ad57600080fd5b005b3480156103bb57600080fd5b506103ad600480360360408110156103d257600080fd5b506001600160a01b038135169060200135610e34565b3480156103f457600080fd5b5061041c6004803603602081101561040b57600080fd5b50356001600160e01b031916610e9d565b604080519115158252519081900360200190f35b34801561043c57600080fd5b50610445611078565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561047f578181015183820152602001610467565b50505050905090810190601f1680156104ac5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156104c657600080fd5b506103ad600480360360408110156104dd57600080fd5b506001600160a01b03813516906020013561109f565b3480156104ff57600080fd5b5061050861111f565b604080516001600160a01b039092168252519081900360200190f35b34801561053057600080fd5b506103ad6004803603606081101561054757600080fd5b508035906020810135906040013561112e565b34801561056657600080fd5b5061056f61146e565b60408051918252519081900360200190f35b34801561058d57600080fd5b506103ad600480360360208110156105a457600080fd5b50356001600160a01b03166114ea565b3480156105c057600080fd5b5061056f6115db565b3480156105d557600080fd5b5061041c600480360360208110156105ec57600080fd5b50356115e5565b3480156105ff57600080fd5b506103ad6004803603602081101561061657600080fd5b503561161d565b34801561062957600080fd5b5061050861166f565b34801561063e57600080fd5b506103ad6004803603606081101561065557600080fd5b506001600160a01b0381358116916020810135909116906040013561167e565b34801561068157600080fd5b506103ad6004803603602081101561069857600080fd5b50356001600160a01b03166116ef565b3480156106b457600080fd5b5061056f61175e565b3480156106c957600080fd5b506103ad600480360360808110156106e057600080fd5b5080359060208101359060408101359060600135611764565b34801561070557600080fd5b506103ad6118b2565b34801561071a57600080fd5b506105086004803603602081101561073157600080fd5b5035611924565b34801561074457600080fd5b5061041c6004803603604081101561075b57600080fd5b508035906020013561193f565b34801561077457600080fd5b506103ad6004803603608081101561078b57600080fd5b50803590602081013590604081013590606001356119be565b3480156107b057600080fd5b506103ad600480360360208110156107c757600080fd5b5035611af0565b3480156107da57600080fd5b506103ad600480360360408110156107f157600080fd5b506001600160a01b038135169060200135611b42565b34801561081357600080fd5b506103ad6004803603602081101561082a57600080fd5b5035611b9a565b34801561083d57600080fd5b5061085b6004803603602081101561085457600080fd5b5035611c00565b604051808c1515151581526020018b1515151581526020018a815260200189815260200188815260200187815260200186815260200185815260200184815260200180602001838152602001828103825284818151815260200191508051906020019080838360005b838110156108dc5781810151838201526020016108c4565b50505050905090810190601f1680156109095780820380516001836020036101000a031916815260200191505b509c5050505050505050505050505060405180910390f35b34801561092d57600080fd5b506105086004803603602081101561094457600080fd5b5035611d26565b34801561095757600080fd5b5061041c611d41565b34801561096c57600080fd5b506103ad611d51565b34801561098157600080fd5b506105086004803603602081101561099857600080fd5b5035611e3c565b3480156109ab57600080fd5b50610508611e5e565b3480156109c057600080fd5b506103ad600480360360208110156109d757600080fd5b50356001600160a01b0316611e6d565b3480156109f357600080fd5b5061056f60048036036020811015610a0a57600080fd5b50356001600160a01b0316611f5e565b348015610a2657600080fd5b506103ad60048036036040811015610a3d57600080fd5b506001600160a01b038135169060200135611f79565b348015610a5f57600080fd5b5061056f612074565b348015610a7457600080fd5b5061056f61207a565b348015610a8957600080fd5b506103ad612080565b348015610a9e57600080fd5b50610ac560048036036020811015610ab557600080fd5b50356001600160a01b03166120f9565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610b01578181015183820152602001610ae9565b505050509050019250505060405180910390f35b348015610b2157600080fd5b5061056f60048036036020811015610b3857600080fd5b50356121c0565b348015610b4b57600080fd5b50610508612470565b348015610b6057600080fd5b506103ad60048036036060811015610b7757600080fd5b508035906020810135906040013561247f565b348015610b9657600080fd5b50610445612721565b348015610bab57600080fd5b506103ad60048036036040811015610bc257600080fd5b5080359060200135612740565b348015610bdb57600080fd5b50610bf960048036036020811015610bf257600080fd5b5035612904565b6040805163ffffffff9092168252519081900360200190f35b348015610c1e57600080fd5b506103ad60048036036020811015610c3557600080fd5b50356001600160a01b0316612931565b348015610c5157600080fd5b5061056f6129a0565b348015610c6657600080fd5b506103ad60048036036040811015610c7d57600080fd5b506001600160a01b0381351690602001356129a6565b348015610c9f57600080fd5b5061056f612a3a565b348015610cb457600080fd5b5061056f612a40565b348015610cc957600080fd5b506103ad60048036036020811015610ce057600080fd5b5035612a46565b348015610cf357600080fd5b5061041c60048036036020811015610d0a57600080fd5b5035612a98565b348015610d1d57600080fd5b506103ad60048036036020811015610d3457600080fd5b50356001600160a01b0316612b59565b348015610d5057600080fd5b50610508612bc6565b348015610d6557600080fd5b50610508612bd5565b348015610d7a57600080fd5b5061056f612be4565b348015610d8f57600080fd5b50610508612bea565b348015610da457600080fd5b506103ad60048036036020811015610dbb57600080fd5b50356001600160a01b0316612bf9565b348015610dd757600080fd5b5061050860048036036020811015610dee57600080fd5b5035612c74565b348015610e0157600080fd5b50610508612c8f565b348015610e1657600080fd5b506103ad60048036036020811015610e2d57600080fd5b5035612c9e565b6000546001600160a01b03163314610e81576040805162461bcd60e51b815260206004820181905260248201526000805160206135df833981519152604482015290519081900360640190fd5b600f80546001019055610e98600080808486612cf0565b505050565b604080517f737570706f727473496e74657266616365286279746573342900000000000000815290519081900360190190206000906001600160e01b0319838116911614806110705750604080517f746f6b656e4d657461646174612875696e743235362c737472696e67290000008152815190819003601d01812075746f6b656e734f664f776e657228616464726573732960501b82529151908190036016018120908060256135ba8239604080519182900360250182207f7472616e7366657228616464726573732c75696e743235362900000000000000835281519283900360190183207f617070726f766528616464726573732c75696e74323536290000000000000000845282519384900360180184206f6f776e65724f662875696e743235362960801b855283519485900360100185207162616c616e63654f6628616464726573732960701b865284519586900360120186206c746f74616c537570706c79282960981b8752855196879003600d0187206773796d626f6c282960c01b88528651978890036008018820656e616d65282960d01b89529651978890036006019097206001600160e01b03198d81169190971890971818181818189390931893909318919091169190911490505b90505b919050565b6040518060400160405280600b81526020016a135e481119519a4814195d60aa1b81525081565b600054600160a01b900460ff16156110b657600080fd5b6110c03382612f2e565b6110c957600080fd5b6110d38183612f4e565b604080513381526001600160a01b038416602082015280820183905290517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259181900360600190a15050565b600b546001600160a01b031681565b600054600160a01b900460ff161561114557600080fd5b600b54604080516323b872dd60e01b81523360048201523060248201526044810184905290516001600160a01b03909216916323b872dd916064808201926020929091908290030181600087803b15801561119f57600080fd5b505af11580156111b3573d6000803e3d6000fd5b505050506040513d60208110156111c957600080fd5b50516111d457600080fd5b6111de3383612f2e565b611222576040805162461bcd60e51b815260206004820152601060248201526f2737ba1036b0ba3937b71037bbb732b960811b604482015290519081900360640190fd5b61122b82612a98565b611271576040805162461bcd60e51b8152602060048201526012602482015271139bdd081c9958591e481d1bc8189c99595960721b604482015290519081900360640190fd5b61127b8284612f7c565b6112cc576040805162461bcd60e51b815260206004820152601c60248201527f43616e27742062726565642077697468207669612061756374696f6e00000000604482015290519081900360640190fd5b600a54604080516362ae87ab60e11b81526004810186905290516000926001600160a01b03169163c55d0f56916024808301926020929190829003018186803b15801561131857600080fd5b505afa15801561132c573d6000803e3d6000fd5b505050506040513d602081101561134257600080fd5b5051600c54909150810182101561135857600080fd5b600b546015546040805163a9059cbb60e01b81526001600160a01b039283166004820152602481018690529051919092169163a9059cbb9160448083019260209291908290030181600087803b1580156113b157600080fd5b505af11580156113c5573d6000803e3d6000fd5b505050506040513d60208110156113db57600080fd5b50516113e657600080fd5b600a5460408051630b30c8ff60e31b8152600481018790526024810185905290516001600160a01b039092169163598647f89160448082019260009290919082900301818387803b15801561143a57600080fd5b505af115801561144e573d6000803e3d6000fd5b505050506114688363ffffffff168563ffffffff16612fc7565b50505050565b600b54604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b1580156114b957600080fd5b505afa1580156114cd573d6000803e3d6000fd5b505050506040513d60208110156114e357600080fd5b5051905090565b6000546001600160a01b03163314611537576040805162461bcd60e51b815260206004820181905260248201526000805160206135df833981519152604482015290519081900360640190fd5b6000819050806001600160a01b03166376190f8f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561157557600080fd5b505afa158015611589573d6000803e3d6000fd5b505050506040513d602081101561159f57600080fd5b50516115aa57600080fd5b600a80546001600160a01b039283166001600160a01b03199182161790915560158054939092169216919091179055565b6004546000190190565b60008082116115f357600080fd5b6004828154811061160057fe5b906000526020600020906006020160040154600014159050919050565b6000546001600160a01b0316331461166a576040805162461bcd60e51b815260206004820181905260248201526000805160206135df833981519152604482015290519081900360640190fd5b601055565b600a546001600160a01b031681565b600054600160a01b900460ff161561169557600080fd5b6001600160a01b0382166116a857600080fd5b6001600160a01b0382163014156116be57600080fd5b6116c833826130d4565b6116d157600080fd5b6116db8382612f2e565b6116e457600080fd5b610e988383836130f4565b6000546001600160a01b0316331461173c576040805162461bcd60e51b815260206004820181905260248201526000805160206135df833981519152604482015290519081900360640190fd5b600e80546001600160a01b0319166001600160a01b0392909216919091179055565b600d5481565b600054600160a01b900460ff161561177b57600080fd5b6117853385612f2e565b6117c8576040805162461bcd60e51b815260206004820152600f60248201526e2737ba102832ba24b21037bbb732b960891b604482015290519081900360640190fd5b6117d1846115e5565b15611815576040805162461bcd60e51b815260206004820152600f60248201526e14195d081a5cc81c1c9959db985b9d608a1b604482015290519081900360640190fd5b60095461182c9085906001600160a01b0316612f4e565b600954604080516313f5f20560e11b81526004810187905260248101869052604481018590526064810184905233608482015290516001600160a01b03909216916327ebe40a9160a48082019260009290919082900301818387803b15801561189457600080fd5b505af11580156118a8573d6000803e3d6000fd5b5050505050505050565b6000546001600160a01b031633146118ff576040805162461bcd60e51b815260206004820181905260248201526000805160206135df833981519152604482015290519081900360640190fd5b600054600160a01b900460ff1661191557600080fd5b6000805460ff60a01b19169055565b6008602052600090815260409020546001600160a01b031681565b600080831161194d57600080fd5b6000821161195a57600080fd5b60006004848154811061196957fe5b9060005260206000209060060201905060006004848154811061198857fe5b906000526020600020906006020190506119a4828683876131d6565b80156119b557506119b584866132ac565b95945050505050565b600054600160a01b900460ff16156119d557600080fd5b6119df3385612f2e565b611a22576040805162461bcd60e51b815260206004820152600f60248201526e2737ba102832ba24b21037bbb732b960891b604482015290519081900360640190fd5b611a2b84612a98565b611a71576040805162461bcd60e51b8152602060048201526012602482015271139bdd081c9958591e481d1bc8189c99595960721b604482015290519081900360640190fd5b600a54611a889085906001600160a01b0316612f4e565b600a54604080516313f5f20560e11b81526004810187905260248101869052604481018590526064810184905233608482015290516001600160a01b03909216916327ebe40a9160a48082019260009290919082900301818387803b15801561189457600080fd5b6000546001600160a01b03163314611b3d576040805162461bcd60e51b815260206004820181905260248201526000805160206135df833981519152604482015290519081900360640190fd5b600c55565b600054600160a01b900460ff1615611b5957600080fd5b611b633382612f2e565b611b6c57600080fd5b600090815260086020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314611be7576040805162461bcd60e51b815260206004820181905260248201526000805160206135df833981519152604482015290519081900360640190fd5b60015463ffffffff168110611bfb57600080fd5b600355565b6000806000806000806000806000606060008060048d81548110611c2057fe5b906000526020600020906006020190508060040154600014159b50438160010160089054906101000a90046001600160401b03166001600160401b031611159a508060050160009054906101000a900461ffff1661ffff1699508060010160089054906101000a90046001600160401b03166001600160401b03169850806004015497508060010160009054906101000a90046001600160401b03166001600160401b0316965080600201549550806003015494508060050160029054906101000a900461ffff1661ffff169350611cfb8160000154613301565b92508060050160049054906101000a900461ffff1661ffff1691505091939597999b90929496989a50565b6005602052600090815260409020546001600160a01b031681565b600054600160a01b900460ff1681565b6000546001600160a01b03163314611d9e576040805162461bcd60e51b815260206004820181905260248201526000805160206135df833981519152604482015290519081900360640190fd5b600b546000546001600160a01b039182169163a9059cbb9116611dbf61146e565b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b158015611e0e57600080fd5b505af1158015611e22573d6000803e3d6000fd5b505050506040513d6020811015611e3857600080fd5b5050565b6000818152600560205260409020546001600160a01b03168061107357600080fd5b6016546001600160a01b031681565b6000546001600160a01b03163314611eba576040805162461bcd60e51b815260206004820181905260248201526000805160206135df833981519152604482015290519081900360640190fd5b6000819050806001600160a01b03166385b861886040518163ffffffff1660e01b815260040160206040518083038186803b158015611ef857600080fd5b505afa158015611f0c573d6000803e3d6000fd5b505050506040513d6020811015611f2257600080fd5b5051611f2d57600080fd5b600980546001600160a01b039283166001600160a01b03199182161790915560168054939092169216919091179055565b6001600160a01b031660009081526006602052604090205490565b601054811015611fc1576040805162461bcd60e51b815260206004820152600e60248201526d1253959053125108105353d5539560921b604482015290519081900360640190fd5b600b54604080516323b872dd60e01b81523360048201523060248201526044810184905290516001600160a01b03909216916323b872dd916064808201926020929091908290030181600087803b15801561201b57600080fd5b505af115801561202f573d6000803e3d6000fd5b505050506040513d602081101561204557600080fd5b505161205057600080fd5b600f8054600101905560006120636133c5565b905061146860008060008487612cf0565b60035481565b60105481565b6000546001600160a01b031633146120cd576040805162461bcd60e51b815260206004820181905260248201526000805160206135df833981519152604482015290519081900360640190fd5b600054600160a01b900460ff16156120e457600080fd5b6000805460ff60a01b1916600160a01b179055565b6060600061210683611f5e565b905080612123575050604080516000815260208101909152611073565b60608160405190808252806020026020018201604052801561214f578160200160208202803883390190505b509050600061215c6115db565b9050600060015b8281116121b3576000818152600560205260409020546001600160a01b03888116911614156121ab578084838151811061219957fe5b60209081029190910101526001909101905b600101612163565b8395505050505050611073565b60008054600160a01b900460ff16156121d857600080fd5b6000600483815481106121e757fe5b6000918252602090912060069091020160018101549091506001600160401b0316612247576040805162461bcd60e51b815260206004820152600b60248201526a125b9d985b1a59081c195d60aa1b604482015290519081900360640190fd5b60408051610120810182528254815260018301546001600160401b038082166020840152600160401b90910416918101919091526002820154606082015260038201546080820152600482015460a0820152600582015461ffff80821660c0840152620100008204811660e0840152600160201b909104166101008201526122ce90613448565b612311576040805162461bcd60e51b815260206004820152600f60248201526e09cdee840e4cac2c8f240c4d2e4e8d608b1b604482015290519081900360640190fd5b60008160040154905060006004828154811061232957fe5b6000918252602090912060058086015460069093029091019081015490925061ffff6201000092839004811692909104168110156123725750600581015462010000900461ffff165b600e5484548354600187015460408051630d9f5aed60e01b8152600481019490945260248401929092526000196001600160401b03600160401b909204821601166044830152516000926001600160a01b031691630d9f5aed916064808301926020929190829003018186803b1580156123eb57600080fd5b505afa1580156123ff573d6000803e3d6000fd5b505050506040513d602081101561241557600080fd5b505160008881526005602052604081205460048801549293506001600160a01b03169161244d908a9061ffff60018801168686612cf0565b60006004909801979097555050600d805460001901905550929350505050919050565b6000546001600160a01b031681565b600054600160a01b900460ff161561249657600080fd5b600c548110156124dc576040805162461bcd60e51b815260206004820152600c60248201526b135d5cdd081c185e5b595b9d60a21b604482015290519081900360640190fd5b600b54604080516323b872dd60e01b81523360048201523060248201526044810184905290516001600160a01b03909216916323b872dd916064808201926020929091908290030181600087803b15801561253657600080fd5b505af115801561254a573d6000803e3d6000fd5b505050506040513d602081101561256057600080fd5b505161256b57600080fd5b6125753384612f2e565b61257e57600080fd5b61258882846132ac565b61259157600080fd5b6000600484815481106125a057fe5b6000918252602091829020604080516101208101825260069093029091018054835260018101546001600160401b0380821695850195909552600160401b9004909316908201526002820154606082015260038201546080820152600482015460a0820152600582015461ffff80821660c0840152620100008204811660e0840152600160201b9091041661010082015290915061263d90613471565b61264657600080fd5b60006004848154811061265557fe5b6000918252602091829020604080516101208101825260069093029091018054835260018101546001600160401b0380821695850195909552600160401b9004909316908201526002820154606082015260038201546080820152600482015460a0820152600582015461ffff80821660c0840152620100008204811660e0840152600160201b909104166101008201529091506126f290613471565b6126fb57600080fd5b612707828683876131d6565b61271057600080fd5b61271a8585612fc7565b5050505050565b6040518060400160405280600381526020016204d44560ec1b81525081565b600b54604080516323b872dd60e01b81523360048201523060248201526044810184905290516001600160a01b03909216916323b872dd916064808201926020929091908290030181600087803b15801561279a57600080fd5b505af11580156127ae573d6000803e3d6000fd5b505050506040513d60208110156127c457600080fd5b50516127cf57600080fd5b6000600483815481106127de57fe5b90600052602060002090600602019050601354821415612877576005810154600160201b900461ffff1660011461284e576040805162461bcd60e51b815260206004820152600f60248201526e494e56414c4944205354414745203160881b604482015290519081900360640190fd5b60058101805461ffff600160201b80830482166001019091160265ffff00000000199091161790555b601454821415610e98576005810154600160201b900461ffff166002146128d7576040805162461bcd60e51b815260206004820152600f60248201526e24a72b20a624a21029aa20a3a2901960891b604482015290519081900360640190fd5b60058101805461ffff600160201b80830482166001019091160265ffff0000000019909116179055505050565b600181600e811061291157fe5b60089182820401919006600402915054906101000a900463ffffffff1681565b6000546001600160a01b0316331461297e576040805162461bcd60e51b815260206004820181905260248201526000805160206135df833981519152604482015290519081900360640190fd5b601180546001600160a01b0319166001600160a01b0392909216919091179055565b60135481565b600054600160a01b900460ff16156129bd57600080fd5b6001600160a01b0382166129d057600080fd5b6001600160a01b0382163014156129e657600080fd5b6009546001600160a01b0383811691161415612a0157600080fd5b600a546001600160a01b0383811691161415612a1c57600080fd5b612a263382612f2e565b612a2f57600080fd5b611e383383836130f4565b600c5481565b60145481565b6000546001600160a01b03163314612a93576040805162461bcd60e51b815260206004820181905260248201526000805160206135df833981519152604482015290519081900360640190fd5b601455565b6000808211612aa657600080fd5b600060048381548110612ab557fe5b6000918252602091829020604080516101208101825260069093029091018054835260018101546001600160401b0380821695850195909552600160401b9004909316908201526002820154606082015260038201546080820152600482015460a0820152600582015461ffff80821660c0840152620100008204811660e0840152600160201b90910416610100820152909150612b5290613471565b9392505050565b6011546001600160a01b03163314612ba25760405162461bcd60e51b815260040180806020018281038252602b81526020018061358f602b913960400191505060405180910390fd5b600f805460010190556000612bb56133c5565b9050610e9860008060008486612cf0565b6009546001600160a01b031681565b6011546001600160a01b031681565b600f5481565b600e546001600160a01b031681565b6000546001600160a01b03163314612c46576040805162461bcd60e51b815260206004820181905260248201526000805160206135df833981519152604482015290519081900360640190fd5b6001600160a01b03811615612c7157600080546001600160a01b0319166001600160a01b0383161790555b50565b6007602052600090815260409020546001600160a01b031681565b6015546001600160a01b031681565b6000546001600160a01b03163314612ceb576040805162461bcd60e51b815260206004820181905260248201526000805160206135df833981519152604482015290519081900360640190fd5b601355565b600060028404600d61ffff82161115612d075750600d5b612d0f613542565b604051806101200160405280868152602001426001600160401b0316815260200160006001600160401b031681526020018963ffffffff1681526020018863ffffffff168152602001600081526020018361ffff1681526020018761ffff168152602001600161ffff16815250905060006001600483908060018154018082558091505090600182039060005260206000209060060201600090919290919091506000820151816000015560208201518160010160006101000a8154816001600160401b0302191690836001600160401b0316021790555060408201518160010160086101000a8154816001600160401b0302191690836001600160401b03160217905550606082015181600201556080820151816003015560a0820151816004015560c08201518160050160006101000a81548161ffff021916908361ffff16021790555060e08201518160050160026101000a81548161ffff021916908361ffff1602179055506101008201518160050160046101000a81548161ffff021916908361ffff16021790555050500390507f0a5311bd2a6608f08a180df2ee7c5946819a649b204b554bb8e39825b2c50ad5858284606001518560800151866000015160405180866001600160a01b03166001600160a01b031681526020018581526020018481526020018381526020018281526020019550505050505060405180910390a1612f22600086836130f4565b98975050505050505050565b6000908152600560205260409020546001600160a01b0391821691161490565b60009182526007602052604090912080546001600160a01b0319166001600160a01b03909216919091179055565b60008060048481548110612f8c57fe5b90600052602060002090600602019050600060048481548110612fab57fe5b906000526020600020906006020190506119b5828683876131d6565b600060048281548110612fd657fe5b90600052602060002090600602019050600060048481548110612ff557fe5b906000526020600020906006020190508263ffffffff16816004018190555061301d82613499565b61302681613499565b600084815260086020908152604080832080546001600160a01b031990811690915586845281842080549091169055600d805460019081019091558784526005835292819020549284015481516001600160a01b039094168452918301879052828101869052600160401b9091046001600160401b03166060830152517f241ea03ca20251805084d27d4440371c34a0b85ff108f6bb5611248f73818b80916080908290030190a150505050565b6000908152600760205260409020546001600160a01b0391821691161490565b6001600160a01b038083166000818152600660209081526040808320805460010190558583526005909152902080546001600160a01b0319169091179055831615613187576001600160a01b038316600090815260066020908152604080832080546000190190558383526008825280832080546001600160a01b03199081169091556007909252909120805490911690555b604080516001600160a01b0380861682528416602082015280820183905290517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360600190a1505050565b6000818414156131e8575060006132a4565b81856002015414806131fd5750818560030154145b1561320a575060006132a4565b838360020154148061321f5750838360030154145b1561322c575060006132a4565b6002830154158061323f57506002850154155b1561324c575060016132a4565b846002015483600201541480613269575084600301548360020154145b15613276575060006132a4565b846002015483600301541480613293575084600301548360030154145b156132a0575060006132a4565b5060015b949350505050565b60008181526005602052604080822054848352908220546001600160a01b039182169116808214806119b557506000858152600860205260409020546001600160a01b03908116908316149250505092915050565b606081806133285750506040805180820190915260018152600360fc1b6020820152611073565b8060005b811561334057600101600a8204915061332c565b6060816040519080825280601f01601f19166020018201604052801561336d576020820181803883390190505b50905060001982015b84156133bb57600a850660300160f81b8282806001900393508151811061339957fe5b60200101906001600160f81b031916908160001a905350600a85049450613376565b5095945050505050565b6012805460408051434060208083019190915242828401526060808301859052835180840390910181526080909201909252805191012060019091019091557d90e40fbeea1d3a4abc8955e946fe31cdcf66f634e100000000000000000090067d0e7d34c64a9c85d4460dbbca87196b61618a4bd2168000000000000000000190565b60008160a00151600014158015611070575050604001516001600160401b034381169116111590565b60008160a001516000148015611070575050604001516001600160401b034381169116111590565b600354600582015443919060019061ffff16600e81106134b557fe5b600891828204019190066004029054906101000a900463ffffffff1663ffffffff16816134de57fe5b6001840180546fffffffffffffffff00000000000000001916600160401b93909204939093016001600160401b0316919091021790556005810154600d61ffff9091161015612c7157600501805461ffff8082166001011661ffff19909116179055565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101919091529056fe4f776e61626c653a2063616c6c6572206973206e6f7420746865207374616b696e6720636f6e74726163747472616e7366657246726f6d28616464726573732c616464726573732c75696e74323536294f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572a265627a7a72315820d9dc322dc23884a0eda3010b0bcad8e2e3f7f61fdd1e593ba6af9cfbfbfe703f64736f6c63430005110032