Assignment - Marketplace Contract Coding

You should be sending the tokenContractAddress to the function, but you are assigning it like if setCatContract is a variable (but is not a variable, is a function that set the variable value to whatever you assign).

Try setCatContract(tokenContractAddress) instead in the constructor.

Carlos Z

1 Like

Marketplace.sol

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

import "./Kittycontract.sol";
import "./Ownable.sol";
import "./IKittyMarketplace.sol";

contract KittyMarketplace is Ownable, IKittyMarketPlace {
    Kittycontract private _kittyContract;

    struct Offer {
        address payable seller;
        uint256 price;
        uint256 index;
        uint256 tokenId;
        bool active;
    }
    Offer[] offers;

    event MarketTransaction(string TxType, address owner, uint256);

     mapping(uint256 => Offer) tokenIdToOffer;

     function setKittyContract(address _kittyContractAddress) public onlyowner {
         _kittyContract = kittycontract(_kittyContractAddress);
     }
     constructor(address _kittyContractAddress) public {
         setKittyContract(_kittyContractAddress);
     }

     function getOffer(uint256 _tokenId)
     public
     view
     returns
( 
    address seller, 
    uint256 price,
    uint256 index, 
    uint256 tokenId, 
    bool active

) {
    Offer storage offer = tokenIdToOffer[_tokenId];
    return (
        offer.seller,
        offer.price,
        offer.index,
        offer.tokenId,
        offer.active
    );
}

function getAllTokenOnSale() public returns(uint256[] memory listOfOffers) {
    uint256 totalOffers = offers.lenght;

    if (totalOffers == 0){
        return new uint256[](0);
    }else 

        uint256[] memory result = new uint256[](totalOffers);

        uint256 offerId;

        for(offerId = 0; offerId < totalOffers; offerId++){
            if (offers[offerId].active == true){
                result[offerId] = offers[offerId].tokenId;
            }
        }
        return result;
    }
}

    function _ownsKitty(address _address, uint256 _tokenId)
        internal
        view
        returns (bool)
    
    {
        return (_kittyContract.ownerOf(tokenId) == _address);

    }

    /*
     * create a new offer based for the given tokenId and price
     */ 
    function setOffer(uint256 _price, uint256 _tokenId) public {
        require (
            _ownsKitty(msg.sender, _tokenId),
            "You are not the true owner of the kitty"
        );
        require(tokenIdToOffer[_tokenId].active == false, "You can't sell twice the same offers");
        require(_kittyContract.isApprovedForAll(msg.sender, address(this)), "Contract needs to be approved to transfer the kitty in the future");
        
        Offer memory _offer = Offer ({
            seller: msg.sender, 
            price: _price, 
            active: true,
            tokenId: _tokenId,
            index: offers.length
        });

        tokenIdToOffer[_tokenId] = _offer;
        offers.push(_offer);

        emit MarketTransaction("Create offer", msg.sender, _tokenId);
    }

    /*
    * Remove an existing offers
    */
    function removeOffer(uint256 _tokenId) public {
        Offer memory offer = tokenIdToOffer[_tokenId];
        require(
            offer.seller == msg.sender,
            "You are not the seller of that kitty"
        );

        delete tokenIdToOffer[_tokenId];
        offers[tokenIdToOffer[_tokenId].index].active = false;

        emit MarketTransaction("Rmove offer", msg.sender, _tokenId);
    }

    /*
    * Accept an offer and buy the kitty
    */ 
    function buyKitty(uint256 _tokenId) public payable {
        Offer memory offer = tokenIdToOffer[_tokenId];
        require(msg.value == offer.price, "The price is incorrect");
        require(tokenIdToOffer[_tokenId].active == true, "No active order present");

        //Important: delete the kitty from the mapping BEFORE paying out to prevent reentry attacks 
        delete tokenIdToOffer[_tokenId];
        offers[offer.index].active = false;

        //Transfer the funds to the seller
        // To do: make this logic pull instead of push
        if(offer.price> 0) {
            offer.seller.transfer(offer.price);
        }

        //Transfer ownership of the kitty
        _kittyContract.transferFrom(offer.seller, msg.sender, _tokenId);

        emit MarketTransaction("Buy", msg.sender, _tokenId);
    }


1 Like

KittyMarketplace.sol

pragma solidity 0.8.0;

import "./Kittycontract.sol";
import "./Ownable.sol";
import "./IKittyMarketplace.sol";

contract KittyMarketPlace is Ownable, IKittyMarketPlace {
    Kittycontract private _kittyContract;

    struct Offer {
        address payable seller;
        uint price;
        uint index;
        uint tokenId;
        bool active;
    }

    Offer[] offers;


    mapping(uint => Offer) tokenIdToOffer;

    function setKittyContract(address _kittyContractAddress) public override onlyOwner {
        _kittyContract = Kittycontract(_kittyContractAddress);
    }

    constructor(address _kittyContractAddress) {
        setKittyContract(_kittyContractAddress);
    }

    function getOffer(uint256 _tokenId) external view override returns (address seller, uint256 price, uint256 index, uint256 tokenId, bool active) {
        seller = tokenIdToOffer[_tokenId].seller;
        price = tokenIdToOffer[_tokenId].price;
        index = tokenIdToOffer[_tokenId].index;
        tokenId = _tokenId;
        active = tokenIdToOffer[_tokenId].active;
        
        return (seller, price, index, tokenId, active);
    }

    function getAllTokenOnSale() external view override returns(uint256[] memory listOfOffers) {
        uint256 totalOffers = offers.length;

        if(totalOffers == 0) {
            return new uint[](0);
        } else {

            uint[] memory result = new uint[](totalOffers);

            for (uint256 i = 0; i < totalOffers; i++) {
                if(offers[i].active == true) {
                    result[i] = offers[i].tokenId;
                }
            }
        return result;
        }
    }

    function setOffer(uint256 _price, uint256 _tokenId) external override {
        require(_kittyContract._owns(msg.sender, _tokenId));
        require(tokenIdToOffer[_tokenId].active == false);
        require(_kittyContract.isApprovedForAll(msg.sender, address(this)));

        Offer memory newOffer = Offer({
            seller: payable(msg.sender), 
            price: _price, 
            index: offers.length, 
            tokenId: _tokenId, 
            active: true
        });

        tokenIdToOffer[_tokenId] = newOffer;
        offers.push(newOffer);

        emit MarketTransaction("Create offer", msg.sender, _tokenId);
    }
        
    function removeOffer(uint256 _tokenId) external override {
        Offer memory offer = tokenIdToOffer[_tokenId];
        require(offer.seller == msg.sender);

        delete tokenIdToOffer[_tokenId];
        offers[offer.index].active = false;
        
        emit MarketTransaction("Remove offer", msg.sender, _tokenId);
    }

    function buyKitty(uint256 _tokenId) external override payable {
        Offer memory offer = tokenIdToOffer[_tokenId];
        require(msg.value == offer.price);
        require(offer.active == true);
        
        delete tokenIdToOffer[_tokenId];
        offers[offer.index].active = false;

        if(offer.price > 0) {
            offer.seller.transfer(offer.price);
        }
        
        _kittyContract.transferFrom(offer.seller, msg.sender, _tokenId);
        
        emit MarketTransaction("Buy", msg.sender, _tokenId);
    }
}
1 Like

