Assignment - Get Kitty

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.

getKitty Solution

    function getKitty(uint256 _kittyId) public view returns(Kitty memory) {
        Kitty memory returnKitty = kitties[_kittyId];
        return returnKitty;
    }   

I have some error and don’t know why?

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./IERC721.sol";
import "../node_modules/@openzeppelin/contracts/utils/math/SafeMath.sol";

  contract Kittycontract is IERC721 {
    
     using SafeMath for uint256;

     string public TokenName = "KittyCoin";
     string public TokenSymbol = "KTC";
     uint256 TokenAmount;

     mapping (uint256 => address) kittyIndexToOwner;   //owner of token
     mapping (address => uint256) ownerShipTokenCount; //token balance

     struct Kitty{
         uint256 gens; 
         uint64 birthTime;
         uint32 momId;
         uint32 dadId;
         uint16 generation;
     }

     Kitty[] kitties;

     function crateKitty (uint256 _momId, uint256 _dadId, uint256 _generation, uint256 _gens,  address _owner  ) public returns (uint256) { // vraca cat ID 

        // kreiramo novi struct object using the name of the struct, pa zagrade kao function call, pa onda viticaste kao object 
        Kitty memory _kitty = Kitty({gens: _gens, birthTime: uint64(block.timestamp), momId: uint32(_momId), dadId: uint32(_dadId), generation: uint16(_generation)});

        uint256 newKittyID = kitties.push(_kitty) - 1;

        _transfer(address(0), _owner, newKittyID);
     }

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

    function totalSupply() override external view returns (uint256 total){
         total = TokenAmount;
    }

    function name() override external view returns (string memory tokenName){
         tokenName = TokenName;
    }

    function symbol() override external view returns (string memory tokenSymbol){
         tokenSymbol = TokenSymbol;
    }

    function ownerOf(uint256 tokenId) override external view returns (address owner){
        return kittyIndexToOwner[tokenId];
    }

    function transfer(address to, uint256 tokenId) override external{
        require(to != address(0), "cannot be the zero address");
        require(to != address(this), "can not be the contract address");
        require(kittyIndexToOwner[tokenId] == msg.sender);

        _transfer(msg.sender, to, tokenId);

        emit Transfer(msg.sender, to, tokenId);
    }

    function _transfer(address _from, address _to, uint256 _tokenId) internal {
        ownerShipTokenCount[_to]++;

        kittyIndexToOwner[_tokenId] = _to;

        if(_from != address(0)){
            ownerShipTokenCount[_from]-- ;
        }
        emit Transfer(_from, _to, _tokenId);
    }



}

Hey @Lane11, hope you are well.

Try with this:

     function crateKitty (uint256 _momId, uint256 _dadId, uint256 _generation, uint256 _gens,  address _owner  ) public returns (uint256) { // vraca cat ID 

        // kreiramo novi struct object using the name of the struct, pa zagrade kao function call, pa onda viticaste kao object 
        Kitty memory _kitty = Kitty({gens: _gens, birthTime: uint64(block.timestamp), momId: uint32(_momId), dadId: uint32(_dadId), generation: uint16(_generation)});
        
        uint256 newKittyID = kitties.length; // will be the index position before push the new kitty
        kitties.push(_kitty); // we push the new kitty, the index should be the same than newKittyID;
        _transfer(address(0), _owner, newKittyID);
     }

Carlos Z

2 Likes

There’s an easy (but not descriptive) way to do it which is:

    function getKitty(uint256 _kittyId) external view returns (Kitty memory _kitty) {
        require(_kittyId < kitties.length);
        return kitties[_kittyId];
    }

But if you want to be more descriptive with your output, then I have done:

    function getKitty(uint256 _kittyId) external view returns (uint16 _genes, uint64 _birthTime, uint32 _mumId, uint32 _dadId, uint16 _generation) {
        require(_kittyId < kitties.length);
        return (kitties[_kittyId].genes, kitties[_kittyId].birthTime, kitties[_kittyId].mumId, kitties[_kittyId].dadId, kitties[_kittyId].generation);
    }
1 Like

