Assignment - Get Kitty

Apologies @kenn.eth uploaded the other files too.

hey @Riki I checked out your code. In order to run it will still need the package.json file to install the libraries you are using.

What I can notice just by reading is the compiler version you are using at truffle-config.js is 0.8.7 but some of your contracts are using 0.8.4 . So in order to compile, you should use the same version in your compiler. If you are running all under the 0.8 version you can use this in your config:

 version: "^0.8.0"

But since this project is build with 0.5 version, you should use the same version we are using in the course in order to get the same result.

Okay then I first try the 0.5.0. But if I put 0.5.0 in truffle config and 0.5.0 to all my solidity files it says the current compilre version is 0.8.7?

Source file requires different compiler version (current compiler is 0.8.7+commit.e28d00a7.Emscripten.clang) - note that nightly builds are considered to be strictly less than the released version

I have changed the truffle config file also to 0.5.0.

truffle config

do I need to reinstall truffle in this case? I mean uninstall first then install the 5.0 one? If it is the case do I need to redo the truffle init inside the cryptokitti project?

Also do we have a package.json file here? I do not have it. I have all these but no package.json.

files

Thank you.

Ok, got it. However, When I make this change something else comes up. Now ā€œfunctionā€ is highlighted as a problem. My point is, where do I go or what are my tools to figure this out? I truly hope I donā€™t have to play the ā€œtry and errorā€ game here or have to get back to you every time a problem is detected and I canā€™t figure this out. What is my best tool to fix this on my own so I donā€™t have to bother you so much? :joy:
Here again screen shots of the problems. Please, let me know the best approach to fix this so I can move forward with the course.
Thank you very much for your time,
MaiaShot 0015

Problems!
Shot 0016

Hi there,

Iā€™ve tried to not use the forum too much for this course, but i cannot figure out what in the world is going on with my codeā€¦

For my getKitty() The error i keep getting is:

TypeError: Type struct KittycontractNFT.Kittys storage ref is not implicitly conve
rtible to expected type struct KittycontractNFT.Kittys storage ref[] storage point
er.

149 |     Kittys[] storage _kittys = kittys[tokenID];
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

and a following error:

TypeError: Member "genes" not found or not visible after argument-dependent looku
p in struct KittycontractNFT.Kittys storage ref[] storage pointer.

151 |       genes = _kittys.genes;
    |               ^^^^^^^^^^^^^

Here is my code:

pragma solidity ^0.8.0;

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

