Assignment - DNA Mixing

Here is my code…
assignment DNA Mixing

breed()
function breed(uint256 _dadId, uint256 _mumId) public returns (uint256) {
        //check ownership
        require(_owns(msg.sender, _dadId) && _owns(msg.sender, _mumId), "You must own both parents in order to breed");
        
        //check you got newDna from _mixDna
        uint256 newDna = _mixDna(kitties[_dadId].genes, kitties[_mumId].genes);
        
        //figure out generation
        uint256 newGen;
        if (kitties[_dadId].generation == kitties[_mumId].generation) {
            newGen = kitties[_mumId].generation++;
        } else if (kitties[_dadId].generation < kitties[_mumId].generation) {
            newGen = kitties[_dadId].generation++;
        } else {
            newGen = (kitties[_dadId].generation + kitties[_mumId].generation) /2 + 1;
        }
        
        //create a new cat with new properties, give it to msg.sender
        _createKitty(_mumId, _dadId, newGen, newDna, msg.sender); 
    }
_mixDna()
function _mixDna(uint256 _dadDna, uint256 _mumDna) internal pure returns (uint256) {
        //dadDna: 11 22 33 44 55 66 77 88
        //mumDna: 88 77 66 55 44 33 22 11

        uint256 firstHalf = _dadDna / 100000000; //11223344
        uint256 secondHalf = _mumDna % 100000000; //44332211

        uint256 newDna = firstHalf * 100000000;
        newDna = newDna + secondHalf; //1122334444332211
        return newDna;
    }
1 Like

I need some help. I’m not sure if I missed the lesson where this was described or maybe I’m missing something obvious.
The lesson goes from working on the factory page to suddenly having multiple pages where the cat is drawn multiple times. I don’t understand how to get the cat drawn multiple times with different dna.
please help

Yeah, looks like half (or more???) the explanations are missing in the last part of the course. Bit disappointed here. Spending so much time on the front-end (in which we’re not very interested in), and then pretty much nothing on web3 and how to link the front-end with our smart-contract…

Basically, from the Cat factory, you have to figure on your own how:

  • to build the rest of the front-end,
  • to show your cats in the catalogue,
  • to display the breeding tab,
  • to add all event listeners from your smart-contract (and to add functions to your contract when/if needed)
  • to code the marketplace contract (we do have the interface)
  • to build the marketplace page

I’m sure I forgot a few things, but that’s definitely a BIG jump. Anyway, was thinking about querying Chainlink oracle for a true random number in my upgraded breeding function, but I guess this would have to wait until I filled all the missing parts! :joy:

Hey @walter_w, hope you are well.

Could you please explain a little bit about the error that your code have?

About the other pages, there are meant to be build by the student, although you can get help here if you face any issue over the journey.

Carlos Z

I’m not getting an error, I don’t know how to draw the cat multiple times with css & html.
Can you supply the solution files since its not the focus of the assignment?

Thanks @thecil, I appreciate the offer. The thing is, building a couple of html pages isn’t really the issue. But things like how to keep your instance var after changing page (haven’t figure it out yet, found a nice way around eventually), or some hints about how to render your cat when fetching data from the blockchain. I mean, those are not necessarily obvious for new born dev :sweat_smile:

@thecil, can I get some help drawing the cats multiple times with css & html?
Its been 5 days since I asked for help with this

hey @walter_w ! Check out this answer where I explain how to render multiple cats.

hi guys,

heres my code for function breed

function breed(uint dadId, uint mumId) public returns(uint256){
        //check ownership
        require(_owes(msg.sender, dadId));
        require(_owes(msg.sender, mumId));
        
        Doggie memory _dadId = doggies[dadId];
        uint dadDna = _dadId.genes;
        Doggie memory _mumId = doggies[mumId];
        uint mumDna = _mumId.genes;
        uint newDna = _mixDna(dadDna, mumDna);
        //figure out generation
        uint16 _generation = _dadId.generation + 1;
            
        //create new Dog with new properties and give it to the msg.sender
         _createDoggie(mumId, dadId, _generation, newDna, msg.sender);
    }