here is the current status of my Marketplace.

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

import "./Bearcontract.sol";
import "./Ownable.sol";
import "./IBearMarketPlace.sol";

contract BearMarket is Ownable, IBearMarketPlace {

    Bearcontract private _bearcontract;

    struct Offer {
        address payable seller;
        uint256 price;
        uint256 index;
        uint256 tokenId;
        bool active;
    }

    Offer[] offers;

    mapping(uint256 => Offer) tokenIdToOffer;


    //Function and constructor to set the Bearcontract
    function setBearContract(address _bearContractAddress) onlyOwner public {
        _bearcontract = Bearcontract(_bearContractAddress);
    }

    constructor(address _bearContractAddress) public {
        setBearContract(_bearContractAddress);
    }
    
    //Get the details about a offer for tokenId. Throws an error if there is no active offer for tokenId.
    function getOffer(uint256 tokenId) public view returns (address seller, uint256 price, uint256 index, uint256 _tokenId, bool active) {
        Offer storage offer = tokenIdToOffer[tokenId];
        require(offer.active, "no active offer on this tokenId");
        return(
            offer.seller,
            offer.price,
            offer.index,
            offer.tokenId,
            offer.active
        );
    }
    
    //Get all tokenId's that are currently for sale. Returns an empty array if none exist.
    function getAllTokenOnSale() external view  returns(uint256[] memory listOfOffers) {
        uint256 totalOffers = offers.length;

        if (totalOffers == 0) {
            return new uint256[](0);
        } else {
            uint256[] memory result = new uint256[](totalOffers);

            uint256 offerId;

            for (offerId = 0; offerId < totalOffers; offerId++) {
                if(offers[offerId].active == true){
                    result[offerId] = offers[offerId].tokenId;
                }
            }
            return result;
        }
    }
    
    //Creates a new offer for tokenId for the price price.
    function setOffer(uint256 price, uint256 tokenId) public {
        require(_ownsBear(msg.sender, tokenId), "You are not the token owner!");
        require(tokenIdToOffer[tokenId].active == false, "You cannot add a second offer!");
        require(_bearcontract.isApprovedForAll(msg.sender, address(this)), "Contract needs to be approved for all!");

        Offer memory offer = Offer({
            seller: payable (msg.sender),
            price: price,
            active: true,
            tokenId: tokenId,
            index: offers.length
        });

        tokenIdToOffer[tokenId] = offer;
        offers.push(offer);

        emit MarketTransaction("Create Offer", msg.sender, tokenId);
    }
    
    //Removes an existing offer.
    function removeOffer(uint256 tokenId) public {
        Offer memory offer = tokenIdToOffer[tokenId];

        require(offer.seller == msg.sender, "You are not the seller!");

        delete tokenIdToOffer[tokenId];
        offers[tokenIdToOffer[tokenId].index].active = false;

        emit MarketTransaction("Remove Offer", msg.sender, tokenId);
    }
    
    //Executes the purchase of tokenId.
    function buyBear(uint256 tokenId) public payable {
        Offer memory offer = tokenIdToOffer[tokenId];
        require(msg.value == offer.price, "Value does not match price!");
        require(tokenIdToOffer[tokenId].active == true, "No active order!");

        delete tokenIdToOffer[tokenId];
        offers[tokenIdToOffer[tokenId].index].active = false;

        if (offer.price > 0){
            offer.seller.transfer(offer.price);
        }

        _bearcontract.transferFrom(offer.seller, msg.sender, tokenId);

        emit MarketTransaction("Buy Bear", msg.sender, tokenId);
    }

    //Checks if current address is token owner
    function _ownsBear(address _address, uint256 _tokenId) internal view returns (bool) {
        return (_bearcontract.ownerOf(_tokenId) == _address);
    }
}
1 Like
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;

import "./kittyContract.sol";
import "./Ownable.sol";
import "./IKittyMarketplace.sol";

contract kittyMarketplace is Ownable, IKittyMarketplace {
    Kittycontract private _kittyContract;

    struct Offer {
        address payable seller;
        uint256 price;
        uint256 index;
        uint256 tokenId;
        bool active;
    }

    Offer[] offers;

    mapping(uint256 => Offer) tokenIdToOffer;

    event MarketTransaction(string TxType, address owner, uint256 tokenId);

    /**
    * Set the current KittyContract address and initialize the instance of Kittycontract.
    * Requirement: Only the contract owner can call.
     */
    function setKittyContract(address _kittyContractAddress) external onlyOwner{
        _kittyContract = KittyContract(_kittyContractAddress);
    }

    constructor (address _kittyContractAddress) public{
        setKittyContract(_kittyContractAddress);
    }

    /**
    * Get the details about a offer for _tokenId. Throws an error if there is no active offer for _tokenId.
     */
    function getOffer(uint256 _tokenId) external view 
    returns ( 
        address seller, 
        uint256 price, 
        uint256 index, 
        uint256 tokenId, 
        bool active){

            Offer storage offer = tokenIdToOffer[_tokenId];
            return (
                offer.seller,
                offer.price,
                offer.index,
                offer.tokenId,
                offer.active
                );

            }

       /**
    * Get all tokenId's that are currently for sale. Returns an empty arror if none exist.
     */
    function getAllTokenOnSale() external view  returns(uint256[] memory listOfOffers){
        uint256 totalOffers = offers.length;

        if(totalOffers == 0){
            return new uint256[](0);
        } else
        {
            uint256 memory result = new uint256[](totalOffers);

            uint256 offerId;

            for(offerId = 0;offerId < totalOffers; offerId++) {
                if(offers[offerId].active == true){
                    result[offerId] = offers[offerId].tokenId;
                }
            }
            return result;
                }
            }

    function _ownsKitty(address _address, uint256 _tokenId) internal view returns(bool) {
        return(_kittyContract.ownerOf(_tokenId) == _address);
    }

     /**
    * Creates a new offer for _tokenId for the price _price.
    * Emits the MarketTransaction event with txType "Create offer"
    * Requirement: Only the owner of _tokenId can create an offer.
    * Requirement: There can only be one active offer for a token at a time.
    * Requirement: Marketplace contract (this) needs to be an approved operator when the offer is created.
     */
    function setOffer(uint256 _price, uint256 _tokenId) external{
        require(_wnsKitty(msg.sender,_tokenId));
        require(tokenToOffer[_tokenId].active == false, "Only one active offer at a time");
        require(_kittyContract.isApprovedForAll(msg.sender,address(this)));

        Offer memory _offer = _offer({
            seller: msg.sender,
            price: _price,
            index: offers.length,
            active: true,
            tokenId: _tokenId
        });

        tokenIdToOffer[_tokenId] = _offer;
        offers.push(_offer);

        emit MarketTransaction("Create Offer", msg.sender, _tokenId);

    }

    /**
    * Removes an existing offer.
    * Emits the MarketTransaction event with txType "Remove offer"
    * Requirement: Only the seller of _tokenId can remove an offer.
     */
    function removeOffer(uint256 _tokenId) external{
        Offer memory offer = tokenIdToOffer[_tokenId];
        require(offer.sender == msg.sender,
         "You can not remove the offer.");

         delete tokenIdToOffer[_tokenId];
         offers[tokenIdToOffer[_tokenId].index].active = false;

         emit MarketTransaction("Offer Removed", msg.sender, _tokenId);
    }

    /**
    * Executes the purchase of _tokenId.
    * Sends the funds to the seller and transfers the token using transferFrom in Kittycontract.
    * Emits the MarketTransaction event with txType "Buy".
    * Requirement: The msg.value needs to equal the price of _tokenId
    * Requirement: There must be an active offer for _tokenId
     */
    function buyKitty(uint256 _tokenId) external payable{
        Offer memory offer = tokenIdToOffer[_tokenId];
        require(offer.price == msg.value, "Invalid price");
        require(tokenIdToOffer[_tokenId].active == true, "This kitty isn't for sale.");

        delete tokenIdToOffer[_tokenId];
        tokenIdToOffer[_tokenId].active == false;

        if(offer.price > 0) {
            offer.seller.transfer(offer.price);
        }

        _kittyContract.transferFrom(offer.seller, msg.sender,_tokenId);

        emit MarketTransaction("Buy", msg.sender, _tokenId);
    }
        }
