#21DaysSolidityChallenge Day 16: Enter the NFT Universe โ€” Crafting Your Own NFT Marketplace ๐ŸŒŒ๐Ÿš€

Solidity Academy
Coinmonks

--

๐Ÿš€ Buy me a coffee! โ˜• http://buymeacoffee.com/solidity

๐Ÿ‘‹ Welcome to Day 16 of the Solidity Code Challenge! Today, weโ€™re embarking on a thrilling journey into the world of Non-Fungible Tokens (NFTs) and decentralized marketplaces. NFTs are unique digital assets that have taken the blockchain world by storm, enabling ownership and trading of digital art, collectibles, and more. In this challenge, youโ€™ll create your very own NFT marketplace, complete with features like minting, buying, selling, auctions, royalties, and metadata storage.

#21DaysSolidityChallenge 21 Days Solidity Coding Challenge

Oh, this magical link is just sooo tempting! ๐Ÿช„โœจ Click away, my dear friend. ๐Ÿ˜‰

In this adventure, youโ€™ll learn:

- The significance of NFTs in the blockchain space.
- How to develop a fully functional NFT marketplace using Solidity.
- Practical use cases for NFTs beyond art and collectibles.

๐ŸŒŒ The Rise of NFTs in the Digital Universe

NFTs have revolutionized the way we think about ownership and provenance in the digital realm. Unlike cryptocurrencies such as Bitcoin or Ethereum, NFTs are unique and indivisible, making them the perfect medium for representing digital assets with verifiable scarcity.

Step 1: Setting Up Your Development Environment

Before we embark on building an NFT marketplace, ensure you have the following tools and accounts ready:

1. Ethereum Wallet: Youโ€™ll need an Ethereum wallet like MetaMask to interact with the Ethereum blockchain.

2. Solidity Compiler: Ensure you have the Solidity compiler (solc) installed on your computer or use online Solidity development environments like Remix.

3. Test Network: Choose a test network (e.g., Ropsten, Rinkeby, or Kovan) to deploy and test your NFT marketplace without using real Ether.

4. Integrated Development Environment (IDE): Consider using an IDE like Visual Studio Code with Solidity extensions for a smoother coding experience.

Step 2: Understanding NFTs

NFTs are unique digital tokens that represent ownership of a specific asset. Key attributes of NFTs include:

- Uniqueness: Each NFT has a distinct value and cannot be replicated.

- Indivisibility: NFTs cannot be divided into smaller units.

- Ownership: NFTs prove ownership of digital or physical assets.

- Interoperability: NFTs can be transferred and traded across different platforms.

Step 3: Building Your NFT Marketplace

Letโ€™s create a simplified version of an NFT marketplace in Solidity. In this example, weโ€™ll focus on the core components: minting, buying, selling, auctions, royalties, and metadata storage.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract NFTMarketplace is ERC721Enumerable, Ownable {
using SafeMath for uint256;
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
uint256 public royaltyPercentage = 10; // 10% royalty to creators
struct NFT {
address creator;
uint256 price;
}
mapping(uint256 => NFT) public nftsForSale;
mapping(uint256 => uint256) public currentBid;
mapping(uint256 => address) public currentBidder;
event NFTMinted(uint256 indexed tokenId, address indexed creator, uint256 price);
event NFTListed(uint256 indexed tokenId, uint256 price);
event NFTSold(uint256 indexed tokenId, address indexed seller, address indexed buyer, uint256 price);
event NFTBidPlaced(uint256 indexed tokenId, address indexed bidder, uint256 bidAmount);
event NFTBidWithdrawn(uint256 indexed tokenId, address indexed bidder, uint256 bidAmount);
event NFTAuctionEnded(uint256 indexed tokenId, address indexed winner, uint256 winningBid);
constructor() ERC721("NFTMarketplace", "NFTM") {}
// Mint a new NFT
function mintNFT() external {
uint256 tokenId = _tokenIdCounter.current();
_mint(msg.sender, tokenId);
_tokenIdCounter.increment();
emit NFTMinted(tokenId, msg.sender, 0);
}
// List an NFT for sale
function listNFTForSale(uint256 tokenId, uint256 price) external {
require(_exists(tokenId), "Token does not exist");
require(ownerOf(tokenId) == msg.sender, "You are not the owner");
nftsForSale[tokenId] = NFT(msg.sender, price);
emit NFTListed(tokenId, price);
}
// Buy an NFT
function buyNFT(uint256 tokenId) external payable {
require(_exists(tokenId), "Token does not exist");
NFT memory nft = nftsForSale[tokenId];
require(nft.price > 0, "Token is not for sale");
require(msg.value >= nft.price, "Insufficient funds");
address seller = nft.creator;
nftsForSale[tokenId] = NFT(address(0), 0);
_safeTransfer(seller, msg.sender, tokenId,
"");
payable(seller).transfer(msg.value);
emit NFTSold(tokenId, seller, msg.sender, nft.price);
}
// Place a bid on an NFT auction
function placeBid(uint256 tokenId) external payable {
require(_exists(tokenId), "Token does not exist");
NFT memory nft = nftsForSale[tokenId];
require(nft.price == 0, "Token is not for auction");
require(msg.value > currentBid[tokenId], "Bid must be higher than the current bid");
if (currentBidder[tokenId] != address(0)) {
payable(currentBidder[tokenId]).transfer(currentBid[tokenId]);
}
currentBid[tokenId] = msg.value;
currentBidder[tokenId] = msg.sender;
emit NFTBidPlaced(tokenId, msg.sender, msg.value);
}
// Withdraw a bid from an NFT auction
function withdrawBid(uint256 tokenId) external {
require(_exists(tokenId), "Token does not exist");
require(msg.sender == currentBidder[tokenId], "You did not place the current bid");
uint256 bidAmount = currentBid[tokenId];
require(bidAmount > 0, "No active bid");
currentBid[tokenId] = 0;
currentBidder[tokenId] = address(0);
payable(msg.sender).transfer(bidAmount);
emit NFTBidWithdrawn(tokenId, msg.sender, bidAmount);
}
// End an NFT auction and transfer the NFT to the highest bidder
function endAuction(uint256 tokenId) external onlyOwner {
require(_exists(tokenId), "Token does not exist");
NFT memory nft = nftsForSale[tokenId];
require(nft.price == 0, "Token is not for auction");
require(currentBid[tokenId] > 0, "No active bid");
address winner = currentBidder[tokenId];
uint256 winningBid = currentBid[tokenId];
currentBid[tokenId] = 0;
currentBidder[tokenId] = address(0);
_safeTransfer(nft.creator, winner, tokenId, "");
payable(nft.creator).transfer(winningBid);
emit NFTAuctionEnded(tokenId, winner, winningBid);
}
// Set the royalty percentage for creators
function setRoyaltyPercentage(uint256 percentage) external onlyOwner {
require(percentage <= 100, "Percentage must be <= 100");
royaltyPercentage = percentage;
}
// Withdraw royalties earned by the creator
function withdrawRoyalties() external {
uint256 balance = address(this).balance;
uint256 royalties = (balance * royaltyPercentage) / 100;
payable(owner()).transfer(royalties);
}
// Override _baseURI to provide metadata for NFTs
function _baseURI() internal view override returns (string memory) {
return "https://your-metadata-api.com/api/token/";
}
}

