If I want to implement a little NFT marketplace and want users to be able to put items up for sale, and other users to buy those, how should I do that? Do I need to make market contract that gets approved every time someone puts up something for sale, and when someone buys that items the contract will execute the safeTransferFrom function?

2 Answers 2


Yes, this is one way people typically do it.

Better options are available if your marketplace only applies to one specific token.

  • Is this the best way to do it when I'm not working with only one specific token?
    – warren1235
    May 12, 2021 at 19:04
  • Yes. Everybody is using setApprovalForAll. I don't know anybody using the single approve for this purpose. May 12, 2021 at 19:28
  • Can you elaborate on that? I know those functions, I just don't understand what you mean by this
    – warren1235
    May 12, 2021 at 19:32
  • Using approve requires n operations to transfer n different tokens. But using setApprovalForAll requires 1 operation to transfer n different tokens. May 12, 2021 at 19:34
  • But a user only can put up for sale one nft at a time, so why does the market contract need setApprovalForAll?
    – warren1235
    May 12, 2021 at 19:42

I use this contract:

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

import '@openzeppelin-contracts/contracts/token/ERC721/ERC721.sol';
import '@openzeppelin-contracts/contracts/finance/PaymentSplitter.sol';

contract BALANCE is ERC721 {
    event NftBought(address _seller, address _buyer, uint256 _price);

    mapping (uint256 => uint256) public tokenIdToPrice;
    uint public nextTokenId;
      address public admin;

    constructor() ERC721('Balance', 'BALANCE') {
          admin = msg.sender;
      function mint(address to) external {
    require(msg.sender == admin, 'only admin');
    if(nextTokenId < 2){_safeMint(to, nextTokenId);
              function _baseURI() internal view override returns (string memory) {
    return 'https://.herokuapp.com/';

    function allowBuy(uint256 _tokenId, uint256 _price) external {
        require(msg.sender == ownerOf(_tokenId), 'Not owner of this token');
        require(_price > 0, 'Price zero');
        tokenIdToPrice[_tokenId] = _price;

    function disallowBuy(uint256 _tokenId) external {
        require(msg.sender == ownerOf(_tokenId), 'Not owner of this token');
        tokenIdToPrice[_tokenId] = 0;
    function buy(uint256 _tokenId) external payable {
        uint256 price = tokenIdToPrice[_tokenId];
        require(price > 0, 'This token is not for sale');
        require(msg.value == price, 'Incorrect value');
        address seller = ownerOf(_tokenId);
        _transfer(seller, msg.sender, _tokenId);
        tokenIdToPrice[_tokenId] = 0; // not for sale anymore
        payable(seller).transfer(msg.value); // send the ETH to the seller

        emit NftBought(seller, msg.sender, msg.value);

I call allowBuy('tokenId', 'prince_in_WEI') to set the id price and then send buy('tokenId') although i having issues with big number with it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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