Assignment - Safetransfer Implementation

Hello Devs,

I get an error message and have trouble figuring out what is going wrong. It says “No matching declaration found after argument-dependent lookup”

What am I missing?

I will reply to my own message because I’ve found the problem. On line 227 where function _isApprovedForOwner is defined I missed the end which returns (bool).

Schermafbeelding 2021-06-29 om 15.59.52

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

import "./IERC721.sol";
import "../node_modules/@openzeppelin/contracts/access/Ownable.sol";
import "./IERC721Receiver.sol";

 contract Kittycontract is IERC721, Ownable {

    uint256 public constant CREATION_LIMIT_GEN0 = 10;
    string private constant tokenName = "ThomasKitties";
    string private constant tokenSymbol = "TM";

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

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

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


    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;

    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( _isApprovedOrOwner(msg.sender, _from, _to, _tokenId) );
        _safeTransfer(_from, _to, _tokenId, _data);
    }

    // function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes memory _data) public override {
    //     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);
    }
    
    function transferFrom(address _from, address _to, uint256 _tokenId) public override {
        require(_isApprovedOrOwner(msg.sender, _from, _to, _tokenId));
        // 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(_from, _to, _tokenId);
    }

    function approve(address _to, uint256 _tokenId) public override {
        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 view override returns (address){
        require(tokenId < kitties.length); //Token must exist

        return kittyIndexToApproved[tokenId];
    }

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

    

    function getKitty(uint256 _id) external 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; 
    }



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

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



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

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

        _transfer(address(0), _owner, newKittenId);
    
        emit Birth(_owner, newKittenId, _mumId, _dadId, _genes);

    return newKittenId;
    }

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

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

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

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

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

    function transfer(address _to, uint256 _tokenId) external override {
        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, uint256 _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 on ERC721Received in the _to contract
        bytes4 returnData = IERC721Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data);
        return returnData == MAGIC_ERC721_RECEIVED;
        //Check return value
    }

    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 {
        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

        //msg.sender is from OR spender is approved for tokenId OR spender is operator for from
        return (_spender == _from || _approvedFor(_spender, _tokenId) || isApprovedForAll(_from, _spender)); 
}

}

Hey @thomascarl, hope you are ok.

I might need to check also your interfaces IERC721.sol and IERC721Receiver.sol, might be that are different from openzeppelin.

But have you tried to use the ERC721 preset from openzeppelin instead of writing your own ERC721 functions?

Carlos Z

1 Like

I have a question, when I tried placing a string at the end of the safeTransferFrom function to omit the data parameter, it throws an error, so I just removed it and it does not have any error. Is there anything wrong with this?

Assignment here:

    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata _data) public virtual override {
        require(_isApprovedOrOwner(msg.sender, _tokenId), "ERC721: transfer caller is not owner nor approved");
        _safeTransfer(_from, _to, _tokenId, _data);
    }

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

//re-usable functions
    function _isApprovedOrOwner(address _spender, uint256 _tokenId) internal view virtual returns (bool) {
        require(_exists(_tokenId), "ERC721: operator query for nonexistent token");
        require(_ownedBy(msg.sender, _tokenId), "ERC721: Sender does not own this token");
        return (_spender == msg.sender || getApproved(_tokenId) == _spender || isApprovedForAll(msg.sender, _spender));
    }
    function _exists(uint256 _tokenId) internal view virtual returns (bool) {
        return _kittyOwners[_tokenId] != address(0);
    }

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

Full Contract Here

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

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