1 Like

So, I canā€™t figure any of this stuff out on my own so, I basically have to follow Filipā€™s solutions.

However, Filipā€™s code does not seem to work ā€œout of the boxā€ and, trying to figure out why the code I am copying, does not work for me, like it does for Filip in the videosā€¦is like trying to look for a needle in a haystack (for me).

Sometimes it is just a typo on my end, sometimes itā€™s different compiler issues that require some tweeks in the code and, sometimes it is because I have 22 digits (11 pairs) in my dna string.

However, I finally got my code working. It is basically Filipā€™s code with some adjustments, to make it work on my endā€¦and, even that, was super challenging for me.

Here is the working code:

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

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

contract KittyContract is IERC721, Ownable {

    uint256 public constant CREATION_LIMIT_GEN0 = 10;
    string public constant name = "RadKitty";
    string public constant symbol = "RK";

    bytes4 internal constant MAGIC_ERC721_RECEIVED = bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"));

    /*
     *     bytes4(keccak256('balanceOf(address)')) == 0x70a08231
     *     bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e
     *     bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3
     *     bytes4(keccak256('getApproved(uint256)')) == 0x081812fc
     *     bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465
     *     bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5
     *     bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde
     *
     *     => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^
     *        0xa22cb465 ^ 0xe985e9c ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
     */
    bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;

    /*
     *     bytes4(keccak256('supportsInterface(bytes4)'));
     */
    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;

    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;
    mapping(address => uint256) ownershipTokenCount;

    mapping(uint256 => address) public kittyIndexToApproved;
    mapping(address => mapping (address => bool)) private _operatorApprovals;

    uint256 public gen0Counter;

    constructor() {
        _createKitty(0, 0, 0, 1122334455667788990011, address(0));
    }

    function breed(uint256 _dadId, uint256 _mumId) public returns (uint256){
        require(_owns(msg.sender, _dadId), "The user doesn't own the token");
        require(_owns(msg.sender, _mumId), "The user doesn't own the token");

        ( uint256 dadDna,,,,uint256 DadGeneration ) = getKitty(_dadId);

        ( uint256 mumDna,,,,uint256 MumGeneration ) = getKitty(_mumId);
        
        uint256 newDna = _mixDna(dadDna, mumDna);

        uint256 kidGen = 0;
        if (DadGeneration < MumGeneration){
            kidGen = MumGeneration + 1;
            kidGen /= 2;
        } else if (DadGeneration > MumGeneration){
            kidGen = DadGeneration + 1;
            kidGen /= 2;
        } else{
            kidGen = MumGeneration + 1;
        }

        _createKitty(_mumId, _dadId, kidGen, newDna, msg.sender);
        return newDna;

    }

    function supportsInterface(bytes4 _interfaceId) external pure returns (bool) {
        return (_interfaceId == _INTERFACE_ID_ERC721 || _interfaceId == _INTERFACE_ID_ERC165);
    }

    function approve(address _to, uint256 _tokenId) public {
        require(_owns(msg.sender, _tokenId));

        _approve(_tokenId, _to);
        emit Approval(msg.sender, _to, _tokenId);
    }

    function setApprovalForAll(address operator, bool approved) public {
        require(operator != msg.sender);
        
        _operatorApprovals[msg.sender][operator] = approved;
        emit ApprovalForAll(msg.sender, operator, approved);
    }

    function getApproved(uint256 tokenId) public view returns (address) {
        require(tokenId < kitties.length); //Token must exist

        return kittyIndexToApproved[tokenId];
    }

    function isApprovedForAll(address owner, address operator) public view returns (bool) {
        return _operatorApprovals[owner][operator];
    }

  function getKittyByOwner(address _owner) external view returns(uint[] memory) {
    uint[] memory result = new uint[](ownershipTokenCount[_owner]);
    uint counter = 0;
    for (uint i = 0; i < kitties.length; i++) {
      if (kittyIndexToOwner[i] == _owner) {
        result[counter] = i;
        counter++;
      }
    }
    return result;
  }

    function safeTransferFrom(address _from, address _to, uint256 _tokenId) public {
        safeTransferFrom(_from, _to, _tokenId, "");
    }

    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes memory _data) public {
        require( _isApprovedOrOwner(msg.sender, _from, _to, _tokenId) );
        _safeTransfer(_from, _to, _tokenId, _data);
    }

    function _safeTransfer(address _from, address _to, uint256 _tokenId, bytes memory _data) internal {
        _transfer(_from, _to, _tokenId);
        require(_checkERC721Support(_from, _to, _tokenId, _data));
    }

    function transferFrom(address _from, address _to, uint256 _tokenId) public {
      require(_to != address(0));
        require(msg.sender == _from || _approvedFor(msg.sender, _tokenId) || isApprovedForAll(_from, msg.sender));
        require(_owns(_from, _tokenId));
        require(_tokenId < kitties.length);
        
        //_transfer(msg.sender, _to, _tokenId); //<=Old code
        
        require(_isApprovedOrOwner(msg.sender, _from, _to, _tokenId));

        _transfer(_from, _to, _tokenId); //Newer code
    }




    function getKitty(uint256 _id) public view returns (
        uint256 genes,
        uint256 birthTime,
        uint256 mumId,
        uint256 dadId,
        uint256 generation
    )
    {
        Kitty storage kitty = kitties[_id];

        birthTime = uint256(kitty.birthTime);
        mumId = uint256(kitty.mumId);
        dadId = uint256(kitty.dadId);
        generation = uint256(kitty.generation);
        genes = kitty.genes;
    }

  // Counts the number of cats the contract owner has created.

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

        gen0Counter++;

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

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

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

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

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

        return newKittenId;
    }

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

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

    function ownerOf(uint256 _tokenId) external view returns (address owner) {
        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]--;
            delete kittyIndexToApproved[_tokenId];
        }

        emit Transfer(_from, _to, _tokenId);
    }

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

    function _approve(uint256 _tokenId, address _approved) internal {
        kittyIndexToApproved[_tokenId] = _approved;
    }

    function _approvedFor(address _claimant, uint _tokenId) internal view returns (bool) {
        return kittyIndexToApproved[_tokenId] == _claimant;
    }

    function _checkERC721Support(address _from, address _to, uint256 _tokenId, bytes memory _data) internal returns (bool) {
        if(!_isContract(_to)){
            return true;
        }
        
        //Call onERC721Received in thte _to contract
        bytes4 returnData = IERC721Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data);
        //Check return value
        return returnData == MAGIC_ERC721_RECEIVED;


    }

    function _isContract(address _to) view internal returns (bool) {
        uint32 size;
        assembly{
            size := extcodesize(_to)
        }
        return size > 0;
    }

    function _isApprovedOrOwner(address _spender, address _from, address _to, uint256 _tokenId) internal view returns (bool) {
        require(_tokenId < kitties.length); //Token must exist
        require(_to != address(0)); //TO address is not zero address
        require(_owns(_from, _tokenId)); //From owns the token
        
        //spender is from OR spender is approved for tokenId OR spender is operator for from
        return (_spender == _from || _approvedFor(_spender, _tokenId) || isApprovedForAll(_from, _spender));
    }

    function _mixDna( uint256 _mumDna, uint256 _dadDna) public view returns(uint256) {
        uint256[11] memory geneArray;
        uint16 random = uint16(block.timestamp % 65535);
        
        uint256 i = 1;
        uint256 index = 10;

        for(i = 1; i <=1024; i = i * 2){
            if(random & i != 0){
                geneArray[index] = uint16(_mumDna % 100);
            } else{
                geneArray[index] = uint16(_dadDna % 100);
            }
            _mumDna = _mumDna / 100;            
            _dadDna = _dadDna / 100;

            if(i != 1024){index = index -1;}
        }

        uint256 newGene;
        for(i = 0; i < 11; i++){
            newGene = newGene + geneArray[i];
            if(i !=10){
                newGene = newGene * 100;
            }
        }
        return newGene;

    //    1.  0000000000000001 = 1
    //    2.  0000000000000010 = 2
    //    3.  0000000000000100 = 4
    //    4.  0000000000001000 = 8
    //    5.  0000000000010000 = 16
    //    6.  0000000000100000 = 32
    //    7.  0000000001000000 = 64
    //    8.  0000000010000000 = 128
    //    9.  0000000000000001 = 256
    //    10. 0000000000000001 = 512
    //    11. 0000000000000001 = 1024
    //    12. 0000000000000001 = 2048
    //    13. 0000000000000001 = 4096
    //    14. 0000000000000001 = 8192
    //    15. 0000000000000001 = 16384
    //    16. 0000000000000001 = 32768


    }

        KittyContract private _kittyContract;

    struct Offer {
        address payable seller;
        uint256 price;
        uint256 index;
        uint256 tokenId;
        bool active;
    }

    Offer[] offers;

    event MarketTransaction(string TxType, address owner, uint256 tokenId);
    
    mapping(uint256 => Offer) tokenIdToOffer;

    function setKittyContract(address _kittyContractAddress) public onlyOwner {
        _kittyContract = KittyContract(_kittyContractAddress);
    }


    function getOffer(uint _tokenId) public view returns (address seller, uint256 price, uint256 index, uint256 tokenId, bool active){
        Offer storage offer = tokenIdToOffer[_tokenId];
        return (
            offer.seller,
            offer.price,
            offer.index,
            offer.tokenId,
            offer.active
        );
    }

    function getAllTokenOnSale() external view returns(uint256[] memory listOfOffers) {
        uint256 totalOffers = offers.length;

        if(totalOffers == 0) {
            return new uint256[](0);
        } else {

            uint256[] memory result = new uint256[](totalOffers); //Size 1 (of Array)

            uint256 offerId;

            for (offerId = 0; offerId < totalOffers; offerId++) {
                if(offers[offerId].active == true) {
                    result[offerId] = offers[offerId].tokenId;
                }
            }
            return result;
        }
    }

    function _ownsKitty(address _address, uint256 _tokenId) internal view returns(bool) {
        return (_kittyContract.ownerOf(_tokenId) == _address);
    }

    //Create New Offer for the given tokenId and price
    function setOffer(uint256 _price, uint256 _tokenId) public {
        require(_ownsKitty(msg.sender, _tokenId), "You are not the owner of that Kitty");
        require(tokenIdToOffer[_tokenId].active == false, "You cannot sell the same offer twice");
        require(_kittyContract.isApprovedForAll(msg.sender, address(this)), "Contract needs to be appoved to transfer kitty in the future");

        Offer memory _offer = Offer({
            seller: payable(msg.sender),
            price: _price,
            active: true,
            tokenId: _tokenId,
            index: offers.length
        });

        tokenIdToOffer[_tokenId] = _offer;
        offers.push(_offer);

        emit MarketTransaction("Create offer", msg.sender, _tokenId);
    }

    //Remove existing offer
    function removeOffer(uint256 _tokenId) public {
       
        Offer memory offer = tokenIdToOffer[_tokenId];
        require(offer.seller == msg.sender, "You are not the seller of that Kitty");

        delete tokenIdToOffer[_tokenId];
        offers[offer.index].active = false;
        
        emit MarketTransaction("Remove Offer", msg.sender, _tokenId);
    }

    //Accept offer and buy Kitty
    function buyKitty(uint256 _tokenId) public payable {
        Offer memory offer = tokenIdToOffer[_tokenId];
        require(msg.value == offer.price, "The price is incorrect");
        require(tokenIdToOffer[_tokenId].active == true, "Not active");

        //Important to delete Kitty from mapping BEFORE paying out to prevent re-entry attacks
        delete tokenIdToOffer[_tokenId];
        offers[offer.index].active = false;

        //Transfer funds to the seller
        // TO DO: make this logic pull instead of push 
        if(offer.price > 0){
            offer.seller.transfer(offer.price);
        }

        //Transfer ownership of the Kitty
        _kittyContract.transferFrom(offer.seller, msg.sender, _tokenId);

        emit MarketTransaction("Buy", msg.sender, _tokenId); 
    }

}




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