A quick implementation on the first try:

    function getKitty(uint _kittyId) public view returns(uint dna_, uint birthTime_, uint momId_, uint dadId_, uint generation_) {
        Kitty storage kittyInfo = kitties[_kittyId];
        dna_ = kittyInfo.dna;
        birthTime_ = kittyInfo.birthTime;
        momId_ = kittyInfo.momId;
        dadId_ = kittyInfo.dadId;
        generation_ = kittyInfo.generation;
    }
1 Like
function getFishy(uint256 _tokenId) external view 
    returns (uint256 momId, 
             uint256 dadId,
             uint256 generation,
             uint256 genes,
             address owner) {

        address _currentOwner = ownerToken[_tokenId];

        require(_currentOwner != address(0), "Ensure token exists");
        require(fishies.length > 0, "Ensure Fishies exist");

        return(fishies[_tokenId].momId,
               fishies[_tokenId].dadId, 
               fishies[_tokenId].generation, 
               fishies[_tokenId].genes , 
               _currentOwner);
    }
1 Like
function getKitty(uint256 id) external view returns (
        
        uint256 birthTime,
        uint256 motherID,
        uint256 fatherID,
        uint256 generation,
        uint256 genes
        ){
        Kitty storage kitty = kitties[id]; //save as a pointer

        birthTime = uint256(kitty.birthTime);
        motherID = uint256(kitty.motherID);
        fatherID = uint256(kitty.fatherID);
        generation = uint256(kitty.generation);
        genes = kitty.genes;
    }
1 Like

Response SC from getKitty()

function getKitty(uint256 tokenId) public view returns (Kitty memory){
    require(owners[tokenId] != address(0), "Token does not exists!");
    Kitty storage kitty = kitties[tokenId];

    return kitty;
  }
KittyContract.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.5.0 < 0.8.11;

import “@openzeppelin/contracts/utils/math/SafeMath.sol”;

import “@openzeppelin/contracts/access/Ownable.sol”;

import “./IERC721.sol”;

contract KittyContract is IERC721, Ownable {

using SafeMath for uint256;

string private _name;

string private _symbol;

uint256 public gen0Counter;

uint256 public gen0MintLimit = 9;

struct Kitty {

uint256 dna;

uint64 spawnedAt;

uint32 momId;

uint32 dadId;

uint16 generation;

}

Kitty[] kitties;

mapping(address => uint256) public balances;

mapping(uint256 => address) public owners;

event KittySpawned(uint256 kittyId, uint256 dna, address owner, uint256 momId, uint256 dadId);

constructor(string memory name_, string memory symbol_) {

_name = name_;

_symbol = symbol_;

}

function balanceOf(address owner) external override view returns (uint256 balance) {

balance = balances[owner];

}

function totalSupply() external override view returns (uint256 total) {

total = kitties.length;

}

function name() external override view returns (string memory tokenName) {

tokenName = _name;

}

function symbol() external override view returns (string memory tokenSymbol) {

tokenSymbol = _symbol;

}

function ownerOf(uint256 tokenId) external override view returns (address owner) {

owner = owners[tokenId];

require(owner != address(0), "Token id does not exists!");

}

function createKittyGen0(uint256 _dna) public onlyOwner {

require(gen0Counter < gen0MintLimit, "Minting Limit reached for Gen0");

gen0Counter = gen0Counter.add(1);



_createKitty(_dna, 0, 0, 0, msg.sender);

}

function _createKitty(

uint256 _dna,

uint256 _momId,

uint256 _dadId,

uint256 _generation,

address _owner

) private returns (uint256){

Kitty memory kitty = Kitty({

  dna: _dna,

  spawnedAt: uint64(block.timestamp),

  momId: uint32(_momId),

  dadId: uint32(_dadId),

  generation: uint16(_generation)

});

kitties.push(kitty);

uint256 newKittyId = (kitties.length).sub(1);



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

emit KittySpawned(newKittyId, _dna, _owner, _momId, _dadId);



return newKittyId;

}

function getKitty(uint256 tokenId) public view returns (Kitty memory){

require(owners[tokenId] != address(0), "Token does not exists!");

Kitty storage kitty = kitties[tokenId];

return kitty;

}

function transfer(address to, uint256 tokenId) external override {

require(to != address(0), "Recieving address cannot be dead address!");

require(to != address(this), "Cannot send to the contract!");

require(owners[tokenId] == msg.sender, "Token Id must belong to the message sender!");

_transfer(msg.sender, to, tokenId);

}

function _transfer(address _from, address _to, uint256 _tokenId) internal {

if(_from != address(0)) {

  balances[_from] = balances[_from].sub(1);

}

owners[_tokenId] = _to;

balances[_to] = balances[_to].add(1);

emit Transfer(_from, _to, _tokenId);

}

}