contract KittycontractNFT is IERC721, Ownable {

  event Birth(address _owner, uint256 _tokenID, uint256 momID, uint256 dadID, uint256 _genes);

  string public constant _tokenName = "WaterstoneKittys";
  string public constant _tokenSymbol = "WSK";

  mapping(address => uint256) balances;


  mapping(uint256 => address) ownerOfNFT;

  //NFT creation limit
  uint256 public constant gen0Limit = 10;

  //NFT Gen0 limit
  uint256 public gen0Counter;

  struct Kittys {
    uint256 genes;
    uint32 momID;
    uint32 dadID;
    uint64 birthTime;
    uint16 generation;
  }

  Kittys[] kittys;

  /**
   * @dev Returns the number of tokens in ``owner``'s account.
   */
  function balanceOf(address owner) external view override returns (uint256 balance){
    //we need it to return a balance of an owner --> mapping
    return balances[owner]; //need to create a 'balances' mapping
  }

  /*
   * @dev Returns the total number of tokens in circulation.
   */
  function totalSupply() public view override returns (uint256 total){
    return kittys.length;
  }

  /*
   * @dev Returns the name of the token.
   */
  function name() external view override returns (string memory tokenName){
    return _tokenName;
  }

  /*
   * @dev Returns the symbol of the token.
   */
  function symbol() external view override returns (string memory tokenSymbol){
    return _tokenSymbol;
  }

  /**
   * @dev Returns the owner of the `tokenId` token.
   *
   * Requirements:
   *
   * - `tokenId` must exist.
   */
  function ownerOf(uint256 tokenId) external view override returns (address owner){
    return ownerOfNFT[tokenId];
  }

  /* @dev Transfers `tokenId` token from `msg.sender` to `to`.
  *
  * Requirements:
  *
  * - `to` cannot be the zero address.
  * - `to` can not be the contract address.
  * - `tokenId` token must be owned by `msg.sender`.
  *
  * Emits a {Transfer} event.
  */
  function transfer(address _to, uint256 _tokenID) external override {
    require(_to != address(0), "ERC721: Transfer is to the 0 address!");
    require(_to != address(this), "ERC721: Transfer is not supported to this contract");
    require(owns(msg.sender, _tokenID));

    _transfer(msg.sender, _to, _tokenID);

  }

  function _transfer(address _from, address _to, uint256 _tokenID) internal {
    //increment balance of 'to' address + 1
    balances[_to] += 1;

    //Assign the NFT to the '_to' address
    ownerOfNFT[_tokenID] = _to;

    //if '_from' address is not the 0 address (aka not a newly minted coin being transferred)...
    //decrement the balance of the '_from' address by - 1
    if(_from != address(0)){
      balances[_from] -= 1;
    }

    emit Transfer(_from, _to, _tokenID);
  }

  function owns(address _from, uint256 tokenID) internal view returns(bool){
    return ownerOfNFT[tokenID] == _from;
  }

  function createKittyGen0(uint256 _genes) public onlyOwner returns(uint256) {
    //takes the genes that you send in from front send
    //creates a new kitty for us with those specific genes
    require(gen0Counter < gen0Limit);

    gen0Counter++;
    //use _createKitty()

    return _createKitty(0, 0, 0, _genes, address(this));
  }

  function _createKitty(uint256 _momID, uint256 _dadID, uint256 _generation, uint256 _genes,address _owner) internal returns(uint256){

      Kittys memory _kitty = Kittys({

        momID: uint32(_momID),
        dadID: uint32(_dadID),
        generation: uint16(_generation),
        genes: _genes,
        birthTime: uint64(block.timestamp)
        });

      kittys.push(_kitty);

      uint256 newKittenID = kittys.length - 1;

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

      emit Birth(_owner, newKittenID, _momID, _dadID, _genes);

      return newKittenID;

  }

  function getKitty(uint256 tokenID) external view returns(uint256 genes, uint256 momID, uint256 dadID, uint256 birthTime, uint256 generation){

    Kittys[] storage _kittys = kittys[tokenID];

      genes = _kittys.genes;
      momID =  uint256(_kittys.momID);
      dadID =  uint256(_kittys.dadID);
      birthTime = uint256(_kittys.birthTime);
      generation = uint256(_kittys.generation);

  }

}

Any help would be very appreciated.

Will

hey @Maia ! To find out the errors you can place the mouse on top of the error and will show a message.
Also if you notice in the Problems tap, the message is : " Expected ā€˜;ā€™ but fot ā€˜functionā€™ "
This normally means that the code is breaking at some point.

I can see that your code have two breaking points.

The first one is in your modifier() because is not closing tags " } " . Should close tag at line 13 for example.

