Hi all,
I’m going through the Cryptokitty NFT marketplace course and trying to compile a contract, and I’ve got into the following error, which I’m not sure how to solve it even after trying to google it. I have an idea of what it meant, I think truffle is telling me I need to explicitly convert the struct value from uint16 to uint256 instead of implicitly doing so, but I’m not sure how to do it.
below is the the error message, followed by my smart contract:
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "./IERC721.sol";
import "../node_modules/@openzeppelin/contracts/utils/math/SafeMath.sol";
import "../node_modules/@openzeppelin/contracts/access/Ownable.sol";
// Kittycontract inheriting from IERC721
// I in IERC721 stands for interface,
// it's pretty much the functions header file for solidity
// still need to implement the functions before deploying the contract
// in order to make the smart contract to work in my own logic
contract Kittycontract is IERC721, Ownable{
//state variables
uint256 public constant CREATION_LIMIT_GEN0 = 10;
string public constant name = "MeowKitties";
string public constant symbol = "MK";
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 (uint256 => address) public kittyIndexToOwner; //takes kitty ID and return owner address
mapping (address => uint256) ownershipTokenCount; //takes an address and return how many kitty that address own
uint256 public gen0Counter;
//function for retuning the characteris of the kitty
function getKitty(uint256 _id) external view returns(
uint256 genes,
uint64 birthTime,
uint32 mumId,
uint32 dadId,
uint16 generation
){
//pointers, can use memory instead of storage, but memory takes more space
Kitty storage kitty = kitties[_id];
//convert to uint256, because its easier to read in frontend
birthTime = uint256(kitty.birthTime);
mumId = uint256(kitty.mumId);
dadId = uint256(kitty.dadId);
generation = uint256(kitty.generation);
genes = kitty.genes;
}
//create generation 0 kitty function
//onlyOwner - means only the owner of this contract can call this function
function createKittyGen0(uint256 _genes) public onlyOwner returns(uint256){
require(gen0Counter < CREATION_LIMIT_GEN0); //only can create a certain amount of Gen0 kitties
gen0Counter++;
//Gen0 have no owners they are own by the contract
return _createKitty(0, 0, 0, _genes, msg.sender);
}
//to be use for breeding kitties
//_ before function name, general practice means internal function.
function _createKitty(
uint256 _mumId,
uint256 _dadId,
uint256 _generation,
uint256 _genes,
address _owner //the recipten of this newly minted kitty
) private returns (uint256){ //returns new minted kitty ID
//creating new kitty struct
Kitty memory _kitty = Kitty({
genes: _genes,
birthTime: uint64(block.timestamp), //now means seconds since 1/1/1970 get from Eth network
mumId: uint32(_mumId), //converting a uint256 integer to uint32 integer
dadId: uint32(_dadId),
generation: uint16(_generation)
});
kitties.push(_kitty);
uint256 newKittenId = kitties.length -1;
//emitting the "Birth" even
emit Birth(_owner, newKittenId, _mumId, _dadId, _genes);
//_owner, meaning not transfer to another account, but rahter meant its
// breeding a new kitty
_transfer(address(0), _owner, newKittenId);
return newKittenId;
}
//external - can ONLY be call the function outside of this contract by other contract,
// usually cheaper in gas to call external
//view - read only, can't change or mainupulate variables in this contract
//returns - expects to return something, in this case returns a uin256 value
function balanceOf(address owner) external view returns (uint256 balance){
return ownershipTokenCount[owner];
}
//public - everyone can call this function
function totalSupply() public view returns (uint){
return kitties.length; //returns the length of the Kitty (struct) array
}
//returns an address
function ownerOf(uint256 _tokenId) external view returns (address) {
return kittyIndexToOwner[_tokenId];
}
function transfer(address _to, uint256 _tokenId) external{
require(_to != address(0)); //reciever address can't be address 0 (caller of this function) before allow to continue
require(_to != address(this)); //reciever address can't be THIS contract before allow to continue
require(_owns(msg.sender, _tokenId)); //sender must own that kitty he wants to send before allow to continue
//need to pass all the previous require first before calling below function
_transfer(msg.sender, _to, _tokenId);
}
//internal - this function can ONLY be access and view by this contract
//this function is separated from the transfer function above so it can be reused,
//for example use it to mint new kitties
function _transfer(address _from, address _to, uint256 _tokenId) internal{
ownershipTokenCount[_to]++;
kittyIndexToOwner[_tokenId] = _to; //set the owner of the kitty being transfer to the reciever
//address(0) is the address of the person calling this function,
//thus only deduct the number of kitties owned by caller, if trasnfer out, not minting new kitty
if(_from != address(0)){
ownershipTokenCount[_from]--; // deduct number of kitties owned from sender after transfer
}
//Emit the transfer event. Calling emit is part of ERC721 standard.
emit Transfer(_from, _to, _tokenId);
}
//this function returns a bool, true if _claimant indeed owns the kitty he claims he owns
function _owns(address _claimant, uint256 _tokenId) internal view returns (bool){
return kittyIndexToOwner[_tokenId] == _claimant;
}
}