
Hello, first, check whether you have nodejs installed and after installed the necessary packages for work.
My operating system is Ubuntu 20.04 also you can work on windows or mac
1.NextJs
npx create-next-app@latest .
2.OpenZeppelin contracts
npm i @openzeppelin/contracts
3.ethers
npm i ethers
4.axios
npm i axios
5.web3
npm i web3
6.dotenv
npm i dotenv
7.ipfs-http-client
npm i ipfs-http-client
Counters: The contract uses OpenZeppelin's Counters library to manage token and item IDs. _tokenIds keeps track of the NFT token IDs, and _itemsSold tracks the number of items sold.
Listing Price: There's a default listing price of 0.0002 ether for creating market items. The contract owner can update this price using the updateListingPrice function.
Owner: The contract has an owner address, representing the owner of the contract, who has special privileges.
MarketItem Struct: The MarketItem struct holds information about a listed NFT, including its token ID, seller, owner, price, and whether it's been sold.
Event: The MarketItemCreated event is emitted when a new item is listed on the marketplace, providing important information about the listing.
Constructor: The constructor initializes the contract with the name "Alphanft Tokens" and symbol "ALT," and sets the contract owner to the address that deployed the contract.
updateListingPrice: This function allows the contract owner to update the listing price for creating market items.
getListingPrice: A public view function to retrieve the current listing price.
createMarketItem: This private function is used to create a new market item. It requires a token ID and a price, checks if the price is valid, and transfers the NFT to the contract. The item's details are stored in the idToMarketItem mapping, and the MarketItemCreated event is emitted.
1. createToken Function:
Input Parameters: This function takes two parameters:
tokenURI (string): A URI pointing to the metadata associated with the token.
price (uint256): The price at which the token is listed for sale.
Execution:
It first increments the _tokenIds counter, which likely keeps track of the unique identifiers for newly created tokens.
Then, it mints a new token and associates it with the sender (msg.sender), effectively transferring ownership to the caller.
The token's URI metadata is set using _setTokenURI.
After creating the token, it invokes the createMarketItem function, which appears to be responsible for creating a marketplace listing for this token, specifying the newTokenId and the given price.
Finally, it returns the newTokenId, which is the unique identifier of the newly created token.
2. resellToken Function:
Input Parameters: This function takes two parameters:
tokenId (uint256): The unique identifier of the token being resold.
price (uint256): The new price at which the token is listed for resale.
Execution:
It begins with two requirements:
Ensures that the sender (msg.sender) is the current owner of the token (idToMarketItem[tokenId].owner). This is to prevent unauthorized reselling.
Verifies that the value sent with this function (msg.value) is equal to the listingPrice, ensuring the correct amount is provided to list the token for resale.
If both requirements are met:
The token's status is marked as unsold by setting idToMarketItem[tokenId].sold to false.
The token's price is updated to the new price provided.
The seller's address (idToMarketItem[tokenId].seller) is set to the sender's address (msg.sender).
The token's ownership is temporarily transferred to the contract address (address(this)), indicating that it is listed for sale but not owned by anyone.
The _itemsSold counter is decremented to account for the fact that this token is no longer considered sold.
Finally, the token is transferred from the sender to the contract address (address(this)), effectively listing it for resale in the marketplace.
cancelListing Function :
Input: It takes one parameter, tokenId, which represents the unique identifier of the NFT listing that the user wants to cancel.
Ownership Check: It begins with a requirement that ensures only the owner of the NFT listing (the seller) can perform this operation. If the sender (the caller of this function) is not the seller, the operation will revert.
NFT Transfer: It transfers the ownership of the NFT back to the seller (msg.sender). This is done using the _transfer function, which is likely inherited from an ERC721 contract.
Reset Listing Details: After the NFT is returned to the seller, the contract updates the listing details in the idToMarketItem mapping:
It marks the item as unsold by setting idToMarketItem[tokenId].sold to false.
The price is set to 0, effectively removing the listing price.
The seller (idToMarketItem[tokenId].seller) is set to the zero address (address(0)), indicating that the NFT is no longer listed for sale.
The owner of the NFT (idToMarketItem[tokenId].owner) is set to the seller's address (msg.sender), as they now own the NFT again.
Items Sold Counter: Finally, it increments the _itemsSold counter. This counter keeps track of the number of items that have been sold through the marketplace.
Function Signature:
function createMarketSale(uint256 tokenId) public payable nonReentrant
Parameters:
tokenId: The unique identifier of the NFT that the user wants to purchase.
Function Description:
The function is used by a buyer to complete the purchase of an NFT by providing the necessary payment.
Implementation:
uint256 price = idToMarketItem[tokenId].price;: Retrieve the price of the NFT being purchased from the marketplace based on its token ID.
uint256 totalAmount = price + listingPrice;: Calculate the total amount required for the purchase, which includes the NFT's price and the marketplace's listing fee.
require(msg.value == totalAmount, "Please submit the asking price in order to complete purchase");: Ensure that the buyer has sent the exact required payment to complete the purchase. If the payment amount is not equal to totalAmount, the transaction will revert.
Payment Handling:
(bool sellerTransferSuccess, ) = idToMarketItem[tokenId].seller.call{ value: price }("");: Attempt to transfer the NFT's price directly to the seller. If the transfer is successful, sellerTransferSuccess will be true.
require(sellerTransferSuccess, "Seller transfer failed");: Ensure that the transfer to the seller was successful. If it fails, the transaction will revert.
(bool listingTransferSuccess, ) = address(this).call{ value: listingPrice }("");: Attempt to transfer the marketplace's listing fee to the contract itself. If the transfer is successful, listingTransferSuccess will be true.
require(listingTransferSuccess, "Listing transfer failed");: Ensure that the transfer of the listing fee was successful. If it fails, the transaction will revert.
Updating Item Details:
idToMarketItem[tokenId].owner = payable(msg.sender);: Update the ownership of the purchased NFT to the buyer (msg.sender).
idToMarketItem[tokenId].sold = true;: Mark the NFT as sold.
idToMarketItem[tokenId].seller = payable(address(0));: Set the seller's address to the zero address to indicate that the NFT is no longer owned by the seller.
Incrementing Items Sold Counter:
_itemsSold.increment();: Increment the counter for the total number of items sold in the marketplace.
Transferring NFT Ownership:
_transfer(address(this), msg.sender, tokenId);: Transfer the ownership of the purchased NFT from the contract (where it was temporarily held during the sale) to the buyer (msg.sender).
Function Signature:
function fetchMarketItems() public view returns (MarketItem[] memory)
Function Description:
The function is designed to be called by anyone (public) and is used to retrieve a list of market items (NFTs) that are currently available for purchase in the marketplace.
Implementation:
uint256 itemCount = _tokenIds.current();: Get the total number of NFTs that have been created and are currently tracked by the contract.
uint256 unsoldItemCount = _tokenIds.current() - _itemsSold.current();: Calculate the number of unsold NFTs by subtracting the total items sold (_itemsSold.current()) from the total number of NFTs (_tokenIds.current()).
uint256 currentIndex = 0;: Initialize a variable to keep track of the current index while iterating through the market items.
MarketItem[] memory items = new MarketItem[](unsoldItemCount);: Create a dynamic array of MarketItem structs to store information about the unsold NFTs. The array is sized based on the number of unsold items.
The function then enters a loop that iterates through each NFT (from 1 to itemCount) and checks if the NFT is currently owned by the contract (idToMarketItem[i + 1].owner == address(this)). If the NFT is owned by the contract, it is considered an unsold market item, and its information is added to the items array.
uint256 currentId = i + 1;: Calculate the current NFT's ID.
MarketItem storage currentItem = idToMarketItem[currentId];: Access the MarketItem struct for the current NFT.
items[currentIndex] = currentItem;: Add the information about the current NFT to the items array at the current index.
currentIndex += 1;: Increment the index to prepare for the next iteration.
Return Value:
The function returns an array (items) containing information about all the unsold market items in the marketplace.
Function Signature:
function fetchMyNFTs() public view returns (MarketItem[] memory)
Function Description:
This function is designed to be called by any user (public) and is used to fetch a list of NFTs that are currently owned by the caller (the msg.sender) in the NFT marketplace.
Implementation:
uint256 totalItemCount = _tokenIds.current();: Get the total number of NFTs that have been created and are currently tracked by the contract.
uint256 itemCount = 0;: Initialize a variable to count the number of NFTs owned by the caller.
uint256 currentIndex = 0;: Initialize a variable to keep track of the current index while iterating through the NFTs.
The function enters a loop that iterates through each NFT (from 1 to totalItemCount) and checks if the NFT is currently owned by the caller (msg.sender). If the NFT is owned by the caller, it increments the itemCount to keep track of the number of NFTs owned.
if (idToMarketItem[i + 1].owner == msg.sender) {: Check if the current NFT is owned by the caller.
After counting the user's NFTs, the function creates a dynamic array of MarketItem structs called items, which is sized based on the itemCount.
The function then enters a second loop that iterates through all NFTs (from 1 to totalItemCount) and checks again if each NFT is owned by the caller. If it is, the information about the NFT is added to the items array.
if (idToMarketItem[i + 1].owner == msg.sender) {: Check if the current NFT is owned by the caller.
uint256 currentId = i + 1;: Calculate the current NFT's ID.
MarketItem storage currentItem = idToMarketItem[currentId];: Access the MarketItem struct for the current NFT.
items[currentIndex] = currentItem;: Add the information about the current NFT to the items array at the current index.
currentIndex += 1;: Increment the index to prepare for the next iteration.
Return Value:
The function returns an array (items) containing information about all the NFTs owned by the caller in the marketplace.
Function Signature:
function fetchItemsListed() public view returns (MarketItem[] memory)
Function Description:
This function is designed to be called by any user (public) and is used to fetch a list of NFTs that the caller (the msg.sender) has listed for sale in the NFT marketplace.
Implementation:
uint256 totalItemCount = _tokenIds.current();: Get the total number of NFTs that have been created and are currently tracked by the contract.
uint256 itemCount = 0;: Initialize a variable to count the number of NFTs listed for sale by the caller.
uint256 currentIndex = 0;: Initialize a variable to keep track of the current index while iterating through the NFTs.
The function enters a loop that iterates through each NFT (from 1 to totalItemCount) and checks if the NFT is currently listed for sale by the caller (msg.sender). If the NFT is listed by the caller, it increments the itemCount to keep track of the number of listed NFTs.
if (idToMarketItem[i + 1].seller == msg.sender) {: Check if the current NFT is listed for sale by the caller.
After counting the user's listed NFTs, the function creates a dynamic array of MarketItem structs called items, which is sized based on the itemCount.
The function then enters a second loop that iterates through all NFTs (from 1 to totalItemCount) and checks again if each NFT is listed for sale by the caller. If it is, the information about the NFT is added to the items array.
if (idToMarketItem[i + 1].seller == msg.sender) {: Check if the current NFT is listed for sale by the caller.
uint256 currentId = i + 1;: Calculate the current NFT's ID.
MarketItem storage currentItem = idToMarketItem[currentId];: Access the MarketItem struct for the current NFT.
items[currentIndex] = currentItem;: Add the information about the current NFT to the items array at the current index.
currentIndex += 1;: Increment the index to prepare for the next iteration.
Return Value:
The function returns an array (items) containing information about all the NFTs that the caller has listed for sale in the marketplace.
Function Signature:
function fetchSellerNFTs(address _seller) public view returns (MarketItem[] memory)
Function Description:
This function is designed to be called by any user (public) and is used to fetch a list of NFTs owned by a specific seller (specified by the _seller parameter) within the NFT marketplace.
Function Parameters:
_seller: The Ethereum address of the seller for whom the NFTs are to be fetched.
Implementation:
uint256 totalItemCount = _tokenIds.current();: Get the total number of NFTs that have been created and are currently tracked by the contract.
uint256 itemCount = 0;: Initialize a variable to count the number of NFTs owned by the specified seller.
uint256 currentIndex = 0;: Initialize a variable to keep track of the current index while iterating through the NFTs.
address topSeller = _seller;: Assign the specified seller's address to a variable named topSeller.
The function enters a loop that iterates through each NFT (from 1 to totalItemCount) and checks if the NFT is currently owned by the topSeller. If the NFT is owned by the specified seller, it increments the itemCount to keep track of the number of NFTs owned by that seller.
if (idToMarketItem[i + 1].seller == topSeller) {: Check if the current NFT is owned by the specified seller (topSeller).
After counting the NFTs owned by the seller, the function creates a dynamic array of MarketItem structs called items, which is sized based on the itemCount.
The function then enters a second loop that iterates through all NFTs (from 1 to totalItemCount) and checks again if each NFT is owned by the topSeller. If it is, the information about the NFT is added to the items array.
if (idToMarketItem[i + 1].seller == topSeller) {: Check if the current NFT is owned by the specified seller (topSeller).
uint256 currentId = i + 1;: Calculate the current NFT's ID.
MarketItem storage currentItem = idToMarketItem[currentId];: Access the MarketItem struct for the current NFT.
items[currentIndex] = currentItem;: Add the information about the current NFT to the items array at the current index.
currentIndex += 1;: Increment the index to prepare for the next iteration.
Return Value:
The function returns an array (items) containing information about all the NFTs owned by the specified seller within the marketplace.
Function Signature:
function withdraw() public payable onlyOwner
Function Description:
This function is designed to be called by the contract owner (address that deployed the contract). Its purpose is to withdraw the ether balance that might have accumulated in the contract. The function ensures that only the contract owner can trigger this action.
Function Modifiers:
onlyOwner: This is a custom modifier that restricts the execution of the function to only the contract owner. It checks if the sender (caller) of the function is the owner before allowing the function to proceed.
Implementation:
(bool success, ) = payable(msg.sender).call{ value: address(this).balance }("");: This line initiates a low-level call to the contract owner's address (msg.sender) and transfers the entire balance held by the contract (address(this).balance) to the owner's address. The result of the call is captured in the success variable, which is a boolean indicating whether the call was successful.
require(success);: After the call is made, this line checks if the success variable is true, indicating that the transfer was successful. If the transfer fails for any reason (e.g., out-of-gas or a failed execution), the require statement will cause the function to revert, ensuring that the ether remains in the contract.
Function Access Control:
The onlyOwner modifier ensures that only the owner of the contract can execute this function. This helps maintain control over when and by whom funds can be withdrawn from the contract.
Usage:
The withdraw function is typically used by the contract owner to retrieve any accumulated ether from the contract. This can be important for managing the contract's finances or distributing earnings from the marketplace.
In this lecture, we started writing the NFT Context file and registered in Infura in order to get public and secret api keys as well as subdomain
Description of NFTContext:
Imports:
The code imports several libraries and dependencies needed for the application, including React for building the user interface, ethers for Ethereum interactions, Web3Modal for handling Ethereum wallet connections, Web3 for Ethereum provider setup, axios for HTTP requests, and ipfs-http-client for interfacing with the IPFS (InterPlanetary File System) network.
Environment Variables:
The code utilizes environment variables for sensitive information such as the projectId and projectSecret. These variables are expected to be set in the environment where the application runs.
IPFS Configuration:
The code configures an IPFS client using the ipfs-http-client library. It connects to an IPFS node hosted on ipfs.infura.io over HTTPS and provides authorization headers using a basic authentication mechanism.
Exporting NFTContext:
The code exports an NFTContext object created with React.createContext(). This context used to share data and functions related to NFTs and the NFT marketplace across different components of the application.
-------------------------------------------------------------------------------------------------------------------
.env
NEXT_PUBLIC_PROJECT_ID=
NEXT_PUBLIC_SECRECT_KEY=
State Management:
currentAccount: This state variable appears to store the current Ethereum account (address) associated with the user.
It's likely used to track the user's wallet account.
network: This state variable is a boolean flag that might indicate whether the application is connected to an Ethereum network or not.
isLoadingNFT: This state variable is a boolean flag used to manage loading states, possibly related to fetching NFT data.
isWalletInstalled: This state variable is also a boolean flag. I
t might indicate whether a supported Ethereum wallet (like MetaMask) is installed in the user's browser.
currentChainId: This variable to store the current Ethereum network chain ID.
Ethereum has different networks, and this variable might help track which network the application is connected to.
saleCancelled: This state variable appears to be an array that might be used
to store information about canceled sales or transactions.
Constants:
CONF: This constant likely holds some configuration data, possibly related to the application's settings.
ABIMARKET: This constant store the ABI (Application Binary Interface) for the marketplace's smart contract.
nftsPerPage: This constant defines the number of NFTs (Non-Fungible Tokens) to display per page,
which might be relevant for pagination or display purposes.
nftCurrency: This constant could indicate the currency used for pricing NFTs,
with 'ETH' suggesting that Ethereum (ETH) is the currency used.
Component Props:
The NFTProvider component receives a children prop.
It allows other components or content to be nested within NFTProvider and makes them accessible within its context.
Initialization:
The function starts by creating an instance of the Web3Modal, which is often used for connecting to Ethereum wallets and providers in web applications.
It then attempts to connect to a wallet through web3Modal.connect(), and it creates a Web3 provider using ethers.providers.Web3Provider(connection).
It extracts the current Ethereum network's chainId using provider.getNetwork(). This chainId represents the unique identifier of the connected Ethereum network.
Checking Network Compatibility:
The function checks if the chainId obtained from the current network matches any of the values in the targetChainId array ([137, 11155111]).
If there's a match, it sets the currentChainId state variable to the matched chainId and also sets the network state variable to true. It then returns the chainId.
Handling Network Mismatch:
If the chainId doesn't match any value in the targetChainId array, it implies that the user is on an unsupported network.
In this case, the function attempts to handle the mismatch by using Ethereum wallet APIs (window.ethereum) to switch the connected network.
It first checks if the networkVersion reported by the wallet (window.ethereum.networkVersion) is different from the defaultChainId (which is initially set to 137).
If they are different, it attempts to request a network switch using window.ethereum.request() with the method 'wallet_switchEthereumChain'. If the user approves the switch, the function might switch the user to the defaultChainId.
If the switch request fails (e.g., if the user denies the switch), the function may handle the error with a specific code (e.g., 4902) indicating that the chain has not been added to the wallet. In such cases, it may attempt to add the network to the wallet using 'wallet_addEthereumChain'.
The parameters provided for adding the Ethereum chain include details about the network, such as the chain name (e.g., 'Polygon'), chain ID, native currency, and RPC (Remote Procedure Call) URLs.
Logging Errors:
If any error occurs during this process, it logs an error message to the console with the text 'Error from checkNetwork'.
Initialization:
It sets the isLoadingNFT state variable to false, indicating that loading of NFTs has begun.
It initializes a connection to a web3 provider using Web3Modal. It retrieves the marketplace contract address (MARKETADDR) for the current Ethereum network (currentChainId) from a configuration object (CONF).
It creates an Ethereum contract instance using the retrieved contract address, the contract's ABI (ABIMARKET), and the web3 provider.
Fetching Market Items:
It calls the fetchMarketItems function on the marketplace contract to retrieve a list of market items. This likely includes information about NFTs that are listed for sale on the marketplace.
Processing Data:
It processes the fetched data using Promise.all, mapping each item in the data to a new object.
For each market item, it performs the following tasks:
Fetches the token's URI using contract.tokenURI(tokenId). This URI likely points to metadata associated with the NFT.
Makes an HTTP GET request to the token URI to retrieve additional data like image, name, and description.
Formats the price from its unformatted representation to a readable format in Ether.
Constructs an object containing various properties of the NFT, including price, tokenId, seller, owner, name, image, description, and tokenURI.
Sorting and Pagination:
It sorts the processed NFT items based on their tokenId in descending order, likely to display the newest items first.
It calculates the startIndex and endIndex for the range of items to display on the current page based on the currentPage and nftsPerPage values.
It extracts the items within the specified range to create itemsToShow.
Return:
Finally, the function returns itemsToShow, which is an array of NFTs ready to be displayed on the user interface.
Asynchronous Function: The function is declared as async, indicating that it will perform asynchronous operations, such as making network requests.
Upload to IPFS:
It attempts to upload the provided file (or content) to the IPFS using the client.add method. The client object is an instance of ipfsHttpClient configured to connect to an IPFS node.
If the upload is successful, the function proceeds to the next step. Otherwise, it catches any errors that occur during the upload process.
Construct URL:
If the upload is successful, it constructs a URL (url) using the base URL and appends the added.path to it. added.path represents the unique path or identifier of the uploaded content on the IPFS network.
Return URL:
The function returns the constructed url, which can be used to access the uploaded content on the IPFS network.
Error Handling:
If any errors occur during the upload process (e.g., network issues or IPFS node unavailability), an error message is logged to the console with the message "Error uploading to IPFS."
In this lecture we add custom style to globals.css , change tailwind.config.js and rewrite _app.js file.
Imports:
It imports several modules and components at the beginning, including Script, ThemeProvider from next-themes, and some custom components and styles.
Component Definition:
The MyApp function is defined as the root component of the application.
Component Structure:
It wraps the entire application content within a <NFTProvider>. This likely provides context and state related to NFTs to the entire application.
Theme Provider:
It uses the ThemeProvider from the next-themes library to enable dynamic theming based on a CSS class attribute. This allows users to switch between light and dark themes.
HTML Structure:
The content is enclosed within a <div> with a class that specifies the background color based on the theme (either light or dark). The min-h-screen class ensures that the content takes at least the height of the screen.
Navbar and Footer:
It includes a Navbar component at the top and a Footer component at the bottom. These likely provide navigation and site information to the user.
Font Awesome Icon Kit:
It loads the Font Awesome Icon Kit script from a CDN (Content Delivery Network). This script provides access to a library of icons for use in the application.
The Button component is a reusable button component.
It accepts several props:
btnName: The text that appears on the button.
classStyles: Additional CSS classes to apply to the button for styling.
handleClick: A callback function to be executed when the button is clicked.
Inside the component, it renders an HTML button element with the provided text (btnName).
It applies CSS classes and styles to the button, including a gradient background color, font styles, and text color.
It attaches an onClick event listener to the button that triggers the handleClick callback when the button is clicked.
The MenuItems component in Navbar is used to display a menu of items, for navigation.
It accepts several props:
isMobile: A boolean indicating whether the menu is being displayed in a mobile context.
active: The active menu item.
setActive: A function to set the active menu item.
Inside the component, there is a generateLink function that takes an index i and returns a route based on the index value.
The function uses a switch statement to map index values to specific routes. For example, index 0 maps to '/', index 1 maps to '/listed-nfts', and index 2 maps to '/my-nfts'.
Are you ready to take your existing skills in blockchain development to the next level? Welcome to our comprehensive practical video course, "Multichain NFT Marketplace in React Nextjs & Solidity Blockchain - 2024," designed to help you consolidate and enhance your expertise.
Who Is This Course For? This course is tailored for individuals who already have a foundational understanding of JavaScript, Intermediate knowledge of Solidity and Ethereum, and experience working with React. If you're eager to solidify your knowledge and master the art of creating a decentralized NFT marketplace that spans various blockchain networks, this course is perfect for you.
What You'll Learn:
Frontend Development with Next.js: We'll begin from scratch, guiding you through the process of building a modern, user-friendly frontend interface using Next.js. You'll learn how to craft responsive web designs and incorporate essential user interface elements.
Solidity Smart Contracts: Dive deep into Solidity, Ethereum's smart contract language. You'll become proficient in creating robust and secure smart contracts that power the backend of your NFT marketplace.
Connecting Blockchain and Frontend: Master the essential techniques for connecting the blockchain to your frontend application. Understand how to interact with smart contracts and retrieve data from various blockchain networks.
Multi-Network Integration: Explore the intricacies of integrating your NFT marketplace across multiple blockchain networks, including Ethereum and others like Polygon. Grasp the challenges and solutions for operating seamlessly on different chains.
Full Project Development: Throughout the course, you'll work on a real-world project, starting with a blank canvas and progressing to a fully operational multi-network NFT marketplace. Gain practical experience by writing code and tackling real development challenges.
Why Take This Course? By the end of this course, you will not only have fortified your technical skill set but will also possess a deep understanding of how to create a fully functional NFT marketplace that operates on multiple blockchain networks. This knowledge is invaluable for developers seeking to excel in the rapidly growing world of decentralized applications and NFT ecosystems.
Prerequisites:
Intermediate knowledge of JavaScript.
Intermediate knowledge of Solidity and Ethereum.
Experience working with React.