import "./KittyContract.sol";
import "./Ownable.sol";



contract KittyMarketPlace is Ownable {
    KittyContract private _kittyContract;

    struct Offer {
        address payable seller;
        uint256 price;
        uint256 index;
        uint256 tokenId;
        bool active;
    }

    Offer[] offers;

    event MarketTransaction(string TxType, address owner, uint256 tokenId);
    
    mapping(uint256 => Offer) tokenIdToOffer;

    function setKittyContract(address _kittyContractAddress) public onlyOwner {
        _kittyContract = KittyContract(_kittyContractAddress);
    }

    constructor(address _kittyContractAddress) {
        setKittyContract(_kittyContractAddress);
    }

    function getOffer(uint _tokenId) public view returns (address seller, uint256 price, uint256 index, uint256 tokenId, bool active){
        Offer storage offer = tokenIdToOffer[_tokenId];
        return (
            offer.seller,
            offer.price,
            offer.index,
            offer.tokenId,
            offer.active
        );
    }

    function getAllTokenOnSale() external view returns(uint256[] memory listOfOffers) {
        uint256 totalOffers = offers.length;

        if(totalOffers == 0) {
            return new uint256[](0);
        } else {

            uint256[] memory result = new uint256[](totalOffers); //Size 1 (of Array)

            uint256 offerId;

            for (offerId = 0; offerId < totalOffers; offerId++) {
                if(offers[offerId].active == true) {
                    result[offerId] = offers[offerId].tokenId;
                }
            }
            return result;
        }
    }

    function _ownsKitty(address _address, uint256 _tokenId) internal view returns(bool) {
        return (_kittyContract.ownerOf(_tokenId) == _address);
    }

    //Create New Offer for the given tokenId and price
    function setOffer(uint256 _price, uint256 _tokenId) public {
        require(_ownsKitty(msg.sender, _tokenId), "You are not the owner of that Kitty");
        require(tokenIdToOffer[_tokenId].active == false, "You cannot sell the same offer twice");
        require(_kittyContract.isApprovedForAll(msg.sender, address(this)), "Contract needs to be appoved to transfer kitty in the future");

        Offer memory _offer = Offer({
            seller: payable(msg.sender),
            price: _price,
            active: true,
            tokenId: _tokenId,
            index: offers.length
        });

        tokenIdToOffer[_tokenId] = _offer;
        offers.push(_offer);

        emit MarketTransaction("Create offer", msg.sender, _tokenId);
    }

    //Remove existing offer
    function removeOffer(uint256 _tokenId) public {
       
        Offer memory offer = tokenIdToOffer[_tokenId];
        require(offer.seller == msg.sender, "You are not the seller of that Kitty");

        delete tokenIdToOffer[_tokenId];
        offers[offer.index].active = false;
        
        emit MarketTransaction("Remove Offer", msg.sender, _tokenId);
    }

    //Accept offer and buy Kitty
    function buyKitty(uint256 _tokenId) public payable {
        Offer memory offer = tokenIdToOffer[_tokenId];
        require(msg.value == offer.price, "The price is incorrect");
        require(tokenIdToOffer[_tokenId].active == true, "Not active");

        //Important to delete Kitty from mapping BEFORE paying out to prevent re-entry attacks
        delete tokenIdToOffer[_tokenId];
        offers[offer.index].active = false;

        //Transfer funds to the seller
        // TO DO: make this logic pull instead of push 
        if(offer.price > 0){
            offer.seller.transfer(offer.price);
        }

        //Transfer ownership of the Kitty
        _kittyContract.transferFrom(offer.seller, msg.sender, _tokenId);

        emit MarketTransaction("Buy", msg.sender, _tokenId); 
    }

}
3_marketplace_migration.js
const KittyContract = artifacts.require("KittyContract");
const KittyMarketPlace = artifacts.require("KittyMarketPlace");

