How to Build Your NFT Marketplace
One of the most popular web3 projects for your portfolio is an NFT marketplace. An NFT marketplace is a platform where creators can list their NFTs so others can mint them. A great example of this is Opensea.
We are not exactly making Opensea. Instead, we will create a simpler contract that allows you to list NFTs, mint NFTs directly from the marketplace, and delist NFTs. So, let's get started.
Creating an NFT contract
First, we need to create a simple NFT for testing purposes. This part is easy, but make sure to include a function that allows minting an NFT to a specific address (we will use this later).
Here’s a simple implementation of the ERC721 token:
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
contract NFT is ERC721 {
address public owner;
uint256 tokenMinted = 0;
constructor() ERC721("NFT", "NFT1"){}
//This function is important, (will find later)
function mint(address _to) public payable {
tokenMinted += 1;
_mint(_to, tokenMinted);
}
}
Make sure to save or store the deployed address of this contract. We will use this later.
Structure of the NFT Marketplace
Before we start building, let's discuss the features we want for the marketplace.
We need a function to list an NFT.
We need a function to buy an NFT.
We need a function to delist an NFT.
We need a function to get a specific listed NFT.
We need a function to get all listed NFTs.
We will use tokenID to identify the listed NFTs. You can also add other functions like withdraw or balance, but here we are focusing on the core functionalities.
List NFT
First, create a Marketplace contract and define a struct named Item. This structure will be used to store the listed NFTs.
Here’s an implementation:
contract Marketplace {
struct Item {
string name;
address nftAddress;
uint256 price;
uint256 tokenId;
address seller;
bool listed;
}
uint256 private listingFee = 0.02 ether;
address private owner;
uint256 private tokenId;
mapping(uint256 => Item) private items;
Also, create tokenId
to generate Token IDs for the NFTs. The items
mapping will link each tokenId
to its respective Item
(or NFT).
Now, you can create the ListItem
function as follows:
function listItem(string memory _name,
address nftAddress, uint256 price) public
{
Item memory newNFT = Item(_name, nftAddress,
price, tokenId + 1, msg.sender, true);
items[tokenId + 1] = newNFT;
tokenId += 1;
}
Buy NFT
To do this, we need to create an interface for our NFT contract that we want to list. This part will use the mint function we discussed earlier. This way, we can call the mint function of the NFT contract from our marketplace.
interface nftContract {
function mint(address _to) external payable;
}
Now, here’s the implementation of the buyNFT
function:
function buyNFT(uint256 _tokenId) public payable {
Item memory currNFT = items[_tokenId];
require(currNFT.listed, "No NFT exists of such type");
require(msg.value == currNFT.price , "Please provide
sufficient funds");
uint256 nftPrice = currNFT.price;
nftContract(items[_tokenId].nftAddress).mint{value: nftPrice}(
msg.sender
);
}
Here, we use the mint function of the deployed NFT contract through its interface. We also need to check if the buyer has enough ETH to buy the current NFT and if the NFT with the given tokenID exists.
This part is the trickiest in the whole contract. Make sure you understand it well before moving on. The rest is easy.
Delist NFT
Here, we just need to set the listing property of the NFT to false and remove it from the items
mapping.
function deListNFT(uint256 _tokenId) public {
Item memory currNFT = items[_tokenId];
require(currNFT.seller == msg.sender,
"You are not the owner of this NFT");
items[_tokenId].listed = false;
delete items[_tokenId];
}
We also need to check if the address (or user) delisting the NFT is the same one that listed it.
Get an NFT
We will create a function to retrieve a specific NFT using its tokenID.
function getNFT(uint256 _tokenId) public view returns (Item memory) {
return items[_tokenId];
}
Get all listed NFTs
To get all listed NFTs, we will create a function that returns a list of all NFTs that are currently listed.
function getListedNFTs() public view returns (Item[] memory) {
Item[] memory listedNFTs = new Item[](tokenId);
uint256 curr = 0;
for (uint256 i = 1; i <= tokenId; i++) {
if (items[i].listed) {
listedNFTs[curr] = items[i];
curr += 1;
}
}
return listedNFTs;
}
Now that we have all the necessary functions in our marketplace, you can deploy or test it using Remix.
Here’s the full implementation:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
interface nftContract {
function mint(address _to) external payable;
}
contract Marketplace {
struct Item {
string name;
address nftAddress;
uint256 price;
uint256 tokenId;
address seller;
bool listed;
}
address private owner;
uint256 private tokenId;
modifier onlyOwner() {
require(msg.sender == owner,
"Only owner of Marketplace is authorized");
_;
}
mapping(uint256 => Item) private items;
constructor() {
owner = msg.sender;
}
// NFT functions
// Adding NFT to marketplace
function listItem(
string memory _name,
address nftAddress,
uint256 price
) public {
Item memory newNFT = Item(_name, nftAddress,
price, tokenId + 1, msg.sender, true);
items[tokenId + 1] = newNFT;
tokenId += 1;
}
// Buying NFT
function buyNFT(uint256 _tokenId) public payable {
Item memory currNFT = items[_tokenId];
require(currNFT.listed, "No NFT exists of such type");
require(msg.value == currNFT.price,
"Please provide sufficient funds");
uint256 nftPrice = currNFT.price;
nftContract(items[_tokenId].nftAddress).mint{value: nftPrice}(
msg.sender
);
}
// Getting NFT details
function getNFT(
uint256 _tokenId
) public view returns (Item memory) {
return items[_tokenId];
}
// Removing NFT from Marketplace
function deListNFT(uint256 _tokenId) public {
Item memory currNFT = items[_tokenId];
require(currNFT.seller == msg.sender,
"You are not the owner of this NFT");
items[_tokenId].listed = false;
delete items[_tokenId];
}
// Get all listed NFTs
function getListedNFTs() public view returns (Item[] memory) {
Item[] memory listedNFTs = new Item[](tokenId);
uint256 curr = 0;
for (uint256 i = 1; i <= tokenId; i++) {
if (items[i].listed) {
listedNFTs[curr] = items[i];
curr += 1;
}
}
return listedNFTs;
}
//Marketplace related functions
// Withdraw contarct funds
function withdraw() public onlyOwner {
payable(owner).transfer(address(this).balance);
}
// Balance of marketplace
function balance() public view onlyOwner returns (uint256) {
return address(this).balance ;
}
}
You can add additional features like withdrawing balance, checking the balance of the marketplace contract, adding a listing fee, and more.
Now you can list NFTs that meet the conditions mentioned earlier using the NFT contract’s address and mint NFTs directly from the marketplace. You can use Sepolia or any other testnet to experiment with this.
That's how you can create your NFT marketplace. This is a simple version, and adding more features will increase the complexity. But it's a good starting point to build upon.
That's all for now. Thanks for reading and happy learning!
Subscribe to my newsletter
Read articles from Arujjwal Negi directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by