contract Kittycontract is IERC721, Ownable{
    using SafeMath for uint256;
    
    string public constant _name = "KittyCutie";
    string public constant _symbol = "KTCT";
    uint public constant Gen0_limit = 20;

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

    event Birth(address owner, uint256 kittenId, uint256 mumId, uint256 dadId, uint256 genes);
    
    
    struct Kitty {
        uint256 genes;
        uint64 birthTime;
        uint32 mumId;
        uint32 dadId;
        uint16 generation;
    }

    Kitty[] kitties;

    mapping(address => uint256) public _kittyBalance;
    mapping(uint256 => address) _kittyOwners;
    mapping(uint256 => address) public _kittyApprovals; //owner approve a specific address to transfer a specific kitty (token) 
    mapping(address => mapping(address => bool)) private _operatorApprovals; //owner approve a specific address to transfer all kities owned

    uint256 public Gen0_Kitties_created;

    function createKittyGen0(uint256 _genes) public onlyOwner returns(uint256) {
        require(Gen0_Kitties_created < Gen0_limit);
        Gen0_Kitties_created ++;

        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: _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); //transfer from nowhere(address(0)) means Creation of a Kitty

        return newKittenId;
    }

    function getKitty(uint256 _id) public view returns (
        uint256 _genes,
        uint256 _birthTime,
        uint256 _mumId,
        uint256 _dadId,
        uint256 _generation
    ) 
    {
        Kitty storage kitty = kitties[_id];

        _genes = kitty.genes;
        _birthTime = uint256(kitty.birthTime);
        _mumId = uint256(kitty.mumId);
        _dadId = uint256(kitty.dadId);
        _generation = uint256(kitty.generation);       
    }
    
    function balanceOf(address _owner) public view override returns (uint256) {
        require(_owner != address(0), "ERC721: balance query for the zero address");
        return _kittyBalance[_owner];
    }

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

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

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

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

    function transfer(address _to, uint256 _tokenId) public override {
        require(address(this) != _to);
        require(address(0) != _to);
        require(_ownedBy(msg.sender, _tokenId));

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

    function approve(address _approved, uint256 _tokenId) external virtual override {
        require(_ownedBy(msg.sender, _tokenId));
        require(_approved != msg.sender, "Address to approve is same as owner address");

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

    function setApprovalForAll(address _operator, bool _approved) external virtual override{
        require(_operator != msg.sender);

        _operatorApprovals[msg.sender][_operator] = _approved;
        emit ApprovalForAll(msg.sender, _operator, _approved);
    }

    function getApproved(uint256 _tokenId) public view override returns (address){
        require(_tokenId < kitties.length, "Kitty does not exist");

        return _kittyApprovals[_tokenId];
    }

    function isApprovedForAll(address _owner, address _operator) public view override returns (bool) {
        return _operatorApprovals[_owner][_operator];
    }

    function transferFrom(address _from, address _to, uint256 _tokenId) public override {
        require(_to != address(0), "Address invalid");
        require(_isApprovedOrOwner(msg.sender, _tokenId), "ERC721: transfer caller is not owner nor approved");

        _transfer(_from, _to, _tokenId);
    }

    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata _data) public virtual override {
        require(_isApprovedOrOwner(msg.sender, _tokenId), "ERC721: transfer caller is not owner nor approved");
        _safeTransfer(_from, _to, _tokenId, _data);
    }

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

//re-usable functions
    function _ownedBy(address claimant, uint256 _tokenId) internal view returns(bool) {
        return _kittyOwners[_tokenId] == claimant;
    }

    function _transfer(address _from, address _to, uint256 _tokenId) internal {
        _kittyBalance[_to]++;
        _kittyOwners[_tokenId] = _to;
        
        if(_from != address(0)){
            _kittyBalance[_from]--;
            delete _kittyApprovals[_tokenId]; //remove approval when token is transferred to another owner
        }
        
        emit Transfer(_from, _to, _tokenId);
    }

    function _approve(address _to, uint256 _tokenId) internal virtual { 
        _kittyApprovals[_tokenId] = _to;
    }

    function _isApprovedOrOwner(address _spender, uint256 _tokenId) internal view virtual returns (bool) {
        require(_exists(_tokenId), "ERC721: operator query for nonexistent token");
        require(_ownedBy(msg.sender, _tokenId), "ERC721: Sender does not own this token");
        return (_spender == msg.sender || getApproved(_tokenId) == _spender || isApprovedForAll(msg.sender, _spender));
    }

    function _exists(uint256 _tokenId) internal view virtual returns (bool) {
        return _kittyOwners[_tokenId] != address(0);
    }

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

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

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

hey @CryptoXyz !

As long as its works as expected its ok. I just wonder why you need that data and also why to omit it.
Please post a screen shoot of the error to know whats happening.

Also I notice this

You shold use require() before _transfer(_from, _to, _tokenId);

Thanks Carlos. I went a head and imported the openzeppelin contracts from openzeppelin.
I followed a quick tutorial from openzeppelin and when I returned to open the files again VSC, the node modules are greyed out so they are unreachable.
Also, I got a message from VSC, asking me if I wanted to give some sort permission for the gitmore, something to do with “too many changes” on the files from Filip…all of those support files for the Kitties project.
I don’t quite understand how hat works…?
(unkowingly, i said no so maybe that is why the dode modules are greyd out?

1 Like

Could you please provide me the link from filip ? It might be that you fork it or clone it through github desktop manager and after installing openzeppelin contracts module it ask to update the repository (not sure, but i guess it is)

Carlos Z

yes, that is what I ended up doing. I added the desktop version of github and forked Fili’s project.
I had new problems because it now the contracts are so different from Filip’s that it says it must be an abstract contract…so I am trying to actually build it with openzeppelin which will be good for me since I need to rehearse that. Here is Filip’s link in case you need to check it out
https://github.com/Ivan-on-Tech-Academy/academy-kitties-template.git

@thecil, @Bhujanga, @kenn.eth
I re-did my Crypto Kitties project by installing openzeppelin and incorporating the createKitty functions.
I also created a fork in GitHub but now, I am not able to create a cat, I get errors:

revert ERC721: owner query for nonexistent token

I get these errors when I try to create a cat with Metamask:
MetaMask - RPC Error: MetaMask Tx Signature: User denied transaction signature. {code: 4001, message: “MetaMask Tx Signature: User denied transaction signature.”}

this is the link to my project
https://github.com/brlojam4932/digitalCats.git

1 Like

The link that you provide apparently is invalid, probably you forgot to change the visibility for the repository. :face_with_monocle:

that revert message could come from the ERC721 contract (openzeppelin), maybe the ownerOf() function, would need to check your project to look for the exact require that triggers that revert msg.

Carlos Z

I just changed it to Public view

@thecil
Hello Carlos, not sure if you saw my update yesterday. I made my files at github public
https://github.com/brlojam4932/digitalCats.git

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


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

contract Kittycontract is IERC721, Ownable {

    uint256 public constant CREATION_LIMIT_GEN0 = 10;
    string public constant name = "FilipKitties";
    string public constant symbol = "FK";

    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;

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

    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 getKitty(uint256 _id) external 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;
    }

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

        gen0Counter++;

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

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

        uint256 newKittenId = kitties.push(_kitty) - 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 (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]--;
            delete kittyIndexToApproved[_tokenId];
        }

        // Emit the transfer event.
        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, uint256 _tokenId) internal view returns (bool) {
        return kittyIndexToApproved[_tokenId] == _claimant;
    }

}