module.exports = function (deployer) {
  deployer.deploy(KittyMarketPlace, KittyContract.address);
};
1 Like
pragma solidity >=0.4.22 <0.9.0;

import "../node_modules/@openzeppelin/contracts/access/Ownable.sol";
import "../node_modules/@openzeppelin/contracts/utils/math/SafeMath.sol";
import "./IKittyMarketplace.sol";
import "./Kitty.sol";

contract KittyMarketPlace is Ownable, IKittyMarketPlace {
    using SafeMath for uint256;

    Kittycontract private _kittyContract;
    function getKittycontract() external returns(Kittycontract) {
        return _kittyContract;
    }

    struct Offer {
        address payable seller;
        uint256 price;
        uint256 index;
        uint256 tokenId;
        bool active;
    }

    Offer[] offers;

    mapping(uint256 => Offer) tokenIdToOffer;

    function setKittyContract(address _kittyContractAddress) external onlyOwner {
        _kittyContract = Kittycontract(_kittyContractAddress);
    }

    function getOffer(uint256 _tokenId) external view override returns (address seller, uint256 price, uint256 index, uint256 tokenId, bool active) {
        Offer storage offer = tokenIdToOffer[_tokenId];
        require(offer.active, "No active offer for this token");
        return (offer.seller, offer.price, offer.index, offer.tokenId, offer.active);
    }

    function getAllTokenOnSale() external view override returns(uint256[] memory listOfOffers) {
        uint256 totalOffers = offers.length;
        if (totalOffers == 0) {
            return new uint256[](0);
        } else {
            uint256[] memory result = new uint256[](totalOffers);
            uint256 offerId;
            for (offerId = 0; offerId < totalOffers; offerId++) {
                if (offers[offerId].active == true) {
                    result[offerId] = offers[offerId].tokenId;
                }
            }
            return result;
        }
    }

    function setOffer(uint256 _price, uint256 _tokenId) external override {
        require(_kittyContract.ownerOf(_tokenId) == msg.sender, "Only token owner can create an offer");
        require(tokenIdToOffer[_tokenId].active == false, "Token already has an active offer");
        require(_kittyContract.getApproved(_tokenId) == address(this), "Marketplace contract needs to be an approved operator when the offer is created");
        Offer memory newOffer = Offer({
            seller: payable(msg.sender),
            price: _price,
            index: offers.length,
            tokenId: _tokenId,
            active: true
        });
        offers.push(newOffer);
        tokenIdToOffer[_tokenId] = newOffer;
        emit MarketTransaction("Create offer", msg.sender, _tokenId);
    }

    function removeOffer(uint256 _tokenId) external override {
        Offer storage offer = tokenIdToOffer[_tokenId];
        require(offer.active == true, "No active offer for this token");
        require(offer.seller == msg.sender, "Only seller can remove an offer");
        offer.active = false;
        emit MarketTransaction("Remove offer", msg.sender, _tokenId);
    }

    function buyKitty(uint256 _tokenId) external payable {
        Offer memory offer = tokenIdToOffer[_tokenId];
        require(msg.value == offer.price, "Incorrect price");
        require(offer.active == true, "Offer not active");
        require(_kittyContract.ownerOf(_tokenId) == offer.seller, "Only seller can sell the token");

        

        address payable seller = offer.seller;
        _kittyContract.transferFrom(seller, msg.sender, _tokenId);
        seller.transfer(msg.value);

        offer.active = false;
        tokenIdToOffer[_tokenId] = offer;

        emit MarketTransaction("Buy", msg.sender, _tokenId);
    }
}

