Assignment ERC721

Hello

When compiling the Kitties contract I am getting the following Error:

ParserError

I don’t understand what’s supposed to be wrong there… help!

pragma solidity ^0.5.12;

import "./IERC721.sol";

contract Kittycontract is IERC721 {

    string public constant name = "EdiKitties";
    string public constant symbol = "EK";
    
    struct Kitty {
        uint256 genes;
        uint64 birthTime;
        uint32 mumId;
        uint32 dadId;
        uint16 generation;
    }

    Kitty[] kitties;

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

    //Returns the number of tokens in ``owner``'s account.
    function balanceOf(address owner) external view returns (uint256 balance) {
        return ownershipTokenCount[owner];
    }

    //Returns the total number of tokens in circulation.
    function totalSupply() public view returns (uint) {
        return kitties.length;
    }
/*
    //Returns the name of the token.
    function name() external view returns (string memory tokenName) {
        return name;
    }

    //Returns the symbol of the token.
    function symbol() external view returns (string memory tokenSymbol) {
        return symbol;
    }
*/
    //Returns the owner of the `tokenId` token.
    function ownerOf(uint256 _tokenId) external view returns (address) {
        return kittyIndexToOwner[_tokenId];
    }

    function transfer(address _to, uint256 _tokenId) external {
        require(_to != address(0));
        require(_to != address(this));
        require(_owns(msg.sender, _tokenId));

        _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 the transfer event.
        emit Transfer(_from, _to, _tokenId);
    }

    function _owns(address _claimant, uint256 _tokenId) internal view returns (bool) {
        return kittyIndexToOwner[_tokenId] == _claimant;
    }
}

Just figured it out, must’ve been a buggy compiler.
If someone encounters this check compiler in truffle-config.js and for me it was resolved by removing the spaces between curly bracket and variables and redoing them…

2 Likes

Hi, after a few days, I got it to compile, migrate with No errors wow that was not easy

/** 
@ title Smart Contract for Kitty-Labratory */

// SPDX-License-Identifier: MIT
//pragma solodity >= 0.6.0 < 0.9.0;
pragma solidity ^0.8.4;

import "./IERC721.sol";

contract Kittycontract is IERC721 {     //abstract contract or  * this does not work - interface

    //uint256 private _totalSupply; // added on to stop errors 

    string public constant _name = "ChantillyKitties";  // change from public to private
    string public constant _symbol = "CK";              // change from public to private now back

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

    Kitty[] kitties;

    mapping(uint256 => address) public kittyIndexToOwner;       // Map from token ID to owner address
    mapping(address => uint256) ownershipTokenCount;            // Map cats number by owner == get cats per address

    

    //Returns the number of tokens in ``owner``'s account
    function balanceOf(address owner) external view override returns (uint256 balance){
        return ownershipTokenCount[owner];
    }

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

    // add this is new on name and symbol
    function name() public pure override returns (string memory) {
        return _name;
    }
    
    function symbol() public pure override returns (string memory) {
        return _symbol;
    }

    //Returns the owner of the `_tokenId` token
    function ownerOf(uint256 tokenId) external override view returns (address) 
    {
        return kittyIndexToOwner [tokenId];
    }

    //Transfers `tokenId` token from `msg.sender` to `to`.
    function transfer(address to,uint256 tokenId) external override {
        require(to != address(0),        "You're not the owner of this cat!");
        require(to != address(this),               "ERC721: transfer to the zero address");
        //require(to != address(0));
        require(kittyIndexToOwner[tokenId] == msg.sender,  "You're not the owner of this token");        // ERC721: transfer to the contract address" // (_owns (msg.sender,

        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 the transfer event
        emit Transfer(from, to, tokenId);
    }

    function _owns(address claimant, uint256 tokenId) external view returns (bool) { // change from internal to external
        return kittyIndexToOwner [tokenId] == claimant;
    }

}

2 Likes

My Implementation for the ERC721 Kittycontract is as Follows…

Edit: Changed the contract to take into account the Kitties themselves, with the struct detailing:

  • Genes,
  • Birth Time,
  • Mum ID,
  • Dad ID, and
  • Generation

Kittycontract.sol

pragma solidity ^0.8.0;