2 Likes

I run into this error whenever i run instance.createKittyGen0()

truffle(development)> instance.createKittyGen0(1001)
Uncaught:
StatusError: Transaction: 0x29a95d4f622930dc8ddff2b8c6650cdac27842b2906cc5708f6469c25df7ac9e exited with an error (status 0). 
    at evalmachine.<anonymous>
    at sigintHandlersWrap (node:vm:268:12)
    at Script.runInContext (node:vm:137:14)
    at runScript (/usr/local/lib/node_modules/truffle/build/webpack:/packages/core/lib/console.js:364:1)
    at Console.interpret (/usr/local/lib/node_modules/truffle/build/webpack:/packages/core/lib/console.js:379:1)
    at bound (node:domain:421:15)
    at REPLServer.runBound [as eval] (node:domain:432:12)
    at REPLServer.onLine (node:repl:891:10)
    at REPLServer.emit (node:events:520:28)
    at REPLServer.emit (node:domain:475:12)
    at REPLServer.Interface._onLine (node:readline:487:10)
    at REPLServer.Interface._line (node:readline:864:8)
    at REPLServer.Interface._ttyWrite (node:readline:1216:14)
    at REPLServer.self._ttyWrite (node:repl:986:9) {
  tx: '0x29a95d4f622930dc8ddff2b8c6650cdac27842b2906cc5708f6469c25df7ac9e',
  receipt: {
    transactionHash: '0x29a95d4f622930dc8ddff2b8c6650cdac27842b2906cc5708f6469c25df7ac9e',
    transactionIndex: 0,
    blockNumber: 36,
    blockHash: '0xa86c80ecb49e049ec3928af0d613133310b8facd41b26c8bdc60ab599d1d396f',
    from: '0xc329b7cdc69020810a4375e8a011ff1d5c6e2bec',
    to: '0x462c32f3912c1617c900fcc9865023ddb75bda3b',
    cumulativeGasUsed: 24183,
    gasUsed: 24183,
    contractAddress: null,
    logs: [],
    logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
    status: false,
    effectiveGasPrice: '0x9582daab',
    type: '0x2',
    rawLogs: []
  },
  reason: undefined,
  hijackedStack: 'StatusError: Transaction: 0x29a95d4f622930dc8ddff2b8c6650cdac27842b2906cc5708f6469c25df7ac9e exited with an error (status 0). \n' +
    '     Please check that the transaction:\n' +
    '     - satisfies all conditions set by Solidity `require` statements.\n' +
    '     - does not trigger a Solidity `revert` statement.\n' +
    '\n' +
    '    at Object.receipt (/usr/local/lib/node_modules/truffle/build/webpack:/packages/contract/lib/handlers.js:128:1)\n' +
    '    at processTicksAndRejections (node:internal/process/task_queues:96:5)\n' +
    '    at Function.start (/usr/local/lib/node_modules/truffle/build/webpack:/packages/contract/lib/override.js:49:1)'
}
truffle(development)> 


Below is my Kitty contract

pragma solidity ^0.8.10;

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

