-1

I'm trying to transfer my NFT to a marketplace

pragma solidity ^0.8.7;

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

import "hardhat/console.sol";

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

    address contractAddress;

    constructor(address marketplaceAddress) ERC721("Heliopolis NFT", "HNFT") {
        contractAddress = marketplaceAddress;
    }

    function createToken(string memory tokenURI) public returns (uint256) {
        _tokenIds.increment();

        uint256 newItemId = _tokenIds.current();
        _mint(msg.sender, newItemId);
        _setTokenURI(newItemId, tokenURI);

        setApprovalForAll(contractAddress, true);

        return newItemId;
    }

    function transferToken(address from, address to, uint256 tokenId) external {
        require(ownerOf(tokenId) == from, "From address must be token owner");
        _transfer(from, to, tokenId);
    }

    function getContractAddress() public view returns (address) {
        return contractAddress;
    }
}

When I run my web3modal code as below:

import { ethers } from 'ethers';
import Web3Modal from 'web3modal';

import { nftMarketplaceAddress, nftAddress } from 'utils/contracts';

import { nftMarketplaceAbi } from 'utils/nftMarketplaceAbi';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const resellNft = async (nft: any) => {
    try{
        const web3Modal = new Web3Modal();
        const connection = await web3Modal.connect();
        const provider = new ethers.providers.Web3Provider(connection);
        const signer = provider.getSigner();
        const contract = new ethers.Contract(nftMarketplaceAddress, nftMarketplaceAbi, signer);
        // putItemToResll is a Marketplace function, that uses transferToken(*) above
        const transaction = await contract.putItemToResell(nftAddress, nft.tokenId, nft.price,
            {
                gasLimit: 1000000,
                gasPrice: ethers.utils.parseUnits("10", "gwei"),
                value: ethers.utils.parseUnits("0.001", "ether"),

            }
        );
        const response = await transaction.wait();
        console.log(response);
    }catch (e:any){
        throw e;
    }

}

I would receive an error ERC721: transfer caller is not owner nor approved. This thread (ERC721: transfer caller is not owner nor approved) suggests that I should approve the marketplace to call transferFrom() on my behalf, but I recognise that my NFT contract has that approve method in it super-super-...-super class. Would there be any to work this out?

VEvergarden
  • 105
  • 11

1 Answers1

0

yes what you're assuming is correct. If you want another contract to transfer an NFT on your behalf you need to approve that contract.

You can see the function:

function setApprovalForAll(address _operator, bool _approved) external;

Which is part of the ERC721 standard.

So in order to let you marketplace transfer user NFTs on his behalf once sold for exemple you want to call first:

yourNftContract.setApprovalForAll(marketplaceContractAddress, true)

It is the same if you try to put an NFT on sale on opensea, you will first have to do this approval transaction to authorise opensea contract.

agonist_
  • 4,890
  • 6
  • 32
  • 55