import "./IERC721.sol";

contract Kittycontract is IERC721 {

    string tokenName = "KittyToken";
    string tokenSymbol = "KITTY";

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

    Kitty[] kitties;

    mapping(uint => address) public kittyIndexToOwner;
    mapping (address => uint) ownershipTokenCount;

    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 view returns (string memory tokenName) {
        return tokenName;
    }

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

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

    function transfer(address to, uint256 tokenId) external {
        require(to != address(0));
        require(to != address(this));
        require(kittyIndexToOwner[tokenId] == msg.sender);
        ownershipTokenCount[msg.sender] -= 1;
        ownershipTokenCount[to] += 1;
        kittyIndexToOwner[tokenId] = to;
        emit Transfer(msg.sender, to, tokenId);
    }

}
1 Like

Good assignment (good review as well in building a smart contract)
My Kitty Contract

pragma solidity ^0.5;

import "./IERC721.sol";

contract MyKitty is IERC721 {

    mapping(address => uint) tokenOwnedBalance;
    mapping(uint => address) tokenOwner;

    uint tokenTotalSupply;
    string tokenGivenName;
    string tokenTicker;

    constructor(uint _tokenTotalSupply, string memory _tokenGivenName, string memory _tokenTicker) public {
        tokenTotalSupply = _tokenTotalSupply;
        tokenGivenName = _tokenGivenName;
        tokenTicker = _tokenTicker;
    }

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

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

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

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

    function ownerOf(uint256 tokenId) external view returns (address owner) {
        require(tokenOwner[tokenId] != address(0), "Token does not exist");
        owner = tokenOwner[tokenId];
    }

    function transfer(address to, uint256 tokenId) external {
        require(tokenOwner[tokenId] == msg.sender, "Sender should own the token before transferring.");
        require(to != address(0), "Receiving address should be valid");
        require(to != address(this), "Contract address cannot be the receiver");

        tokenOwnedBalance[msg.sender] -= 1;
        tokenOwnedBalance[to] += 1;
        tokenOwner[tokenId] = to;

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

ERC-721 Fishycontract

Fishycontract.sol
pragma solidity ^0.8.10;

import "./IERC721.sol";


contract Fishycontract is IERC721 {

    struct Fishy {
        uint256 dna;
        string tokenName;
        string tokenSymbol;
        string tokenURI;
        uint256 tokenId;
        uint256 dadId;
        uint256 momId;
        uint64 birthDate;
    }

    Fishy[] fishies;

    //MAPPINGS & DECLARATIONS
        //mapping from owner address to token count
    mapping(address => uint256) ownershipTokenBalance; // (balanceOf)
        //mapping from tokenID to owner address
    mapping(uint256 => address) ownerToken; // (ownerOf)
        //Token name
    string public _tokenName = "Fishy";
        //Token symbol
    string public _tokenSymbol = "FISHY";


    //EVENTS
        //Emitted when `tokenId` token is transfered from `from` to `to`
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
        //Emitted when `owner` enables `approved` to manage the `tokenId` token
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);


    //GETTERS
        //Returns the number of tokens in ``owner``'s account
    function balanceOf(address owner) external view returns (uint256 balance) {
        require(owner != address(0), "Ensure address exists");
        return ownershipTokenBalance[owner];
    }

        //Returns the owner of the `tokenId` token
    function ownerOf(uint256 tokenId) external view returns (address owner) {
            //Requirements: `tokenId` must exist.
        address currentOwner = ownerToken[tokenId];
        require(currentOwner != address(0), "Ensure token exists");
        return currentOwner;
    }


    //TRANSFER
        //Transfers `tokenId` token from `msg.sender` to `to`
    function transfer(address to, uint256 tokenId) external {
        //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

        require(to != address(0), "Ensure address exists");
        require(to != address(this), "Ensure this contract address is not transfer destination");
        require(msg.sender == ownerToken[tokenId], "Token must be owned by sender");

        /*If this is the primary transfer function, be sure to include requires/asserts with
        regards to approvals*/


        //insert private _transfer function here
          //_transfer(msg.sender, to, tokenId);
        ownershipTokenBalance[msg.sender] -= 1;
        ownershipTokenBalance[to] += 1;
        ownerToken[tokenId] = to;

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


    //APPROVALS


    //METADATA
        //Returns the name of the token
    function name() external view returns (string memory tokenName) {
        return _tokenName;
    }

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


    //ENUMERATION
        //Returns the total number of tokens in circulation
    function totalSupply() external view returns (uint256 total) {
        return fishies.length;
    }



    //RECEIVER HOOK & ERC-165 SUPPORT



}
1 Like

I get the following error when I run “truffle migrate”

ReferenceError: Token is not defined
at module.exports (/Users/Eleanor/Desktop/Blockchain/DAPP/academy-kitties-template-master/migrations/1_initial_migration.js:4:19)
at Migration._load (/usr/local/lib/node_modules/truffle/build/webpack:/packages/migrate/Migration.js:55:1)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at Migration.run (/usr/local/lib/node_modules/truffle/build/webpack:/packages/migrate/Migration.js:217:1)
at Object.runMigrations (/usr/local/lib/node_modules/truffle/build/webpack:/packages/migrate/index.js:150:1)
at Object.runFrom (/usr/local/lib/node_modules/truffle/build/webpack:/packages/migrate/index.js:110:1)
at Object.runAll (/usr/local/lib/node_modules/truffle/build/webpack:/packages/migrate/index.js:114:1)
at Object.run (/usr/local/lib/node_modules/truffle/build/webpack:/packages/migrate/index.js:79:1)
at runMigrations (/usr/local/lib/node_modules/truffle/build/webpack:/packages/core/lib/commands/migrate/run.js:76:1)
at Object.module.exports [as run] (/usr/local/lib/node_modules/truffle/build/webpack:/packages/core/lib/commands/migrate/run.js:44:1)

This is my code in the migrations file:

const Token = artifacts.require("Santacontract");

module.exports = function (deployer) {
  deployer.deploy(Token);
};

This is my contract code:

pragma solidity ^0.8.0;

import "./IERC721.sol";

contract Santacontract is IERC721 {
    //Token name
    string public constant _name = "SantaFactory";
    //Token symbol
    string public constant _symbol = "SF";

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

    Santa[] santas;

    // constructor(
    //     uint256 memory totalSupply_,
    //     string memory name_,
    //     string memory symbol_
    // ) {
    //     _totalSupply = totalSupply_;
    //     _name = name_;
    //     _symbol = symbol_;
    // }

    // Mapping from token ID to owner address
    mapping(uint256 => address) public santaIndexToOwner;

    // Mapping owner address to token count
    mapping(address => uint256) ownershipTokenCount;

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

    function totalSupply() public view returns (uint256) {
        return santas.length;
    }

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

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

    function ownerOf(uint256 _tokenId) external view returns (address) {
        address owner = santaIndexToOwner[_tokenId];
        return owner;
    }

    function transfer(address _to, uint256 _tokenId) external {
        require(_to != address(0), "ERC721: owner query for nonexistent token");
        require(
            _to != address(this),
            "ERC721: owner query for contract address"
        );
        require(_owns(msg.sender, _tokenId));
        _transfer(msg.sender, _to, _tokenId);
    }

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

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

        //Emit the transfer event
        emit Transfer(_from, _to, _tokenId);
    }

    function _owns(address _claimant, uint256 _tokenId)
        internal
        view
        returns (bool)
    {
        return santaIndexToOwner[_tokenId] == _claimant;
    }
}

May I also check if we still need to install ganache as if I run truffle dev I can receive the 9 addresses and private keys already

hey @Eleanor_Tay ! Can you post full code using github repository. Also take a screenshot of the error and paste it here. Problem might be something with name of the files.

Hi @kenn.eth
This is the error I get:

My github link is here: https://github.com/nortay250/santa-factory

1 Like

I think you already solve this issue in another topic right?

Carlos Z

yup, thanks Carlos, you have answered my previous query!

1 Like
pragma solidity >= 0.5.0 < 0.9.0;

import "./contracts/IERC721.sol";

contract CatContract is IERC721 {

    string public constant name = "ZKitties";
    string public constant symbol = "ZK";

    struct Kitty {
        uint256 genes;
        uint64 birthTime;
        uint32 fatherID;
        uint32 motherID;
        uint16 generation;
    }

    Kitty [] kitties; //array

    mapping(uint256 => address) public kittyIndexToOwner;
    mapping(address => uint256) ownerTokenCount;
    
    function balanceOf(address owner) external view returns (uint256 balance){
        return ownerTokenCount[owner];
    }

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

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

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

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

    function transfer(address to, uint256 tokenId) external {
        require(to != address(0), "Cannot send to this address");
        require(to != address(this), "Cannot send to this contract");
        require(owner[tokenId] == msg.sender, "Owner is msg.sender");

        emit Transfer(msg.sender, to, tokenID);
    }
    
}
2 Likes

Somehow when I ran truffle compile, it only ran the first: 1_migrations.js file. Also, I never got the .json migration files (or I don’t know how or where to find them). I am really not sure what I am missing, could someone please help me out with this? Am I supposed to create the build/contracts folders on my own?

hello @GahuckImGoofy can you post your other migration files you wish to run?
There is a standard to follow with this files.
1_ initial_migration.js
2_ token_migration.js

If this is not working to you, most be a issue on the file.

It was just those two. I have figured it out though, it was an issue with where I had the contracts and the migrations folders saved. Once I moved the contracts folder out of the client folder and deleted the duplicates, it worked.

1 Like

Contract:

KittyContract.sol

// SPDX-License-Identifier: MIT

pragma solidity >=0.5.0 < 0.8.11;

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

import “./IERC721.sol”;

contract KittyContract is IERC721 {

using SafeMath for uint256;

uint256 private supply;

string private _name;

string private _symbol;

mapping(address => uint256) public balances;

mapping(uint256 => address) public owners;

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 = supply;

}

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 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!");

balances[msg.sender] = balances[msg.sender].sub(1);

owners[tokenId] = to;

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

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

}

}