But I’m getting an error in this part:

  function transferFrom(address _from, address _to, uint256 _tokenId) public override transferChecks(_from, _to, _tokenId){
    _transfer(_from, _to, _tokenId);
    }

    function safeTransferFrom(address _from, address _to, uint256 _tokenId) public override {
        safeTransferFrom(_from, _to, _tokenId, "");
//safeTransfer highlights the error "No matching declaration found after argument-dependent lookup."
    }

hey @RBeato! can you screen shoot the error?

Sorry for the delay man.

About the error, is comes from the ownerOf function from your ERC721 contract.
(@openzeppelin/contracts/token/ERC721/ERC721.sol")

The problem comes from the _createKitty functions that calls _tansfer almost at the end of its execution, the problem is that you are not minting the nft before you can transfer it.

So instead calling _transfer you should call _safeMint cuz that one will create the proper tokenId and then transfer it to the new owner (check the openzeppelin ERC721 contract).

I have created this quick test so you can check that IT will fail if your _createKitty use _transfer.

const myCryptoCats = artifacts.require("myCryptoCats");

const {
    BN,           // Big Number support
    constants,    // Common constants, like the zero address and largest integers
    expectEvent,  // Assertions for emitted events
    expectRevert, // Assertions for transactions that should fail
  } = require('@openzeppelin/test-helpers');

contract("CryptoCats", ([owner, alfa, beta, charlie]) => {
    // Global variable declarations
    let contractInstance;
    let _ticker;

    //set contracts instances
    before(async function() {
        // Deploy tokens to testnet
        contractInstance = await myCryptoCats.new();
        console.log("CONTRACT ",contractInstance.address);
    });

    describe("ERC721", () => {

        it("will fail cuz ownerOf tokenId is invalid", async function (){
            await expectRevert(
                contractInstance.createKittyGen0("123456789"),
                "ERC721: owner query for nonexistent token"
            );
        });

    }); //end describe "ERC721"
}); //end contract "CryptoCats"

Carlos Z

Hi! Here is the screen shot:
Capturar

Thanks Carlos, I knew it had to do with the _transfer function but did understand how to begin to solve it – thank you so much!

1 Like

Hello, I added a modifier

modifier ERC721Requirements (address _from, address _to, uint256 _tokenId){
        require (isApprovedForAll(_from, msg.sender) || msg.sender == kittyIndexToApproved[_tokenId] || msg.sender == _from);
        require (_tokenId < kitties.length);
        require (_to != address(0));
        require (_owns(_from, _tokenId));
        _;
    }

    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata data) external ERC721Requirements{
        _safeTransfer(_from, _to, _tokenId, data);
    }

    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external ERC721Requirements{
        bytes4 _data = "";

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

only issue i had is setting the final bytes calldata parameter, compiler is throwing an error and giving me hard time

  function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata data) public override {

                //require address is valid
        require(_to != address(0));

        //make sure _tokenId is valid
        require(_tokenId < totalSupply());

        //checking requirements of approvals
        require((msg.sender == _from) ||
                (getApproved(_tokenId) == msg.sender) ||
                (isApprovedForAll(_from,msg.sender))
                );
        
        //make sure _from owns actually owns token
        require(ownerOf(_tokenId) == _from);

        //make transfer
        uint i = 0;
        _safeTransfer(_from,_to,_tokenId,abi.encodePacked(i));


    }

    /// @notice Transfers the ownership of an NFT from one address to another address
    /// @dev This works identically to the other function with an extra data parameter,
    ///  except this function just sets data to "".
    /// @param _from The current owner of the NFT
    /// @param _to The new owner
    /// @param _tokenId The NFT to transfer
    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external override {
        uint i = 0;
        safeTransferFrom(_from,_to,_tokenId,abi.encodePacked(i));
    }
1 Like

nice idea - thanks for sharing

I had the same problem if you are referring to this: safeTransferFrom(_from, _to, _tokenId, “”);
I removed the quotes all together and made sure I was referencing safeTransferFrom instead of _safeTransfer, which I was doing. So here is what I did – seems to work.

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