Assignment ERC721

Hi this is my code :
in final code , i will use oracol’s random number for set Stats.

// SPDX-License-Identifier: Leluk911
pragma solidity 0.8.7;

import "../node_modules/@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "../node_modules/@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "../node_modules/@openzeppelin/contracts/utils/Counters.sol";

contract MyNft is ERC721URIStorage {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    constructor() ERC721("NftCat", "NFC") {}

    struct Cat {
        uint256 Id;
        uint8 color1;
        uint8 color2;
        uint8 color3;
        uint8 power;
        uint8 lifepoint;
        uint8 stamina;
        uint8 speed;
    }
    Cat[] public Cats;

    function mint(
        address to,
        uint8 _color1,
        uint8 _color2,
        uint8 _color3,
        uint8 _power,
        uint8 _lifepoint,
        uint8 _stamina,
        uint8 _speed
    ) external virtual {
        uint256 newItemId = _tokenIds.current();

        Cat memory NewCat = Cat(
            newItemId,
            _color1,
            _color2,
            _color3,
            _power,
            _lifepoint,
            _stamina,
            _speed
        );

        Cats.push(NewCat);
        _mint(to, newItemId);
    }

    function wiewStat(uint256 _tokenId)
        public
        view
        virtual
        returns (Cat memory)
    {
        return Cats[_tokenId];
    }

    // this transaction must approve
    function transferNft(address _to, uint256 _tokenId) external virtual {
        _transfer(msg.sender, _to, _tokenId);
    }
}

Kittycontract.sol:

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

import "./IERC721.sol";