1 Like

tried this on my own

pragma solidity ^0.8.10;
import "./IERC721.sol";

abstract contract kittyContract is IERC721{
   string tokenSymbol;
   uint256 totalKittyTokens;
   string tokenName;
   address owner;
   
   constructor(string memory _name, string memory _symbol, uint256 _totalKittyTokens){
       tokenName = _name;
       tokenSymbol = _symbol;
       totalKittyTokens = _totalKittyTokens;
       owner = msg.sender;

   }

    mapping(address => uint256) ownershipTokenCount;
    mapping(uint256 => address) tokenOwner;
  

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

    function totalSupply() external view returns (uint256){
        return totalKittyTokens;
    }

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

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

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

   function transfer(address to, uint256 tokenId) external{
       
       ownershipTokenCount[msg.sender] -= tokenId;
       ownershipTokenCount[to] += tokenId;

       require(to != address(0));
       require(to != address(this));
       

   }

}


1 Like

Hi, this is my solution:

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;

import "./IERC721.sol";

contract KittiesContract is IERC721 {
    mapping(address => uint256) internal ownershipTokenCount;
    uint256 internal tokenCount;
    string internal nameOfToken;
    string internal symbolOfToken;

    struct Token {
        uint256 tokenId;
        address owner;
    }

    mapping(uint256 => Token) internal tokens;

    constructor(string memory name_, string memory symbol_) {
        nameOfToken = name_;
        symbolOfToken = symbol_;
    }

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

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

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

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

    function ownerOf(uint256 tokenId) external view returns (address owner) {
        require(
            tokens[tokenId].tokenId != 0,
            "Kitties: Token id does not exist"
        );
        owner = tokens[tokenId].owner;
    }

    function transfer(address to, uint256 tokenId) external {
        require(to != address(0), "Kitties: Token cannot be burned");
        require(
            to != address(this),
            "Kitties: Token cannot be sent to the contract address"
        );
        require(
            msg.sender == tokens[tokenId].owner,
            "Kitties: Only owner can transfer the token"
        );

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

My solution after watching the video ERC721 Help:

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;

import "./IERC721.sol";

contract KittiesContract is IERC721 {
    string public constant name = "MockCryptoKitties";
    string public constant symbol = "MCK";

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

    Kitty[] internal kitties;

    mapping(address => uint256) internal ownershipTokenCount;
    mapping(uint256 => address) internal kittyIndextoOwner;

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

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

    function ownerOf(uint256 tokenId) external view returns (address owner) {
        require(
            kittyIndextoOwner[tokenId] != address(0),
            "Kitties: Token id does not exist"
        );
        owner = kittyIndextoOwner[tokenId];
    }

    function transfer(address to, uint256 tokenId) external {
        require(to != address(0), "Kitties: Token cannot be burned");
        require(
            to != address(this),
            "Kitties: Token cannot be sent to the contract address"
        );
        require(
            msg.sender == kittyIndextoOwner[tokenId],
            "Kitties: Only owner can transfer the token"
        );

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

1 Like

What software is being used to compile the code?
Penguincontract.sol

pragma solidity ^0.5.12;

import "./IERC721.sol";
import "./ownable.sol";

contract Penguincontract is IERC721, Ownable {

    uint256 public constant CREATION_LIMIT_GEN0 = 10;
    string public constant name = "MichaelPenguins";
    string public constant symbol = "MP";

    event Birth(
        address owner,
        uint256 penguinId,
        uint256 mumId,
        uint256 dadId,
        uint256 genes
        );

    struct Penguin {
        uint256 genes;
        uint256 birthTime;
        uint256 mumId;
        uint256 dadId;
        uint256 generation;
    }

    Penguin[] penguins; 

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

    uint256 public gen0Counter;

    function createPenguinGen0(uint256 _genes) public onlyOwner returns (uint256) {
        require(gen0Counter < CREATION_LIMIT_GEN0);

        gen0Counter++;

        return _createPenguin(0, 0, 0, _genes, msg.sender);
    }

    function _createPenguin(
        uint256 _mumId,
        uint256 _dadId,
        uint256 _generation,
        uint256 _genes,
        address _owner
    ) private returns (uint256) {
        Penguin memory _penguin = Penguin({
            genes: _genes,
            birthTime: uint64(now),
            mumId: uint32(_mumId),
            dadId: uint32(_dadId),
            generation: uint16(_generation)
        });

        uint256 newPenguinId = penguins.push(_penguin) - 1;

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

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

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
      function balanceOf(address owner) external view returns (uint256 balance) {
        return ownershipTokenCount[owner];
    }
    /*
     * @dev Returns the total number of tokens in circulation.
     */
    function totalSupply() external view returns (uint) {
        return penguins.length;
    }
    
    function ownerOf(uint256 _tokenId) external view returns (address){
        return PenguinIndexToOwner[_tokenId];
    }
    
    function transfer(address _to, uint256 _tokenId) external {
        require(_to != address(0));
        require(_to != address(this));
        require(_owns(msg.sender, _tokenId));

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

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

        PenguinIndexToOwner[_tokenId] = _to;

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

        emit Transfer(_from, _to, _tokenId);
    }

    function _owns(address _claimant, uint256 _tokenId) internal view returns (bool) {
        return PenguinIndexToOwner[_tokenId] == _claimant;
    }
    

}
1 Like

Here is my solution :slight_smile:
Happy to be the 100th answer :grin:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IERC721.sol";

contract Kitties is IERC721 {

    string public constant tokenName = "Crypto Kitties";

    string public constant tokenSymbol = "CK";

    struct Kitty {

        uint256 genes;

        uint64 birthTime;

        uint32 mumId;

        uint32 dadId;

        uint16 generation;

    }

    Kitty[] kitties;

    mapping (address => uint256) balance;

    mapping (uint256 => address) kittyToOwner;

   

    function totalSupply() external view returns (uint256) {

        return kitties.length;

    }

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

        return balance[owner];

    }

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

        return tokenName;

    }

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

        return tokenSymbol;

    }

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

        require(kittyToOwner[tokenId] != address(0), "Kitty does not exsist!");

        return kittyToOwner[tokenId];

    }

    function transfer(address to, uint256 tokenId) external {

        require(to != address(0), "Cannot send to 0 address!");

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

        require(kittyToOwner[tokenId] == msg.sender, "Can only send your kitty!");

        balance[msg.sender] = balance[msg.sender]-1;

        balance[to] = balance[to]+1;

        kittyToOwner[tokenId] = to;

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

    }

}
1 Like