ERC721 contract call: transfer caller is not owner nor approved

51 views Asked by At

I am writing a React app that is responsible for invoking a contract that transforms an ERC721 NFT from one form to another via ethers.js. During my web app process flow, I am requiring the user to grant access to their Metamask wallet in order to display the eligible NFTs for transformation, as well as to approve the transaction before the contract call takes place.

I'm getting an error when I try to make a call against an existing ERC721 contract stating the caller of the transaction is not the owner or approved to invoke the contract. However, when I look at the NFT in question in a block explorer I can see the invoking wallet is in fact the owner of the NFT, but I am getting this exception:

execution reverted: \"ERC721: transfer caller is not owner nor approved\" (action=\"estimateGas\", data=\"0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000314552433732313a207472616e736665722063616c6c6572206973206e6f74206f776e6572206e6f7220617070726f766564000000000000000000000000000000\", reason=\"ERC721: transfer caller is not owner nor approved\", transaction={ \"data\": \"0x8914d9f00000000000000000000000000000000000000000000000000000000000001363\", \"from\": \"<wallet of sender>\", \"to\": \"<contract address>\" }, invocation=null, revert={ \"args\": [ \"ERC721: transfer caller is not owner nor approved\" ], \"name\": \"Error\", \"signature\": \"Error(string)\" }, code=CALL_EXCEPTION, version=6.8.1)"

Looking at the contract source, I can see there is an approval call made during the transform process which should handle the approval process:

function Nft3DTo2D(uint256 tokenId) external {
    
    uint256[] memory tokenIds = nft3DContract.walletOfOwner(msg.sender);
    require(_contains(tokenIds, tokenId) == true, "Address does not hold token!");

    nft3DContract.safeTransferFrom(msg.sender, address(this), tokenId);
    nft2DContract.approve(msg.sender, tokenId); # approval happens here
    nft2DContract.safeTransferFrom(address(this), msg.sender, tokenId);

}

I'm not really sure why I'm encountering this issue. Any ideas?

1

There are 1 answers

0
thks173 On

"the invoking wallet" is not the actor who made the transfer action.

It's the contract, when calling nft3DContract.safeTransferFrom, so the user need to call nft3DContract.approve to grant the contract the permission to make the transfer action.

The nft2DContract.approve is redundant btw, since the contract is the owner in this case