Second is in the way you wrote require[ should be like require(
Also at line 12 you should always close with a " ; " at the end

1 Like

Also the contracts need to use the same version from the compiler. What you can write in the compiler settings is ā€œ^0.5.0ā€ wich means all the 0.5

hey @William in this case you should just return this values inside of the function like:

function getKitty(uint256 TokenID) 
external
view 
returns(
uint256 genes,
uint256 momID, 
uint256 dadID, 
uint256 birthTime, 
uint256 generation
){
  return (
      _kittys.genes,
      _kittys.momID,
      _kittys.dadID,
      _kittys.birthTime,
      _kittys.generation
     );
}

Migration.sol file was fixed, Thank you. However, after applying your suggestion I had to add ā€œ_;ā€ at line 13.
Now my problem: still cannot fix the compile version on settings of VS. Where I can consult to get this settings properly done? Thank you.
Maia

Shot 0017

Shot 0018

hey @Maia ! Can you place your project in a github link here? So I can review it. Normally you dont have to worry about Visual Code compiler because we are not using it. We are using truffle compiler. So what you have to make sure is to use the same solidity version that we are using in the course, for all .sol files.

Thank you!
https://github.com/Maiajc/Assig01.git

Ok @Maia, what I notice in your code is the solidity version you are using is different in IERC721.sol and kittycontract.sol please use same version solidity ^0.5.12; in both files.
Also use same version solidity ^0.5.12; in your truffle-config.js file.

Get Cat function:

//Get Cat genes per Id
    function getCatGenes(uint256 _catId) external view returns (uint256 generation, uint256 dadId, uint256 mumId, uint256 birthTime, uint256 genes) {
        generation = cats[_catId].generation;
        dadId = cats[_catId].dadId; 
        mumId = cats[_catId].mumId; 
        birthTime = cats[_catId].birthTime;
        genes = cats[_catId].genes;
    }

Edit: Iā€™ve noticed that Filip adds a pointer to storage in order to save GAS. Does it have to be mentioned? Isnā€™t it the case by default on a view function?
Is there any difference between my function above and the following one???

//Get Cat genes per Id
    function getCatGenes(uint256 _catId) external view returns (uint256 generation, uint256 dadId, uint256 mumId, uint256 birthTime, uint256 genes) {
        
        Cat storage cat = cats[_catId]; // pointer to storage in order to save GAS

        generation = uint256(cat.generation);
        dadId = uint256(cat.dadId); 
        mumId = uint256(cat.mumId); 
        birthTime = uint256(cat.birthTime);
        genes = uint256(cat.genes);
    }
1 Like

hey @Pedrojok01 ! I think both functions are good. If you are not getting any error, you can use what you prefer.

1 Like

Thanks for the precision @kenn.eth!
No error, both are working good, but Iā€™ve noticed a very slight GAS difference between the 2 functions when deploying, the Filip one being cheaper. Not sure why though.
Iā€™ll try to check again when calling the function as soon as my Web3 will be up and running. During those ā€œexpensive gas feeā€ time, saving gas matter! :joy:

1 Like

Okay I was able to get 0.5.17, hope that is okay.

Now when I would like to use the createKittyGen0 function in the terminal I get this error:

data: {
    '0xa34b8bb3be527dcd7385a075b22b559dabfab863096249da3463909c9355ee00': { error: 'revert', program_counter: 2085, return: '0x' },
    stack: 'RuntimeError: VM Exception while processing transaction: revert\n    at ' +
      'Function.RuntimeError.fromResults ' +
      '(C:\\Users\\Riki\\AppData\\Roaming\\nvm\\v12.0.0\\node_modules\\truffle\\build\\webpack:\\node_modules\\ganache-core\\lib\\utils\\runtimeerror.js:94:1)\n' +
      '    at BlockchainDouble.processBlock ' +
      '(C:\\Users\\Riki\\AppData\\Roaming\\nvm\\v12.0.0\\node_modules\\truffle\\build\\webpack:\\node_modules\\ganache-core\\lib\\blockchain_double.js:627:1)\n' +
      '    at processTicksAndRejections ' +
      '(internal/process/task_queues.js:88:5)',
    name: 'RuntimeError'
  },
  hijackedStack: 'Error: Returned error: VM Exception while processing transaction: revert\n ' +
    '   at Object.ErrorResponse ' +
    '(C:\\Users\\Riki\\AppData\\Roaming\\nvm\\v12.0.0\\node_modules\\truffle\\build\\webpack:\\node_modules\\web3-core-helpers\\lib\\errors.js:28:1)\n' +
    '    at ' +
    'C:\\Users\\Riki\\AppData\\Roaming\\nvm\\v12.0.0\\node_modules\\truffle\\build\\webpack:\\node_modules\\web3\\node_modules\\web3-core-requestmanager\\lib\\index.js:302:1\n' +
    '    at ' +
    'C:\\Users\\Riki\\AppData\\Roaming\\nvm\\v12.0.0\\node_modules\\truffle\\build\\webpack:\\packages\\provider\\wrapper.js:107:1\n' +
    '    at XMLHttpRequest.request.onreadystatechange ' +
    '(C:\\Users\\Riki\\AppData\\Roaming\\nvm\\v12.0.0\\node_modules\\truffle\\build\\webpack:\\node_modules\\web3\\node_modules\\web3-providers-http\\lib\\index.js:98:1)\n' +
    '    at XMLHttpRequestEventTarget.dispatchEvent ' +
    '(C:\\Users\\Riki\\AppData\\Roaming\\nvm\\v12.0.0\\node_modules\\truffle\\build\\webpack:\\node_modules\\xhr2-cookies\\dist\\xml-http-request-event-target.js:34:1)\n' +
    '    at ' +
    'XMLHttpRequest.exports.modules.996763.XMLHttpRequest._setReadyState ' +
    '(C:\\Users\\Riki\\AppData\\Roaming\\nvm\\v12.0.0\\node_modules\\truffle\\build\\webpack:\\node_modules\\xhr2-cookies\\dist\\xml-http-request.js:208:1)\n' +
    '    at ' +
    'XMLHttpRequest.exports.modules.996763.XMLHttpRequest._onHttpResponseEnd ' +
    '(C:\\Users\\Riki\\AppData\\Roaming\\nvm\\v12.0.0\\node_modules\\truffle\\build\\webpack:\\node_modules\\xhr2-cookies\\dist\\xml-http-request.js:318:1)\n' +
    '    at IncomingMessage.<anonymous> ' +
    '(C:\\Users\\Riki\\AppData\\Roaming\\nvm\\v12.0.0\\node_modules\\truffle\\build\\webpack:\\node_modules\\xhr2-cookies\\dist\\xml-http-request.js:289:47)\n' +
    '    at IncomingMessage.emit (events.js:201:15)\n    at ' +
    'IncomingMessage.EventEmitter.emit (domain.js:494:23)\n    at endReadableNT ' +
    '(_stream_readable.js:1130:12)\n    at processTicksAndRejections ' +
    '(internal/process/task_queues.js:83:17)'
}

I have also reuploaded my code to Github just in case here: https://github.com/Riki0923/CryptoKitti/tree/main/academy-kitties-template

Thanks for the help as always.

Hey @Riki, hope you are well.

I think the problem in your contract comes from the Ownable contract, you did not specify which is the owner, therefore, there is no owner set and then when you call the createKittyGen0 function, it does revert, without an error message because you did not specify any on your require

Ownable:

// SPDX-License-Identifier: MIT

pragma solidity 0.5.12;


contract Ownable {

    address owner;

    modifier onlyOwner(){
        require(owner == msg.sender);
        _;
    }
}

You need to add the constructor to sent the account of the deployer:

    constructor() public {
        owner = msg.sender;
    }

Then your contract works fine, I made this little unit test to help me test your contract functionality properly:

const Kittycontract = artifacts.require("Kittycontract");

contract('Kittycontract', () => {

    describe('Kittycontract Unit Test', () => {
        // Global variable declarations
        let contractInstance 
        //set contracts instances
        before(async () => {
            // Deploy to testnet
            contractInstance = await Kittycontract.deployed()
        })

        it('CreateGen0 Kitties', async () =>{
            await contractInstance.createKittyGen0(1212121212)
        })
        // it('should show info about tokenId 1', async () =>{
        //    const first_token = await contractInstance.getKitty("1");
        //    console.log("info about tokenId 1", first_token);
        // })

    });
});

Carlos Z

My solution:

Summary
    function getKitty(uint256 tokenId) public view onlyOwner returns (
        uint256 genes,
        uint64 birthTime,
        uint32 mumId,
        uint32 dadId,
        uint16 generation
        ){ return(
            kitties[tokenId].genes,
            kitties[tokenId].birthTime,
            kitties[tokenId].mumId,
            kitties[tokenId].dadId,
            kitties[tokenId].generation
            );
        }```

Isnā€™t this just a much simpler way than Filipā€™s? You end up getting the exact same information. Am I missing something?

    function getKitty(uint tokenId) public view returns(Token memory) {
        return allTokens[tokenId];
    }
1 Like

Yes if is working thats also ok.