How to write smart contract for NFT marketplace

How to write smart contract for NFT marketplace




Introduction

This technical guide will give you a comprehensive guide to building a complete NFT marketplace ecosystem using Solidity and Openzeppelin.
Our marketplace features a native token, NFT creation with customizable royalties, and secure trading mechanisms.



Technical Stack

  • Solidity ^0.8.27
  • OpenZeppelin Contracts
  • Hardhat Development Environment
  • TypeScript
  • Ethers.js



Contract Structure

The project is structured into three main contracts:

  • Platform Token (NYWToken.sol)
  • NFT Contract (NYWNFT.sol)
  • Marketplace Contract (NYWMarketplace.sol)

1. Platform Token Implementation (NYWToken.sol)

The foundation of our marketplace starts with implementing the platform’s native token.

This NYWToken contract is a simple ERC20 token implementation.
It inherits from the OpenZeppelin ERC20 contract and initializes the token with a supply of 1 billion tokens.

Key Features:

  • Token Supply: 1 billion tokens
  • Token Standard: ERC20 compliance
  • Decimals: 18 decimal places for maximum divisibility
  • Initial Distribution: All tokens minted to contract deployer
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract NYWToken is ERC20 {
    uint256 initialSupply = 10 ** 9;

    constructor() ERC20("NYWToken", "NYW") {
        _mint(msg.sender, initialSupply * 10 ** decimals());
    }
}
Enter fullscreen mode

Exit fullscreen mode

2. NFT Contract Implementation

The NYWNFT contract handles creating and burning NYW NFT token, and royalty management.
This contract inherits from the OpenZeppelin ERC721 contract, which provides the necessary functionality for creating and managing NFTs.

Key Functions:

  • createNYW(): Creates new NFTs with customizable royalties
  • burnNYW(): Removes NFTs from circulation
  • getCreator(): Updates metadata URI
  • getRoyalty(): Returns royalty configuration

Here is a detailed implementation of the NYWNFT contract:

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract NYWNFT is ERC721URIStorage, Ownable {
    uint256 private _tokenId;

    mapping(uint256 => address) public creators;
    mapping(uint256 => uint256) public royalties;

    event NYWTokenCreated(
        address indexed creator,
        uint256 tokenId,
        uint256 royalty,
        string tokenURI
    );
    event NYWTokenBurned(address indexed burner, uint256 tokenId);

    constructor() ERC721("NYW NFT", "NYW") Ownable(msg.sender) {}

    function createNYW(
        string memory tokenURI,
        uint256 royalty
    ) external returns (uint256) {
        require(
            royalty >= 0 && royalty <= 30,
            "Royalty must be between 0 and 30"
        );
        _tokenId += 1;

        creators[_tokenId] = msg.sender;
        royalties[_tokenId] = royalty;
        _safeMint(msg.sender, _tokenId);
        _setTokenURI(_tokenId, tokenURI);
        _setApprovalForAll(msg.sender, address(this), true);

        emit NYWTokenCreated(msg.sender, _tokenId, royalty, tokenURI);

        return _tokenId;
    }

    function burnNYW(uint256 tokenId) external {
        require(
            msg.sender == ownerOf(tokenId),
            "Only the owner can burn the token"
        );

        _burn(tokenId);
        delete creators[tokenId];
        delete royalties[tokenId];

        emit NYWTokenBurned(msg.sender, tokenId);
    }

    function getCreator(uint256 tokenId) external view returns (address) {
        return creators[tokenId];
    }

    function getRoyalty(uint256 tokenId) external view returns (uint256) {
        return royalties[tokenId];
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        override(ERC721URIStorage)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }
}
Enter fullscreen mode

Exit fullscreen mode

3. Marketplace Contract Implementation (NYWMarketplace.sol)

The NYWMarketplace contract manages listings, delisting and buying NFTs and withdrawing funds:

Key Functions:

  • listNFT(uint256 tokenId_, uint256 price_): Lists new NFT to marketplace for sale
  • delistNFT(uint256 tokenId_): Removes NFT from marketplace
  • buyNFT(uint256 tokenId_): Purchases NFT from marketplace
  • withdraw(): Withdraws funds from marketplace
    function listNFT(uint256 tokenId_, uint256 price_) external {
        // Check if the NFT is already listed
        require(!isExisting[tokenId_], "NFT is already listed");
        // Check if the NFT is owned by the caller
        require(
            nftContract.ownerOf(tokenId_) == msg.sender,
            "You are not the owner of the NFT"
        );

        //Define new NFTMarketItem
        NFTMarketItem memory newNFTMarketItem = NFTMarketItem(
            tokenId_,
            price_,
            nywContract.getRoyalty(tokenId_),
            payable(msg.sender),
            nywContract.getCreator(tokenId_),
            true
        );

        isExisting[tokenId_] = true;
        listedNFTs.push(newNFTMarketItem);
        tokenIdToNFTMarketItemId[tokenId_] = totalListedNFTs;
        totalListedNFTs++;

        emit NYWNFTListed(
            tokenId_,
            price_,
            nywContract.getRoyalty(tokenId_),
            nywContract.getCreator(tokenId_),
            msg.sender
        );
    }

    function delistNFT(uint256 tokenId_) external {
        require(isExisting[tokenId_], "NFT is not listed");
        uint256 nftMarketItemId = tokenIdToNFTMarketItemId[tokenId_];
        require(
            listedNFTs[nftMarketItemId].seller == msg.sender,
            "Only the seller can delist the NFT"
        );

        deleteNFTfromArray(tokenId_);
        emit NYWNFTDelisted(tokenId_);
    }

    function deleteNFTfromArray(uint256 tokenId_) public {
        uint256 nftMarketItemId = tokenIdToNFTMarketItemId[tokenId_];
        uint256 lastIndex = listedNFTs.length - 1;
        listedNFTs[nftMarketItemId] = listedNFTs[lastIndex];
        tokenIdToNFTMarketItemId[
            listedNFTs[lastIndex].tokenId
        ] = nftMarketItemId;
        listedNFTs.pop();
        totalListedNFTs--;
        delete tokenIdToNFTMarketItemId[tokenId_];
        isExisting[tokenId_] = false;
    }

    function buyNFT(uint256 tokenId_) public payable {
        require(isExisting[tokenId_], "NFT is not listed");
        uint256 _nftMarketItemId = tokenIdToNFTMarketItemId[tokenId_];
        NFTMarketItem memory _nftMarketItem = listedNFTs[_nftMarketItemId];
        require(!_nftMarketItem.isSold, "NFT is already sold");
        require(msg.value == _nftMarketItem.price, "Incorrect payment amount");

        // Calculate royalty amount
        uint256 _royaltyAmount = (_nftMarketItem.price *
            _nftMarketItem.royalty) / deno;
        // Calculate platform fee
        uint256 _platformFeeAmount = (_nftMarketItem.price * platformFee) /
            deno;
        // Calculate seller amount
        uint256 _sellerAmount = _nftMarketItem.price -
            _royaltyAmount -
            _platformFeeAmount;
        // Transfer funds to the seller
        payable(_nftMarketItem.seller).transfer(_sellerAmount);
        // Transfer royalty amount to the creator
        payable(_nftMarketItem.creator).transfer(_royaltyAmount);
        // Transfer platform fee amount to the platform
        payable(owner()).transfer(_platformFeeAmount);
        //Transfer NFT to the buyer
        nftContract.safeTransferFrom(
            _nftMarketItem.seller,
            msg.sender,
            _nftMarketItem.tokenId
        );

        _nftMarketItem.isSold = true;
        deleteNFTfromArray(tokenId_);
        emit NYWNFTBought(
            _nftMarketItem.tokenId,
            msg.sender,
            _nftMarketItem.seller,
            _nftMarketItem.price
        );
    }

    function withdraw() external onlyOwner {
        uint256 balance = address(this).balance;
        require(balance > 0, "No funds to withdraw");
        payable(owner()).transfer(balance);
        emit NYWNFTWithdrawn(balance);
    }
Enter fullscreen mode

Exit fullscreen mode



Conclusion

Building a secure and efficient NFT marketplace requires careful implementation of multiple smart contracts working together. This guide covered the essential components: platform token, NFT contract, and marketplace functionality.



Source link
lol

By stp2y

Leave a Reply

Your email address will not be published. Required fields are marked *

No widgets found. Go to Widget page and add the widget in Offcanvas Sidebar Widget Area.