contract Kittycontract is IERC721 {
  string public constant Name = "DemoKitties";
  string public constant Symbol = "DK";

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

  Kitty[] private allKitties; // index => kitty id (token id)

  mapping (address => uint256) ownerTokenBalance; // get uint256 amount (token kitty count) of owner address
  mapping (uint256 => address) public kittyIndexToOwner; // get owner address of uint256 kitty id (token id)
  
  function balanceOf(address _owner) external view returns (uint256) {
    return ownerTokenBalance[_owner];
  }

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

  function name() public view returns (string memory) {
    return Name;
  }

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

  function ownerOf(uint256 _tokenId) external view returns (address) {
    address owner = kittyIndexToOwner[_tokenId];
    require(owner != address(0), "No owner of not existing address");
    return owner;
  }

  function transfer(address _to, uint256 _tokenId) external {
    require(_to != address(0), "TO address must be defined.");
    require(_to != address(this), "Cannot transfer to the contract itself");
    require(_to != msg.sender, "Cannot send to yourselves");
    require(owns(msg.sender, _tokenId), "Cannot send token you not own");

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

  function _transfer(address _from, address _to, uint256 _tokenId) internal {
    ownerTokenBalance[_to]++;
    if (_from != address(0)) {
      ownerTokenBalance[_from]--;
    }
    kittyIndexToOwner[_tokenId] = _to;

    emit Transfer(_from, _to, _tokenId);
  }

  function owns(address claimant, uint256 tokenId) internal view returns (bool) {
    return kittyIndexToOwner[tokenId] == claimant;
  }
}

Hello! This was my attempt. I got pretty far on my own but after watching the solution I realized I over complicated a lot of the functionality of the Transfer function so I edited it after watching as I felt Filip’s was much more optimized. Anyways here is my code.

// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;

import "./IERC721.sol";

contract Katcontract is IERC721 {

    /*
     * @dev List of Token name and symbol
     */
    string public constant tokenName = "CryptoKats";
    string public constant tokenSymbol = "CK";

    /*
     * @dev Struct of CryptoKat NFT
     */
    struct Kat {
        uint256 genes;
        uint64 birthtime;
        uint32 motherId;
        uint32 fatherId;
        uint16 generation;
    }

    /*
     * @dev Array of all CryptoKat NFTs.
     */
    Kat[] internal kats;

    /*
     * @dev Mapping from owner address to count of their tokens.
     */
    mapping(address => uint256) private ownedTokenCount;

    /*
     * @dev Mapping from tokenId to the address that owns it.
     */
    mapping(uint256 => address) internal idToOwner;

    /*************************************************************/

    /*
     * @dev Returns the total number of tokens in circulation.
     */    
    function balanceOf(address owner) external view returns (uint256 balance){
        return ownedTokenCount[owner];
    }

    /**
     * @dev Returns the count of all existing NFTs.
     * @return total supply of NFTs.
     */
    function totalSupply() external view returns (uint256 total){
        return kats.length;
    }

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

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

    /*
     * @dev Returns the owner of the `tokenId` token.
     */
    function ownerOf(uint256 _tokenId) external view returns (address owner){
        return idToOwner[_tokenId];
    }

    /* 
     * @dev Transfers `tokenId` token from `msg.sender` to `to`.
     * Emits a transfer event
     */
    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);
    }

    /*
     * @dev Internal handling of ownedTokenCount from `msg.sender` to `to`.
     */
    function _transfer(address _from, address _to, uint256 _tokenId) internal {
        // Increase token count of recipient 
        ownedTokenCount[_to]++;
        // set tokenId to recipient
        idToOwner[_tokenId] = _to;

        if (_from != address(0)) {
            // decrease token count from sender
            ownedTokenCount[_from]--;
        }

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

    /*
     * @dev Verifies `msg.sender` owns the NFT.
     */
    function _owns(address _claimant, uint256 _tokenId) internal view returns (bool) {
        return idToOwner[_tokenId] == _claimant;
    }

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

// import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol";
// import "../node_modules/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
// import "../node_modules/@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";

import "./IERC721.sol";

contract kittyContract is IERC721 {
    string constant _name = "kittiCrypto";
    string constant _symbol = "KC";

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

    //Array with all token ids (index==>token id)
    Kiti[] private Kitties;
    //Mapping owner address to token count
    mapping(address => uint256) ownershiptokenCount;
    // Mapping from token ID to owner address
    mapping(uint256 => address) public kittyindexToOwner;

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

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

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

    function balanceOf(address _owner)
        external
        view
        override
        returns (uint256)
    {
        return ownershiptokenCount[_owner];
    }

    function ownerOf(uint256 _tokenId) public view override returns (address) {
        address owner = kittyindexToOwner[_tokenId];
        require(
            owner != address(0),
            "ERC721: owner query for nonexistent token"
        );
        return owner;
    }

    function transfer(address _to, uint256 _tokenId) public view override {
        require(
            _to != address(0) && _to != address(this),
            "ERC721: invalid address"
        );
        require(_to != msg.sender, "ERC721: cannot send to yourselves");
        require(
            _owns(msg.sender, _tokenId),
            "ERC721: you are not the owner of this token"
        );
    }

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

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

2 Likes

Kittycontract.sol

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

import "./IERC721.sol";

contract Kittycontract is IERC721 {

    string public constant name = "KittyCripto";
    string public constant symbol = "KC";

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

   //Arrays of token Ids
   Kitty[] kitties;

//Token Id to owner address
    mapping (uint256 => address) public kittyIndexToOwner;

//Owner amount
    mapping (address => uint256) ownershipTokenCount;

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

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

    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 events
    emit Transfer(_from, _to, _tokenId); 
    }

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

Hello @thecil Happy Sunday :grinning:
Trying to set up Ganache, and is asking me for a chain ID. I did watch the youtube instructions from Ivan and he does give a chain ID 1337, but when I use this ID, it doesn’t allow me to proceed. Kindly let me know how I get this chain ID number.
Thanks a million!

1 Like

have you try with ganache-cli --networkId 1337 ? If you are using ganache UI, share an screenshot about your config on ganache, maybe you are not assigning the network ID 1337 (chain Id for a local blockchain)

Carlos Z

1 Like

Hey @thecil
Thanks so much for your reply, I was trying with ganache UI. I will try ganache-cli, from what I read online so far this is what its recommend as well.
Thanks :star_struck:

2 Likes

Doggycontract.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.13;

import "./IERC721.sol";

contract CryptoDoggys is IERC721 {
    string public constant doggyTokenName = "CryptoDoggys";
    string public constant doggyTokenSymbol = "CD";

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

    Doggy[] doggys;

    mapping(address => uint256) tokenOwnershipCount; //Token owners balance
    mapping(uint256 => address) public tokenIdOwnerMapping; //Maps TokenId to owners address


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

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

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

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

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

    function transfer(address to, uint256 _tokenId) external {
         require(_owns(msg.sender, _tokenId), "You are not the owner of this token!");
         require(to != address(0), "You cannot send tokens to this address!");
         require(to != address(this), "You cannot send tokens to this address!");

         _transfer(msg.sender, to, _tokenId);

         
     }

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

            tokenIdOwnerMapping[_tokenId] = _to;

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

            emit Transfer(_from, _to, _tokenId);
     }

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

Kittycontract.sol

pragma solidity 0.8.0;

import "./IERC721.sol";

contract Kittycontract is IERC721 {
    
    mapping(address => uint) OwnershipTokenCout;
    mapping(uint => address)  public TokenIdOwner;
    

    string public constant projectName = "CreativeKitties";
    string public constant projectSymbol = "CK";

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

    Kitty[] kitties;

    

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

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

    function name() external override view returns (string memory tokenName) {
        return projectName;
    }
  
    function symbol() external override view returns (string memory tokenSymbol) {
        return projectSymbol;
    }

    function ownerOf(uint256 tokenId) external override view returns (address owner) {
        return TokenIdOwner[tokenId];
    }
  
    function transfer(address _to, uint256 _tokenId) external override {
        require(_to != address(0), 'Cant send to 0 address');
        require(_to != address(this), 'Cant send to this contract');
        require(TokenIdOwner[_tokenId] == address(msg.sender), 'You dont own this token'); 

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

    function _transfer(address _from, address _to, uint _tokenId) internal {
        OwnershipTokenCout[_to] ++;
        TokenIdOwner[_tokenId] = _to;

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

}
2 Likes

KittyContracts.sol

pragma solidity ^0.8.15;

import "./IERC721.sol";

contract KittyContract is IERC721{

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

    // Mapping from token ID to owner address
    mapping(uint256 => address) private _owners;

    //stuct of kittens
    struct kitten{
        uint genes;
        uint64 birthTime;
        uint32 momId;
        uint32 dadId;
        uint16 generation;
    }

    //array of kittens for totalSupply function
    kitten[] internal kittens;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

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

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

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

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

    function ownerOf(uint256 tokenId) external view returns (address owner){
        require(_owners[tokenId] != address(0), "ERC721: invalid token ID");
        return _owners[tokenId];
    }

    function transfer(address to, uint256 tokenId) external{
        require(to != address(0), "ERC721: transfer to the zero address");
        require(to != address(this), "Cannot transfer to the contract address");
        require(_owners[tokenId] == address(msg.sender), 'nice try but you dont own this');

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

Good afternoon everybody!!

I have to say it was rough to start coding Solidity since so long, but I think I got it right.
I had to change the compiler, cause mine was already working at ^0.8.0
I did this, but I hope this won’t fireback in the future with this project.
Oh well… Only one way to find out.

Anyhow, here’s my code.

pragma solidity ^0.5.0;

import "./IERC721.sol";

contract KittyContract is IERC721 {

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

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

//stuct of kitty
struct Kitty{
    uint256 genes;
    uint256 timeOfBirth;
    uint256 momGenes;
    uint256 dadGenes;
    uint256 generation;
}

//array of kitty's called Kittens for totalSupply function
Kitty[] Kittens;

// Token name 
string private tokenName = "HelloKitties";

// Token symbol 
string constant tokenSymbol = "KITTY";


/**
     * @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 (uint256 total){
        return Kittens.length +1;
    }
    /*
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory tokenName){
        return tokenName;
    }

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

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner){
        require(tokenIdHolder[tokenId] != address(0), "ERC721: Invalid token ID");
        return tokenIdHolder[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{
    require(to != address(0), "Cannot transfer token to Zero address");
    require(to != address(this), "Cannot send token to Contract");
    require(tokenIdHolder[tokenId] == msg.sender, "Token must be yours if you want to send it");

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

2 Likes

It should not fireback any issue, but if you are learning while doing the course, i could advice to stick with the version used in the course, there are some few changes on version 0.8.0 and below, that the version 0.5.0 does not have.

You can read more about it here if you are interested: https://solidity.readthedocs.io/en/latest/

Carlos Z

2 Likes

Hello, I have a questions for this assignment:

Based on the tutorial, I’m still confuse on why does filip set an internal function for _owns since the mapping for balanceOf is already exist? Does this 2 fit the same criteria?

Here is my example code :

 // owner address to token count
    mapping(address => uint256) internal _balanceOf; >> I use this instead of _owns

function transfer(address to, uint256 tokenId) external {
if (_ownerOf[tokenId] != msg.sender) revert Kitty__NotOwner(); >> require statement from mapping instead of internal _own function.

_transfer(msg.sender, to, tokenId; >> from internal function
}

Thanks in advance!

2 Likes

Indeed, the balanceOf mapping from the ERC721 contract fits the same criteria than the mapping that filip shows in the video, although he could just made an example for an internal mapping.

This is the new methodology for reverts. It does the same than require(_ownerOf[tokenId] == msg.sender, "Kitty__NotOwner");

Carlos Z

1 Like

Got it, I purposely wanted to change the syntax so I can fully understand it and that is why I use revert method for gas optimization lol. Thanks!

2 Likes

Here is my solution for this exercise.

Bearcontract.sol

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

import "./IERC721.sol";

contract Bearcontract is IERC721 {

    mapping(address => uint256) ownershipTokenCount;
    mapping(uint256 => address) tokenOwner;
    uint256 public bearSupply;
    string public bearTicker = "AcademyBear";
    string public bearSymbol = "ABT";

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

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

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

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

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

    function transfer(address to, uint256 tokenId) external {
        require(to != address(0), "Invalid Address; Cannot transfer to Address 0!");
        require(to != address(this), "Invalid Address; Cannot transfer to Contract Address!");
        require(tokenOwner[tokenId] == address(msg.sender), "Invalid Address; Cannot transfer to own Address!");
        emit Transfer(msg.sender, to, tokenId);
    }
}
2 Likes

Hello,
here is my first implementation of Kittycontract.sol, compiled with solc 0.8.17 but not yet tested. :nerd_face:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./IERC721.sol";

contract Kittycontract is IERC721{


    //Associates an EOA with its balance
    mapping(address => uint) private balances; 

    //Associates a token id with its owner
    mapping(uint => address) private tokenowners;


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

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

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

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

    // Reverts if a token id does not exists?
    function ownerOf(uint256 tokenid) external view returns (address owner){

        owner = tokenowners[tokenid];

        require(owner != address(0), 'Token id does not exist');

        return owner;
    }

    function transfer(address to, uint256 tokenId) external{

        require(to != address(0), 'invalid to address');
        require(to != address(this), 'to cannot be the contract address');

        address owner = tokenowners[tokenId];

        require(owner != address(0), 'Token id does not exist');
        require(msg.sender == owner, 'only owner can make a transfer');

        tokenowners[tokenId] = to;

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

    }
}






1 Like

Kittycontract.sol

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
import "./IERC721.sol";

contract Kittycontract is IERC721 {
	uint256 public total;             // Total number of tokens

	mapping(address => uint256) ownershipTokenCount;
	mapping(uint256 => address) owners;
	string public name;                   // Descriptive name 
	string public symbol;                 // Short identifier for token (i.e. KTY)

	constructor(string memory _tokenName, string memory _tokenSymbol) public {
		name = _tokenName;
		symbol = _tokenSymbol;           

 
	}

	function balanceOf(address owner) external view returns (uint256 balance) {
		return ownershipTokenCount[owner];
	}
	// Return the total number of tokens in circulation
	function totalSupply() external view returns (uint256 total) {
		return total;
	}
	// Returns the name of the token.
	function name() external view returns (uint256 name) {
		return name;
	}
	// Returns the symbol of the token.
	function symbol() external view returns (uint256 symbol) {
		return symbol;
	}
	function ownerOf(uint256 tokenId) external view returns (address owner) {
		return owners[tokenId];
	}



}

1 Like