2 Likes
breed function
function breed(uint256 dadId, uint256 mumId) public returns (uint256) {
        Kitty storage dad = kitties[dadId];
        Kitty storage mum = kitties[mumId];

        require(
            kittyIndexToOwner[dadId] == msg.sender &&
            kittyIndexToOwner[mumId] == msg.sender,
             "Owner must own tokens");

        require(
            dad.generation == mum.generation,
            "Only cats from same generation can procreate");


        uint256 dadDna = dad.genes;
        uint256 mumDna = mum.genes;
        uint256 newDna = _mixDna(dadDna, mumDna);

        uint16 newGeneration = dad.generation + 1;

        return _createKitty(mumId, dadId, newGeneration, newDna, msg.sender);
    }```

1 Like
    function breed(uint256 _dadId, uint256 _mumId) public returns (uint256 newKittenId){
        //Check ownership
        require(_owns(msg.sender, _dadId));
        require(_owns(msg.sender, _mumId)); 
        //You got the DNA
        uint256 newDna = _mixDna(_dadId, _mumId);
        //Figure out the Generation
        uint256 _generation;

        if(kitties[_mumId].generation == kitties[_dadId].generation){
            _generation = kitties[_mumId].generation++;
        }
        else if (kitties[_mumId].generation < kitties[_dadId].generation)
        {
            _generation = kitties[_mumId].generation++;
        }
        else{
            _generation = (kitties[_mumId].generation + kitties[_dadId].generation) / 2 + 1;
        }

        //Create a new cat with the new properties, give it to the msg.sender
        return newKittenId = _createKitty(_mumId, _dadId, _generation, newDna, msg.sender);
    }
1 Like

Did you ever get help with this? Struggling to have the array of owned nft’s appear when loading a catalogue page. Way too much time wasted.

Yeah, the catalogue is a tricky part. You can’t use the same code that what we used for the factory (not without adjustments at least).
You can try to check a few completed projects from Assignment - Marketplace Frontend to try to understand how it works. That’s what I’ve done.

My code is slightly different. Does it work? I had to take out “returns(uint)” because the function doesn’t return anything and I got an warning while compiling.

    function breed(uint _mumId, uint _dadId) public {
        //Check ownership of mum and dad
        require(ownership[_mumId] == msg.sender, "Mum cat does not belong to msg.sender");
        require(ownership[_dadId] == msg.sender, "Dad cat does not belong to msg.sender");

        //You got the DNA
        uint _mumDNA = allTokens[_mumId].genes;
        uint _dadDNA = allTokens[_dadId].genes;
        uint newDNA = _mixDNA(_mumDNA, _dadDNA);

        //Figure out the generation of new cat
        //I took the average of the parents and added one
        uint newKittyGen = ((allTokens[_mumId].generation + allTokens[_dadId].generation) / 2) + 1;

        //Create a new cat with the new properties, transfer it to the msg.sender
        _createKitty(_mumId, _dadId, newKittyGen, newDNA, msg.sender);
     
    }

hey @Emerald_Coast did you try to run this function?

Here it is with some pseudo-randomness (DNA mixing functions are at the bottom of the contract).

There’s something about this contract that’s been bothering me, maybe someone can explain. Why isn’t the ‘kittenId’ stored in the actual Kitty struct? I know it’s not entirely necessary, but wouldn’t it be pretty helpful for users to be able to easily find the Id of each token?

pragma solidity 0.8.0;

// import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "./Ownable.sol";

contract Kittycontract is Ownable {

    string public constant tickerName = "ThePowerOfMeow";
    string public constant tickerSymbol = "MEOW";
    bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;
    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
    uint256 totalTokenCount;

    bytes4 internal constant MAGIC_ERC721_RECEIVED = bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"));

    uint256 public constant CREATION_LIMIT_GEN0 = 10;
    uint256 public gen0Counter = 0;

    event Birth(
      address owner,
      uint256 kittenId,
      uint256 matronId,
      uint256 sireId,
      uint256 genes
    );

    struct Kitty {
        uint256 genes;
        uint64 birthTime;
        uint32 matronId;
        uint32 sireId;
        uint16 generation;
    }

    Kitty[] kitties;

    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    mapping(address => uint256) private ownershipTokenCount;
    mapping(uint256 => address) public ownedBy;

    mapping(uint256 => address) public kittyIndexToApproved;
    mapping(address => mapping(address => bool)) private _operatorApprovals;

    function supportsInterface(bytes4 _interfaceId) external pure returns(bool){
        return(_interfaceId == _INTERFACE_ID_ERC721 || _interfaceId == _INTERFACE_ID_ERC165);
    }

    function _createKitty(
      uint256 _matronId,
      uint256 _sireId,
      uint256 _generation,
      uint256 _genes,
      address _owner
    ) private returns(uint256) {
        Kitty memory _kitty = Kitty({
            genes: _genes,
            birthTime: uint64(block.timestamp),
            matronId:uint32(_matronId),
            sireId: uint32(_sireId),
            generation: uint16(_generation)
        });
        kitties.push(_kitty);
        uint256 newKittenId = kitties.length - 1;
        emit Birth(_owner, newKittenId, _matronId, _sireId, _genes);
        _transfer(address(0), _owner, newKittenId);
        return newKittenId;
    }

    function createKittyGen0(uint256 _genes) public onlyOwner returns(uint256 id){
        require(gen0Counter < CREATION_LIMIT_GEN0, "Maximum Gen0 limit reached");
        gen0Counter++;
        return _createKitty(0, 0, 0, _genes, msg.sender);
    }

    function breed(uint256 matronId, uint256 sireId) public {
        //check ownership
        require(ownedBy[matronId] == msg.sender && ownedBy[sireId] == msg.sender);
        //New DNA function
        uint256 newGenes = mixDna(kitties[matronId].genes, kitties[sireId].genes);
        //figure out the generation
        uint256 newGeneration;
        if(kitties[matronId].generation > kitties[sireId].generation) {
            newGeneration = kitties[matronId].generation + 1;
        } else {
            newGeneration = kitties[sireId].generation + 1;
        }
        //create new cat, give it to msg.sender
        _createKitty(matronId, sireId, newGeneration, newGenes, msg.sender);
    }



    function getKitty(uint kittenId) public view returns(Kitty memory) {
        return kitties[kittenId];
    }

    function balanceOf(address owner) external view returns(uint256 balance) {
        return ownershipTokenCount[owner];
    }

    function totalSupply() external view returns (uint256 total) {
        return kitties.length;
    }

    function name() external pure returns (string memory tokenName) {
        return tickerName;
    }

    function symbol() external pure returns (string memory tokenSymbol) {
        return tickerSymbol;
    }

    function ownerOf(uint256 tokenId) external view returns (address owner) {
        address tokenOwner = ownedBy[tokenId];
        require(tokenId < kitties.length, "Token does not exist");
        return tokenOwner;
    }

    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external {
        require(validateOperator(msg.sender, tokenId) || kittyIndexToApproved[tokenId] == msg.sender, "Unauthorized operator");
        require(to != address(0), "Invalid recipient, cannot transfer to zero addres");
        _safeTransfer(from, to, tokenId, data);
    }

    function safeTransferFrom(address from, address to, uint256 tokenId) external {
      require(validateOperator(msg.sender, tokenId) || kittyIndexToApproved[tokenId] == msg.sender, "Unauthorized operator");
      require(to != address(0), "Invalid recipient, cannot transfer to zero addres");
      _safeTransfer(from, to, tokenId, "");
    }

    function _safeTransfer(address _from, address _to, uint256 _tokenId, bytes memory _data) internal {
        _transfer(_from, _to, _tokenId);
        require(_checkIERC721Support(_from, _to, _tokenId, _data));
    }

    function transfer(address to, uint256 tokenId) external {
        require(to != address(0), "Invalid recipient, cannot transfer to zero addres");
        require(to != address(this), "Invalid recipient, cannot transfer to this contract");
        require(to != msg.sender, "Invalid recipient, you cannot transfer to yourself");
        require(ownedBy[tokenId] == msg.sender, "Transfer function is only for token owner, operator should use transferFrom");
        _transfer(msg.sender, to, tokenId);
    }

    function _transfer(address _from, address _to, uint256 _tokenId) internal {
        ownershipTokenCount[_to]++;
        if(_from != address(0)){
            ownershipTokenCount[_from]--;
            delete kittyIndexToApproved[_tokenId];
        }
        ownedBy[_tokenId] = _to;
        emit Transfer(_from, _to, _tokenId);
    }

    function approve(address approved, uint256 tokenId) external {
        require(ownedBy[tokenId] != address(0));
        require(validateOperator(msg.sender, tokenId), "Only token owner or authorized operator can approve");
        _approve(ownedBy[tokenId], approved, tokenId);
    }

    function _approve(address _owner, address _approved, uint256 _tokenId) internal {
        kittyIndexToApproved[_tokenId] = _approved;
        emit Approval(_owner, _approved, _tokenId);
    }

    function setApprovalForAll(address operator, bool approved) external {
        require(operator != msg.sender, "Operator must be a third party");
        _setApprovalForAll(operator, approved);
    }

    function _setApprovalForAll(address _operator, bool _approved) internal {
        _operatorApprovals[msg.sender][_operator] = _approved;
        emit ApprovalForAll(msg.sender, _operator, _approved);
    }

    function getApproved(uint256 tokenId) public view returns (address) {
        require(tokenId < kitties.length, "Token does not exist");
        return kittyIndexToApproved[tokenId];
    }

    function isApprovedForAll(address _owner, address _operator) public view returns (bool) {
        return _operatorApprovals[_owner][_operator];
    }

    function transferFrom(address from, address to, uint256 tokenId) external {
        require(validateOperator(msg.sender, tokenId) || kittyIndexToApproved[tokenId] == msg.sender, "Unauthorized operator");
        require(from == ownedBy[tokenId], "Can only transfer from token owner");
        require(to != address(0), "Token has no owner");
        require(tokenId < kitties.length, "Token does not exist");
        _transfer(from, to, tokenId);
    }

    function validateOperator(address _operator, uint _tokenId) internal view returns(bool) {
        bool validOperator = false;
        address tokenOwner = ownedBy[_tokenId];
        if(tokenOwner == _operator){
            validOperator = true;
        }
        else if(_operatorApprovals[tokenOwner][_operator] == true){
            validOperator = true;
        }
        return validOperator;
    }

    function _checkIERC721Support(address _from, address _to, uint256 _tokenId, bytes memory _data) internal returns(bool) {
        if(!_isContract(_to)){ // if _to is NOT a contract, that means it's a wallet and all is well
            return true;
        }
        bytes4 returnData = IERC721Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data);
        return returnData == MAGIC_ERC721_RECEIVED;
    }

    function _isContract(address _to) internal view returns(bool) {
        //check if address _to code size is > 0, which means it's a contract rather than a wallet
        uint32 size;
        assembly{
            size := extcodesize(_to)
        }
        return size > 0;
    }

    function mixDna(uint256 matronDna, uint256 sireDna) internal returns(uint256) {
        return mixDnaColors(matronDna, sireDna) + mixDnaCattributes(matronDna, sireDna);
    }

    function mixDnaColors(uint256 matronDna, uint256 sireDna) internal view returns(uint256){

        uint256 dnaBodyColor;
        if( uint256(keccak256(abi.encodePacked(matronDna, sireDna, block.timestamp -1))) % 2 == 0){
            dnaBodyColor = matronDna / 100000000000000;
        } else {
            dnaBodyColor = sireDna / 100000000000000;
        }
        uint256 dnaEyeColor;
        if( uint256(keccak256(abi.encodePacked(matronDna, sireDna, block.timestamp -2))) % 2 ==0) {
            dnaEyeColor = (matronDna/1000000000000) % 100;
        } else {
            dnaEyeColor = (sireDna/1000000000000) % 100;
        }
        uint256 dnaPawsColor;
        if( uint256(keccak256(abi.encodePacked(matronDna, sireDna, block.timestamp -3))) % 2 ==0) {
            dnaPawsColor = (matronDna/10000000000) % 100;
        } else {
            dnaPawsColor = (sireDna/10000000000) % 100;
        }
        uint256 dnaStripesColor;
        if( uint256(keccak256(abi.encodePacked(matronDna, sireDna, block.timestamp -4))) % 2 ==0) {
            dnaStripesColor = (matronDna/100000000) % 100;
        } else {
            dnaStripesColor = (sireDna/100000000) % 100;
        }
        return( (dnaBodyColor * 100000000000000) + (dnaEyeColor * 1000000000000) + (dnaPawsColor * 10000000000) + (dnaStripesColor * 100000000));
    }

    function mixDnaCattributes(uint256 matronDna, uint256 sireDna) internal view returns(uint256){

        uint256 dnaEyeStyle;
        if( uint256(keccak256(abi.encodePacked(matronDna, sireDna, block.timestamp -5))) % 2 ==0) {
            dnaEyeStyle = (matronDna/10000000) % 10;
        } else {
            dnaEyeStyle = (sireDna/10000000) % 10;
        }
        uint256 dnaStripesPattern;
        if( uint256(keccak256(abi.encodePacked(matronDna, sireDna, block.timestamp -6))) % 2 ==0) {
            dnaStripesPattern = (matronDna/1000000) % 10;
        } else {
            dnaStripesPattern = (sireDna/1000000) % 10;
        }
        uint256 dnaBellyColor;
        if( uint256(keccak256(abi.encodePacked(matronDna, sireDna, block.timestamp -7))) % 2 ==0) {
            dnaBellyColor = (matronDna/10000) % 100;
        } else {
            dnaBellyColor = (sireDna/10000) % 100;
        }
        uint256 dnaJowlsColor;
        if( uint256(keccak256(abi.encodePacked(matronDna, sireDna, block.timestamp -8))) % 2 ==0) {
            dnaJowlsColor = (matronDna/100) % 100;
        } else {
            dnaJowlsColor = (sireDna/100) % 100;
        }
        uint256 dnaAnimation;
        if( uint256(keccak256(abi.encodePacked(matronDna, sireDna, block.timestamp -9))) % 2 ==0) {
            dnaAnimation = (matronDna/10) % 10;
        } else {
            dnaAnimation = (sireDna/10) % 10;
        }
        return((dnaEyeStyle * 10000000) + (dnaStripesPattern * 1000000) + (dnaBellyColor * 10000) + (dnaJowlsColor * 100) + (dnaAnimation * 10));
    }

}

Hey @Attiss ! We use the index as token Id, for user find their dragons you can use different getter functions like

getSingleDragon(uint DragonId) 
getAllDragons(uint[] DragonIds)

Here are the mixing functions added for the breeding.

    function breed(uint _dadId, uint _mumId) public returns (uint) {
        // Check Ownership
        require (ownerOf(_dadId) == msg.sender, "The Sender Does Not Own The Dad");
        require (ownerOf(_mumId) == msg.sender, "The Sender Does Not Own The Mum");

        // Figure out Generation
        Kitty memory dad = kitties[_dadId];
        Kitty memory mum = kitties[_mumId];

        uint16 dadGeneration = dad.generation;
        uint16 mumGeneration = mum.generation;

        uint newGeneration = _mixGeneration(uint256(dadGeneration), uint256(mumGeneration));

        uint16 dadDna = dad.genes;
        uint16 mumDna = mum.genes;

        uint newDna = _mixDna(dadDna, mumDna);

        uint mintedCat = _createKitty(_mumId, _dadId, newGeneration, newDna, msg.sender);
        return mintedCat;
    }

    function _mixGeneration(uint _dadGeneration, uint _mumGeneration) internal pure returns (uint) {
        uint mixedGeneration = (_dadGeneration + _mumGeneration) / 2;
        require (mixedGeneration > 0);
        return mixedGeneration;
    }

    function _mixDna(uint _dadDna, uint _mumDna) internal pure returns (uint) {

        // daddna: 11 22 33 44 55 66 77 88
        // mumdna: 88 77 66 55 44 33 22 11

        uint firstHalf = _dadDna / 100000000; // 11 22 33 44
        uint secondHalf = _mumDna % 100000000; // 44 33 22 11

        uint extendedDna = firstHalf * 100000000; // 11 22 33 44 00 00 00 00

        uint finalDna = extendedDna + secondHalf; // 11 22 33 44 44 33 22 11
        return finalDna;
    }

And the full code for the contract for now:

pragma solidity ^0.8.0;

import "./IERC721.sol";
import "./Ownable.sol";
import "./IERC721Receiver.sol";

contract Kittycontract is IERC721, Ownable {

    string private tokenName = "KittyToken";
    string private tokenSymbol = "KITTY";
    uint constant MAXGENZEROCATS = 2000;
    uint currentGenZeroCats;
    bytes4 internal constant MAGIC_ERC721_RECEIVED = bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"));
    bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;
    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;

    event Birth(address _owner, uint _kittenId, uint _mumId, uint _dadId, uint _genes);

    struct Kitty {
        uint16 genes;
        uint64 birthTime;
        uint32 mumId;
        uint32 dadId;
        uint16 generation;
    }

    function supportsInterface(bytes4 _interfaceId) external pure returns (bool) {
        return _interfaceId == _INTERFACE_ID_ERC721 || _interfaceId == _INTERFACE_ID_ERC165;
    }

    function createKittyGenZero(uint _genes) external returns (uint kittyId) {

        require(currentGenZeroCats < MAXGENZEROCATS);
        currentGenZeroCats += 1;

        return _createKitty(0, 0, 0, _genes, msg.sender);

    }

    function _createKitty(uint _mumId, uint _dadId, uint _generation, uint _genes, address _owner) private returns (uint kittyId) {
        Kitty memory _kitty = Kitty({genes: uint16(_genes), birthTime: uint64(block.timestamp), mumId: uint32(_mumId), dadId: uint32(_dadId), generation: uint16(_generation)});
        kitties.push(_kitty);
        uint newKittenId = kitties.length - 1;
        _transfer(address(0), _owner, newKittenId);
        emit Birth(_owner, newKittenId, _mumId, _dadId, _genes);
        return newKittenId;
    }

    function getKitty(uint256 _kittyId) public view returns (uint _genes, uint _birthTime, uint _mumId, uint _dadId, uint _generation, address _owner) {
        require(_kittyId < kitties.length);

        Kitty storage kitty = kitties[_kittyId];

        _genes = uint256(kitty.genes);
        _birthTime = uint256(kitty.birthTime);
        _mumId = uint256(kitty.mumId);
        _dadId = uint256(kitty.dadId);
        _generation = uint256(kitty.generation);
        _owner = ownerOf(_kittyId);

    }

    Kitty[] kitties;

    mapping(uint => address) public kittyIndexToOwner;
    mapping (address => uint) ownershipTokenCount;
    mapping(uint => address) kittyIndexToApproved;
    mapping (address => mapping (address => bool)) private _operatorApprovals;

    function balanceOf(address owner) external override view returns (uint256 balance) {
        return ownershipTokenCount[owner];
    }

    function totalSupply() external override view returns (uint256 total) {
        return kitties.length;
    }

    function name() public view virtual override returns (string memory) {
        return tokenName;
    }

    function symbol() public view virtual override returns (string memory) {
        return tokenSymbol;
    }

    function ownerOf(uint256 tokenId) public override view returns (address owner) {
        require(tokenId <= kitties.length, "Token Does Not Exist");
        return kittyIndexToOwner[tokenId];
    }

    function transfer(address to, uint256 tokenId) external override {
        require(to != address(0));
        require(to != address(this));
        require(kittyIndexToOwner[tokenId] == msg.sender);
        _transfer(msg.sender, to, tokenId);
    }

    function _transfer(address from, address to, uint256 tokenId) internal {

        if(from != address(0)) {
            ownershipTokenCount[msg.sender] -= 1;
            delete kittyIndexToApproved[tokenId];
        }

        ownershipTokenCount[to] += 1;
        kittyIndexToOwner[tokenId] = to;

        emit Transfer(from, to, tokenId);
    }


    function approve(address _to, uint256 _tokenId) external override {
        require(kittyIndexToOwner[_tokenId] == msg.sender);
        _approve(_to, _tokenId);
        emit Approval(msg.sender, _to, _tokenId);
    }

    function _approve(address _to, uint256 _tokenId) internal {
        kittyIndexToApproved[_tokenId] = _to;
    }

    function setApprovalForAll(address _operator, bool _approved) external override {
        require (_operator != msg.sender);
        _setApprovalForAll(_operator, _approved);
        emit ApprovalForAll(msg.sender, _operator, _approved);
    }

    function _setApprovalForAll(address _operator, bool _approved) internal {
        _operatorApprovals[msg.sender][_operator] = _approved;
    }

    function getApproved(uint256 _tokenId) external override view returns (address) {
        require (_tokenId < kitties.length); // Token Must Exist
        return kittyIndexToApproved[_tokenId];
    }

    function isApprovedForAll(address _owner, address _operator) public override view returns (bool) {
        return _operatorApprovals[_owner][_operator];
    }

    function transferFrom(address _from, address _to, uint256 _tokenId) public override {
        if(_from != msg.sender && ownerOf(_tokenId) != msg.sender) {
            require(_approvedFor(msg.sender, _tokenId) || isApprovedForAll(_from, msg.sender) == true);
        }
        require(_tokenId < kitties.length);
        require(_to != address(0));
        _transfer(_from, _to, _tokenId);
    }

    function _approvedFor(address _claimant, uint _tokenId) internal view returns (bool) {
        return kittyIndexToApproved[_tokenId] == _claimant;
    }

    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata _data) external override {
        transferFrom(_from, _to, _tokenId);
        require(_checkERC721Support(_from, _to, _tokenId, _data));
    }

    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external override {
        transferFrom(_from, _to, _tokenId);
        require(_checkERC721Support(_from, _to, _tokenId, ""));
    }

    function _safeTransfer(address _from, address _to, uint _tokenId, bytes memory _data) internal {
        _transfer(_from, _to, _tokenId);
        require(_checkERC721Support(_from, _to, _tokenId, _data));
    }

    function _checkERC721Support(address _from, address _to, uint _tokenId, bytes memory _data) internal returns (bool) {
        if(!_isContract(_to)) {
            return true;
        }
        
        // Call onERC721Received in the _to contract
        bytes4 returnData = IERC721Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data);

        // Check return Value
        return returnData == MAGIC_ERC721_RECEIVED;
    }

    function _isContract(address _to) view internal returns (bool) {
        uint32 size;
        assembly{
            size := extcodesize(_to)
        }
        return size > 0;
    }

    function breed(uint _dadId, uint _mumId) public returns (uint) {
        // Check Ownership
        require (ownerOf(_dadId) == msg.sender, "The Sender Does Not Own The Dad");
        require (ownerOf(_mumId) == msg.sender, "The Sender Does Not Own The Mum");

        // Figure out Generation
        Kitty memory dad = kitties[_dadId];
        Kitty memory mum = kitties[_mumId];

        uint16 dadGeneration = dad.generation;
        uint16 mumGeneration = mum.generation;

        uint newGeneration = _mixGeneration(uint256(dadGeneration), uint256(mumGeneration));

        uint16 dadDna = dad.genes;
        uint16 mumDna = mum.genes;

        uint newDna = _mixDna(dadDna, mumDna);

        uint mintedCat = _createKitty(_mumId, _dadId, newGeneration, newDna, msg.sender);
        return mintedCat;
    }

    function _mixGeneration(uint _dadGeneration, uint _mumGeneration) internal pure returns (uint) {
        uint mixedGeneration = (_dadGeneration + _mumGeneration) / 2;
        require (mixedGeneration > 0);
        return mixedGeneration;
    }

    function _mixDna(uint _dadDna, uint _mumDna) internal pure returns (uint) {

        // daddna: 11 22 33 44 55 66 77 88
        // mumdna: 88 77 66 55 44 33 22 11

        uint firstHalf = _dadDna / 100000000; // 11 22 33 44
        uint secondHalf = _mumDna % 100000000; // 44 33 22 11

        uint extendedDna = firstHalf * 100000000; // 11 22 33 44 00 00 00 00

        uint finalDna = extendedDna + secondHalf; // 11 22 33 44 44 33 22 11
        return finalDna;
    }
}
1 Like

Very good @jak I notice that you learn and develop so fast! Good job!

1 Like

Hey, thanks for the kind words!

I’m more comfortable with react so doing this project in jquery has been ace.

And have been using hardhat instead of truffle so it’s been harder to cheat there, but I’m struggling with lots of errors to do with the RPC filter in where it says things like:

Errors encountered in param 0: Invalid value "0x0c" supplied to : RpcFilterRequest/fromBlock: (QUANTITY | "earliest" | "latest" | "pending") | undefined/0: QUANTITY, Invalid value "0x0c" supplied to : RpcFilterRequest/fromBlock: (QUANTITY | "earliest" | "latest" | "pending") | undefined/1: "earliest" | "latest" | "pending"

Which I manage to fix, and then when I come back to it, it broken again gaagghh :face_with_symbols_over_mouth:

But this has been a fun project!!
Was hoping to finish it within a week but I’m pushing on Sunday now and still a fair bit to get done.