Recently I am working on a NFT marketplace and I had difficulties in implementing safeTransferFrom function. At this stage I use _transfer function to allow the buyer calling the function directly so that the token can be transferred from the owner to the buyer. I read the documentation the better way to do so is using SetApproval and safeTransferFrom. In that case, how do I implement these functions so that the buyer can still call transfer from function without getting "caller is not the owner/not approved" error. Below is my code:

function buyingWithoutApproval (uint _tokenId) external payable {
    require (ownerOf(_tokenId) != msg.sender);
    Item storage _item = items[_tokenId];
    require(_item.forSale == true);
    address _from = ownerOf(_tokenId);
    _transfer(_from, msg.sender, _tokenId);
    itemToOwner[_tokenId] = msg.sender;
    _item.owner = msg.sender;
    _item.price = 0;
    _item.forSale = false;

from here the buyer can call this function to 'buy' the NFT token. What is the standard way to do so with Approval and safeTransferFrom? Much appreciated with example code is shared! Thanks!


To be clear, there is no required "standard" approach to implement what you like. This was intentionally excluded from the standard so that you could decide the best approach for you.

A very popular approach is to have a buy(...) function for buying available inventory or a bid(...) to make a competitive offer, if this will be an asynchronous purchase.

You are welcome to use transferFrom(...) to initiate a sale. This function explicitly does allow payment to transfer with the function call. However, none of the reference implementations support this, you will need your own implementation.

You might try something like:

function transferFrom(from, to, tokenId) external {
  require(from == ownerOf(tokenId));
  if (msg.sender == owner ||
    msg.sender == approve(tokenId) ||
    isApproved(from, msg.sender)
  ) {
    // Normal transfer here
  } else if (isForSale(tokenId) && msg.value >= salePrice(tokenId)) {
    // Purchase here

This is possible even though few if any people do it that way.

  • After doing more research, I found out implement transfer in this way: token.safeTransferFrom(web3.eth.accounts[0] , web3.eth.accounts[1], 2 , {from:web3.eth.accounts[3]}) // Note that we are adding {from:web3.eth.accounts[3]}, this mean that we are invoking this function using account[3] The contract is approved by the seller by using SetApprovalForAll, However, the problem is when transfer function is called by {from: contract address }, how does the contract pay gas cost to execute the transaction?
    – Oscar948
    Jun 4 at 8:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.