contract kittyContract is IERC721, Ownable{
   uint256 public constant CREATION_LIMIT_GEN0 = 10;
   string public constant tokenSymbol = "CK";
   string public constant tokenName = "CodedKitties";
  
  event Birth(address owner, uint256 kittenId, uint256 mumId, uint256 dadId, uint256 genes);

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

    Kitty[] kitties;

        mapping(address => uint256) ownershipTokenCount;
        mapping(uint256 => address) public kittyTokenOwner;

        uint256 public gen0Counter;

        function createKittyGen0(uint256 _genes) public isOwner returns(uint256){
            require(gen0Counter < CREATION_LIMIT_GEN0);

            gen0Counter++;

            // Gen0 have no owners they are own by the contract
            return _createKitty(0, 0, 0, _genes, msg.sender);
        }

    function _createKitty(uint _mumId, uint256 _dadId, uint256 _generation, uint256 _genes, address _owner)private returns(uint256) {
        Kitty memory _kitty = Kitty({
            genes: _genes,
            birthTime: uint64(block.timestamp),
            mumId: uint32(_mumId),
            dadId: uint32(_dadId),
            generation: uint16(_generation)
        });

        
        // uint256 newKittenId = kitties.push(_kitty) -1;
        
        kitties.push(_kitty);

        uint256 newKittenId = kitties.length -1;


        emit Birth(_owner, newKittenId, _mumId , _dadId, _genes);

        _transfer(address(0), _owner, newKittenId);
    }  

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

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

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

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

     function ownerOf(uint256 tokenId) external view returns (address ){
          require(kittyTokenOwner[tokenId] != address(0));
           return kittyTokenOwner[tokenId];
   }

   function transfer(address to, uint256 tokenId) external{

       require(to != address(0));
       require(to != address(this));
    
    _transfer(msg.sender, to, tokenId);
   }

   function _transfer(address _from, address _to, uint256 _tokenId) internal{
       ownershipTokenCount[_to]++;

       kittyTokenOwner[_tokenId] = _to;

       if(_from != address(0)) {
           ownershipTokenCount[_from]--;
       }

    //    emit transfer event

    emit Transfer(_from, _to, _tokenId);


   }

}


below is my ownable contract

pragma solidity ^0.8.10;

contract Ownable {

    address private owner;
    
    // event for EVM logging
    event OwnerSet(address indexed oldOwner, address indexed newOwner);
    
    // modifier to check if caller is owner
    modifier isOwner() {
        // If the first argument of 'require' evaluates to 'false', execution terminates and all
        // changes to the state and to Ether balances are reverted.
        // This used to consume all gas in old EVM versions, but not anymore.
        // It is often a good idea to use 'require' to check if functions are called correctly.
        // As a second argument, you can also provide an explanation about what went wrong.
        require(msg.sender == owner, "Caller is not owner");
        _;
    }
    
    /**
     * @dev Set contract deployer as owner
     */
    constructor() {
        owner = msg.sender; // 'msg.sender' is sender of current call, contract deployer for a constructor
        emit OwnerSet(address(0), owner);
    }

    /**
     * @dev Change owner
     * @param newOwner address of new owner
     */
    function changeOwner(address newOwner) public isOwner {
        emit OwnerSet(owner, newOwner);
        owner = newOwner;
    }

    /**
     * @dev Return owner address 
     * @return address of owner
     */
    function getOwner() external view returns (address) {
        return owner;
    }
}
1 Like

I think you should call in the truffle console.

truffle(development)> await instance.createKittyGen0(1001)

Carlos Z

It still gives the same error

Hi guys, can you give me a hand with the following error I have?.
As much as I check again and again I can not identify the error in the attached file

. By the way, the sol files are using the same compilator.

On the other hand, I found this

However, the truffle-config.js file is configured for the version: "0.5.12", compiler.

1 Like

Maybe one of your require is getting triggered, try to add an error message on them, here is an example, try to fill the rest of them in your contract and run the function again, this time, you should have an error message the you can follow to have a better picture of the issue.

     function ownerOf(uint256 tokenId) external view returns (address ){
          require(kittyTokenOwner[tokenId] != address(0), "ownerOf: zero address");
           return kittyTokenOwner[tokenId];
   }

   function transfer(address to, uint256 tokenId) external{

       require(to != address(0), "transfer: cannot transfer to zero address");
       require(to != address(this), "transfer: cannot transfer to contract address");
    
    _transfer(msg.sender, to, tokenId);
   }

Carlos Z

Hey @cgironda, hope you are well.

Each of the console error mention “invalid implicit conversion from AAA to BBB”

You might want to check the order you are providing the arguments to the function, quick example:

function something(address _address, uint256 _number, string memory _string){...}

function doSomething(uint256 _a, string memory _words){
// correct way, just provide the arguments in the same order of the function header
// an address, a uint, a string
something(msg.sender, 5, "when moon");
}

Carlos Z

Hi @thecil, thank you for your reply to answer my question.

Based on your explanation I found I declared one of my parameters as an integer.
Now the program runs very well.

Thank you very much!

1 Like

I’ve fixed it bro, the issue was coming from the ownable contract

1 Like