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
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? May 12, 2021 at 19:04
-
Yes. Everybody is using
setApprovalForAll
. I don't know anybody using the singleapprove
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 May 12, 2021 at 19:32
-
Using
approve
requiresn
operations to transfern
different tokens. But usingsetApprovalForAll
requires 1 operation to transfern
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? 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);
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.