Hi, I have this problem: Invalid type for argument in function call. Invalid implicit conversion from address to address payable requested. in setOffer():

 Offer memory _offer = Offer({ 
        seller: msg.sender,
        price: _price,
        active: true,
        tokenId: _tokenId,
        index: offers.length
    });

and also I have this error: Contract "KittyMarketplace" should be marked as abstract.

This is KittyMarketplace contract:

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

import "./Kittycontract.sol";
import "./IKittyMarketplace.sol";

contract KittyMarketplace is IKittyMarketPlace{
    KittyContract private _kittyContract;

    struct Offer{
        address payable seller;
        uint256 price;
        uint256 index;
        uint256 tokenId;
        bool active;
    }

    Offer[] offers;

    mapping(uint256 => Offer) tokenIdToOffer;

    function setKittyContract(address _kittyContractAddress) public { //onlyOwner
        _kittyContract = KittyContract(_kittyContractAddress); // initialize _kittyContract to KittyContract for _kittyContractAddress
    }

    constructor(address _kittyContractAddress) public {
        setKittyContract(_kittyContractAddress);
    }

    function getOffer(uint256 _tokenId) public view returns(
        address seller, 
        uint256 price,
        uint256 index,
        uint256 tokenId,
        bool active
    ){
        Offer storage offer = tokenIdToOffer[_tokenId]; // getting offer from the mapping for _tokenId
        return(
            offer.seller,
            offer.price,
            offer.index,
            offer.tokenId,
            offer.active
        ); // returning details for the offer
    }

    function getAllTokensOnSale() public returns(uint256[] memory listOfOffers){ // returning array of tokenIds that are on sale
        uint256 totalOffers = offers.length;

        if(totalOffers == 0){
            return new uint256[](0); // returning an empty array
        }else{
            uint256[] memory result = new uint256[](totalOffers); // creating new array with size of totalOffers
            uint256 offerId;

            for(offerId=0; offerId < totalOffers; offerId++){ // looping through totalOffers array
                if(offers[offerId].active == true){ // if we find an active offer
                result[offerId] = offers[offerId].tokenId; // we will add it (tokenId, not a full offer) to result array
                }
            }
            return result;
        }
    }

    function _ownsKitty(address _address, uint256 _tokenId) internal view returns(bool) {
        return (_kittyContract.ownerOf(_tokenId) == _address); // if the current caller actually owns a kitty
    }

    function setOffer(uint256 _price, uint256 _tokenId) public {
        require(_ownsKitty(msg.sender, _tokenId), "You are not the owner of that kitty");
        require(tokenIdToOffer[_tokenId].active == false, "You can't sell twice the same offers"); // checking that there is no others offers for that _tokenId
        require(_kittyContract.isApprovedForAll(msg.sender, address(this)), "Contract needs to be approved to transfer kitty in future"); // marketplace needs to be an operator, 
                                                                    // and for marketplace to check it we call isApprovedForAll(). It will return true if marketplace is an operator
    
        Offer memory _offer = Offer({ // creating an new offer
        seller: msg.sender,
        price: _price,
        active: true,
        tokenId: _tokenId,
        index: offers.length
    });

    tokenIdToOffer[_tokenId] = _offer; // adding _offer to specific _tokenId in mapping
    offers.push(_offer); // pushamo u offers array

    emit MarketTransaction("Create offer", msg.sender, _tokenId);
    }

    function removeOffer(uint256 _tokenId) public{ // only seller ca remove the offer and call this function
        Offer memory offer = tokenIdToOffer[_tokenId]; // We get the offer
        require(offer.seller == msg.sender, "You are not the seller of that kitty");

        delete tokenIdToOffer[_tokenId];
        offers[offer.index].active = false; // getting index of _tokenId (from mapping) in offers array and setting active to false

        emit MarketTransaction("Remove offe", msg.sender, _tokenId);
    }
    

    function buyKitty(uint256 _tokenId) public payable {
        Offer memory offer = tokenIdToOffer[_tokenId]; // We get the offer
        require(msg.value == offer.price, "The prie is incorrect");
        require(tokenIdToOffer[_tokenId].active == true, "No active order present");

        // important: delete the kitty (offer) from the mapping BEFORE paying out to prevent reentry attack
        delete tokenIdToOffer[_tokenId]; 
        offers[offer.index].active = false; // we cannot delete anything from array, but we can from mapping. Because it will screw all indexes and so on... 

        //Transfer the funds to the seller (owner)
        if(offer.price > 0){
            offer.seller.transfer(offer.price); // this is push
            // more security way is to use pull instead of push 
        }

        //Transfer ownership to the kitty
        _kittyContract.transferFrom(offer.seller, msg.sender, _tokenId); // transfer token from seller to msg.sender (buyer)

        emit MarketTransaction("Buy", msg.sender, _tokenId);
    }
}

This can be fixed if you convert the address value as payable(address). I think this related to newer version of solidity.

So this code need to be updated like below.