In this example:

- We have a `NFTMarketplace` contract that inherits from the ERC721Enumerable and Ownable contracts. It represents the NFT marketplace and handles core functionalities.

- Users can mint new NFTs, list NFTs for sale, buy NFTs, place bids on NFT auctions, and end auctions to transfer NFTs to the highest bidder.

- The contract supports royalties for creators, enabling them to earn a percentage of each secondary sale.

- Metadata for NFTs is served through a metadata API, and you can replace the base URI with your own.

## Step 4: Compiling and Deploying the NFT Marketplace Contract

Compile your NFT Marketplace contract using the Solidity compiler. Use the following command in your terminal:

solc - bin - abi NFTMarketplace.sol

This command generates the bytecode and ABI required for contract deployment.

Now, deploy your NFT Marketplace contract to a test network. Follow these steps:

1. Open your Ethereum wallet (e.g., MetaMask) and switch to the Ropsten network.

2. Acquire some test Ether for Ropsten from a faucet if needed.

3. Deploy your contract using Remix or another tool.

4. Confirm the deployment in your wallet, and your NFT Marketplace contract is now live on the Ropsten network.

Step 5: Interacting with Your NFT Marketplace

You can now interact with your NFT Marketplace contract as an owner, creator, or buyer. Here are some key interactions:

- As the contract owner, you can set the royalty percentage and withdraw royalties earned by creators.

- Creators can mint new NFTs and list them for sale.

- Buyers can purchase NFTs or place bids on NFT auctions.

Step 6: Testing and Expanding Your NFT Marketplace

To ensure your NFT Marketplace functions correctly, conduct extensive testing on the test network. Consider expanding your solution to include advanced features such as decentralized storage for NFT metadata, custom auction durations, and additional metadata attributes.

Step 7: Practical Use Cases

NFT Marketplaces can be applied to various use cases, including:

- Digital Art: Mint, buy, and sell unique digital artworks.

- Collectibles: Create and trade digital collectibles, including trading cards and virtual pets.

- Gaming: Tokenize in-game assets and enable players to buy, sell, and trade them.

Conclusion ๐ŸŒŒ๐Ÿš€

Congratulations! Youโ€™ve crafted your own NFT marketplace, diving into the exciting world of digital ownership and tokenization. NFTs have transformed the way we think about digital assets, offering limitless possibilities for creators and collectors.

As you continue your Solidity journey, explore advanced NFT features, integrate with decentralized storage solutions like IPFS for metadata, and consider real-world applications for your NFT marketplace.

Stay tuned for more exciting challenges and concepts in our Solidity Code Challenge series. Happy coding, and may your NFT marketplace thrive in the vast digital universe! ๐ŸŒŒ๐Ÿš€

๐Ÿ“š Resources ๐Ÿ“š

--

--

Solidity Academy
Coinmonks
Writer for

Learn smart contract development and blockchain integration in depth. https://heylink.me/solidity/ SEND US Your Products to Review! solidity101@gmail.com