Offer memory _offer = Offer({ 
        seller: payable(msg.sender),

Please test and check if it compiles.

Regarding the second error, its hard to tell what is causing the error. Check if there are other syntax errors in the imported .sol code.

import "./Kittycontract.sol";
import "./IKittyMarketplace.sol";

This helps: seller: payable(msg.sender). Thank you

But about second problem, I found error in imported Kittycontract.sol contract in _createKitty() function in constructor about uint256(-1) :

Explicit type conversion not allowed from "int_const -1" to "uint256"
contract KittyContract is IERC721{ // inheriting KittyContract from IERC721

    string public constant TokenName = "LOLChain";
    string public constant Ticker = "LOL";

    constructor() public {  // zero cat, noone will own, for on other cat will have id=0, because of getAllTokensOnSale() function from KittyMarketplace contract
        _createKitty(0, 0, 0, uint256(-1), address(0)); // newDna is -1 (genes)
    } 

Here is whole contract:

Kittycontract.sol
// SPDX-License-Identifier: MIT
pragma solidity >0.6.0 <0.9.0;

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

contract KittyContract is IERC721{ // inheriting KittyContract from IERC721

    string public constant TokenName = "LOLChain";
    string public constant Ticker = "LOL";

    constructor() public {  // zero cat, noone will own, for on other cat will have id=0, because of getAllTokensOnSale() function from KittyMarketplace contract
        _createKitty(0, 0, 0, uint256(-1), address(0)); // newDna is -1 (genes)
    } 

    // In order to be compliant to ERC721 we also need to be compliant with ERC165. 
    // Any token that follows ERC standard, there needs to be easy way to other contracts or people to check which interface we are implement. 
    /* 
        // All functions that we are implement: 
        bytes4(keccak256("balanceOf(address)")) = 0x70a080231 
        bytes4(keccak256("approve(address,uint256)")) = 0x095ea7b3
        bytes4(keccak256("transferFrom(address,address,uint256)")) = 0x23b872dd
        ...

        // Do bytes4 of the hash of each function header and then do XOR on all functions together to get signature to ERC721 interface

        => 0x70a080231 ^ 0x095ea7b3 ^ 0x23b872dd = 0x80ac58cd
    */
    bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd; 

    /* 
        // For ERC165 -> only one function
        bytes4(keccak256("supportsInterface(bytes4)")) 
    */
    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;

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

    mapping(address => uint256) public  balanceOfKitties;
    mapping(uint256 => address) tokenOwner;
    mapping(uint256 => address) public kittyIndexToApproved; // if some tokenID (kittyId) has any other approved address for spending it

    // address of some owner => address (operatorAddress) of someone that we want to give permission to => true/false
    mapping(address => mapping(address => bool)) private _operatorApprovals; // giving access some other address to our all collection of cast (all tokens)

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

    Kitty[] kitties;

    uint256 public constant CREATION_LIMIT_GEN0 = 10;
    uint256 public gen0counter;
    bytes4 internal constant IERC721_RECEIVED_NUMBER = bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"));

    function breed(uint256 _dadId, uint256 _mumId) public returns(uint256){
        // check ownership
        require(_owns(msg.sender, _dadId), "THe user doesn't own the token");
        require(_owns(msg.sender, _mumId), "THe user doesn't own the token");

        (uint256 dadDna,,,,uint256 DadGeneration) = getKitty(_dadId); // getKitty() returns all properties of Kitty
        (uint256 mumDna,,,,uint256 MumGeneration) = getKitty(_mumId); // that one that we don't need just replace with comas (,,) --> reduces memory use

         uint256 newDna = _mixDna(dadDna, mumDna);

        // calculating new cat generation
        uint256 kidGen = 0; 
        if(DadGeneration < MumGeneration){
            kidGen = MumGeneration + 1; // Need better way because if MumGen=1 and DadGen=0, then kid will have Gen=1 -> the same as the mum
            kidGen /= 2;
        }else if(DadGeneration > MumGeneration){
            kidGen = DadGeneration + 1;
            kidGen /= 2;
        }else{
            kidGen = MumGeneration + 1; // If both Mum and Dad are the same (npr. Gen0) -> kid will be Gen1
        }

        // Creating a new cat with the new properties, gitve it to the msg.sender
        _createKitty(_mumId, _dadId, kidGen, newDna, msg.sender);

    }

    // checking by other people what interfaces our KittyContract contract supports (does supports ERC721,ERC20 (or any other), or all functions that exist in ERC721,ERC20,...)
    function suportsInterface(bytes4 _interfaceId) external view returns(bool){
        return (_interfaceId == _INTERFACE_ID_ERC721|| _interfaceId == _INTERFACE_ID_ERC165);
    }

    // One fixed that safeTransfer fixes, where there is a flaw (mana, propust) in normal transferFrom 
    // Flaw - in mapping we are changing owner of tokens when we send the token to another address. Risk is when sender want to send token, he might put an address of an another 
    //        smart contract that does not support owning tokens (npr. Hello world smart contract) --> MONEY WILL BE LOST. Mapping will set ownership of tokens to this contract, but 
    //        this contract cannot do anything with these tokens (if it has just function npr. getString(), does not support ERC721). 

    // SafeTransfer two checks: 1. Is the recepient (_to) a contract? If it is not a contract, then go ahead with a tx (then it is probably wallet address)
    //                          2. Check receiver support ERC721, if doesn't, throw an error and entire tx will revert. How to check? 
    //                             Every contract that support ERC721 needs to implement onERC721Received() function, and it needs to return a specific number -> 0x150b7a02

    
    function safeTransferFrom(address _from, address _to, uint256 _tokenId) public override {
        safeTransferFrom(_from, _to, _tokenId, "");
    }

    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes memory _data) public override {
        require(msg.sender == _from || _approvedFor(msg.sender, _tokenId) || isApprovedForAll(_from, msg.sender));
        require(_owns(_from, _tokenId)); 
        require(_to != address(0)); // we can't send token to zero address 
        require(_tokenId < kitties.length); // token must exist

        _safeTransfer(_from, _to, _tokenId, _data);
    }

    function _safeTransfer(address _from, address _to, uint256 _tokenId, bytes memory _data) internal {
        _transfer(_from, _to, _tokenId);
        require(_checkERC721Support(_from, _to, _tokenId, _data));
    }

    function transferFrom(address _from, address _to, uint256 _tokenId) public override {
            // we are owner and executor of transferFrom() || we have approval for tokenId || is msg.sender operator for _from?
        require(msg.sender == _from || _approvedFor(msg.sender, _tokenId) || isApprovedForAll(_from, msg.sender));
        require(_owns(_from, _tokenId));
        require(_to != address(0)); // we can't send token to zero address 
        require(_tokenId < kitties.length);

        _transfer(_from, _to, _tokenId);
    }

    function approve(address _to, uint256 _tokenId) public override { // approve one address to be able to transfer a specific tokenId
        require(_owns(msg.sender, _tokenId));
        _approve(_tokenId, _to);
        emit Approval(msg.sender, _to, _tokenId);
    }

    function setApprovalForAll(address operator, bool approved) public override{
        require(operator != msg.sender);
        _operatorApprovals[msg.sender][operator] = approved;
        emit ApprovalForAll(msg.sender, operator, approved);
    }

    function getApproved(uint256 tokenId) public override view returns(address){ // getting approved status of a token, doesn't set anything
        require(tokenId < kitties.length); // Token must exist
        return kittyIndexToApproved[tokenId]; // returns the address of tokenId that has approval
    }

    function isApprovedForAll(address owner, address operator) public override view returns(bool) { // returns bool if a specific oeprator actually is approved operator for specific owner
        return _operatorApprovals[owner][operator]; // Mapping status
    }

    function createKittyGen0(uint256 _genes) public returns(uint256){ // genes from frontend slider
        require(gen0counter <= CREATION_LIMIT_GEN0);
        gen0counter++;
        // Gen0 have no owners, they are own by the contract
        return _createKitty(0, 0, 0, _genes, msg.sender); // owner can be also this contract --> address(this)
    }

    //creating cats
    function  _createKitty(uint256 _mumId, uint256 _dadId, uint256 _generationId, uint256 _genes, address _owner
) private returns (uint256) { // returns catId, function that will be use during brathing and creating from nowhere (birth of ta cat)
        Kitty memory _kitty = Kitty({
            genes: _genes,
            birthTime: uint64(block.timestamp),
            mumId: uint32(_mumId), //easier to input uint256 and then converting to uint32, rather than inputing uint32 in function
            dadId: uint32(_dadId),
            generation: uint16(_generationId)
        });

        kitties.push(_kitty); // push will return size of array
        uint256 newKittyId = kitties.length - 1; //-1 because we want to start from 0 (first cat will have ID 0)
        emit Birth(_owner, newKittyId, _mumId, _dadId, _genes);
        _transfer(address(0), _owner, newKittyId); // --> from address(0) newKittyId will be transferred to _owner, CREATION A CAT FROM NOWHERE (BIRTH)
        return newKittyId;
    }

    function getKitty(uint256 _kittyId) public returns(uint256 genes, uint256 birthTime, uint256 mumId, uint256 dadId, uint256 generation){
        Kitty storage kitty = kitties[_kittyId]; // storage -> pointer to kitties array, memory will create a copy

        //uint256 is easier to read on frontend rather small values of uint
        birthTime = uint256(kitty.birthTime);
        mumId = uint256(kitty.mumId);
        dadId = uint256(kitty.dadId);
        generation = uint256(kitty.generation);
        genes = kitty.genes;
       
    }

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

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

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

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

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

    function transfer(address to, uint256 tokenId) external override{ // this function only sends from msg.sender to recipient
        require(to != address(0));
        require(to != address(this));
        require(_owns(msg.sender, tokenId));

        _transfer(msg.sender, to, tokenId);
    }

    function _owns(address claimant, uint256 tokenId) internal view returns(bool){
        return tokenOwner[tokenId] == claimant; // claimant -> person who is claiming the ownership
    }

    function _transfer(address _from, address _to, uint256 _tokenId) internal{
        balanceOfKitties[_to]++;
        tokenOwner[_tokenId] = _to; // _to is owner of _tokenId
        if(_from != address(0)){ // zbog mintanja nove mačke, jer tad nema oduzimanja tokena ako je nova
            balanceOfKitties[_from]--; // decreasing token from sender
            delete kittyIndexToApproved[_tokenId]; // When token is transferred form one owner to another, we need to delete approved address (seconds from sender) for specific tokenId
        }
        emit Transfer(_from, _to, _tokenId);
    }

    function _approve(uint256 _tokenId, address _approved) internal {
        kittyIndexToApproved[_tokenId] = _approved;
    }

    function _approvedFor(address _claimant, uint256 _tokenId) internal view returns(bool) {
        return kittyIndexToApproved[_tokenId] == _claimant; // is kittyIndexToApproved for the _tokenId is equal to person who claims it is approved (it has approval)
    }

    function _checkERC721Support(address _from, address _to, uint256 _tokenId, bytes memory _data) internal returns(bool){
        if(!_isContract(_to)){ // if it return false, it is not a contract and we can continue to transfer the tokens
            return true;
        }

        // Call onERC721Received in the _to contract (bytes4 -> according to specification (IERC721.sol))
        bytes4 returnData = IERC721Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data); // calling an external contract (interface) and calling its functions
        return returnData == IERC721_RECEIVED_NUMBER; // if these two are equal, then we know that this contract supports ERC721

        // Check return value

    }

    function _isContract(address _to) internal view returns(bool){
        // code size > 0 if it is a smart contract (specification (IERC721.sol))
        // If it is a wallet, code size will be 0
        // If it is a contract, code size will be bigger than 0
        // Solidity assembly language
        uint32 size;
        assembly{
            size := extcodesize(_to) // external code size gets the size of whatever code is in _to address on the Ethereum blockchain
        }
        return size > 0; // TRUE if it is > 0, FALSE =< 0
    }

    // OLD ONE!! 
    // function _mixDna(uint256 _dadDna, uint256 _mumDna) internal returns(uint256){
    //     // dadDna: 11 22 33 44 55 66 77 88  
    //     // mumDna: 88 77 66 55 44 33 22 11   

    //     uint256 firstHalf = _dadDna / 100000000; // first half of dadDNa -> first 8 digits => 11223344
    //     uint256 secondHalf = _mumDna % 100000000; // last hald of mumDna -> last 8 digits => 44332211

    //     /*example: 
    //         10 + 20 = 1020 HOW? we don't want 30
    //         --> 10 * 100 = 1000 <--
    //         --> 1000 + 20 = 1020 <--
    //     */

    //     uint256 newDna = firstHalf * 100000000;
    //     newDna = newDna + secondHalf; // --> 1122334444332211
    //     return newDna;
    // }

    function _mixDna(uint256 _dadDna, uint256 _mumDna) internal returns(uint256){
        uint256[8] memory geneArray; // array of size 8
    
        // there are no real random number in solidity and we don't want to use random in some securtiy features. For breeding is ok.
        uint8 random = uint8(block.timestamp % 255); // % 255 -> we got the number between 0-255 (in binary: 00000000-11111111)
        uint256 i = 1; 
        uint256 index = 7;  //Since we start from end of the DNA -> we need set gene index to the end

        // DNA: 11 22 33 44 55 66 77 88

        // loop through random and check which position is 1 and which position is 0. Loop will run 8 times. 
        for(i=1; i<=128; i=i*2){ // <=128 and *2 (for every iteration) -> because we have 8 binary numbers => 1,2,4,8,16,32,64,128 
            /*
                00000001 - 1
                00000010 - 2
                00000100 - 4
                00001000 - 8
                00010000 - 16
                00100000 - 32
                01000000 - 64
                10000000 - 128
                Bitwise and operator - & 

                Let's say the rundom number is 11001011 and if we use & with every loop number bit by bit:
                11001011            |       11001011            |       11001011            |       ...
                &                   |       &                   |       &                   |       ...
                00000001 = 1        |       00000010 = 1        |       00000100 = 0        |       ...

                if(1) -> use mum gene
                if(0) -> use dad gene
            */

            if(random & i != 0){
                geneArray[index] = uint8(_mumDna % 100); // Since DNA is 16 digits, use last two digits and start from end of the DNA stream.
            }else{ // if we get 1
                geneArray[index] = uint8(_dadDna % 100);
            }

            // remove last two digits from DNA now -> 11 22 33 44 55 66 77
            _mumDna = _mumDna / 100;
            _dadDna = _dadDna / 100;

            index = index - 1; // next time we want to set the position in geneArray at 6th position, then to 5th, 4th,...
        }

        uint256 newGene;
        
        for(i=0; i<8; i++){ // build a full number instead array of 8 different numbers that are 2 digits
            /*   0, 1, 2, 3, 4, 5, 6, 7 --> indexes in array
                [11,22,33,44,55,66,77,88] --> this is for example, but DNA will be mixed of two different genes from previous for loop, maybe [88,22,66,44,55,66,22,88]
            */
            newGene = newGene + geneArray[i];   // take a position 0 and add 11 (first time) to the full dnaString
                                                // second time 112200
                                                // third time 11223300
                                                // ... until reach end of the array 1122334455667788
            if(i != 7){ // we don't want to add two extra zeros before we exit
                newGene = newGene * 100; // add extra zeros to it --> 1100
            }
        }
        return newGene;
    }
}
1 Like

Try replacing this with the below line. The purpose of using uint256(-1) is same as type(uint256).max

_createKitty(0, 0, 0, type(uint256).max, address(0));

Reference with a similar error: https://ethereum.stackexchange.com/questions/94520/explicit-type-conversion-not-allowed-from-int-const-1-to-uint128

1 Like

Thank you, now errors are gone. :slight_smile:

1 Like