7. स्क्रैच/शुरुआत से एनएफटी मार्केटप्लेस कैसे बनाएं

रोड टू वेब3 श्रृंखला(series) के सातवें सप्ताह में आपका स्वागत है। यह ट्यूटोरियल आपको सिखाता है कि स्क्रैच से अपना खुद का NFT मार्केटप्लेस कैसे बनाया जाए: फ्रंटएंड, डेटा स्टोरेज, और स्मार्ट कॉन्ट्रैक्ट!

चाहे आप उपयोगकर्ताओं की संख्या के आधार पर सॉर्ट(sort) करें या वॉल्यूम के आधार पर, NFT मार्केटप्लेसेस Web3 की सबसे बड़ी कंपनियों में से एक हैं। उदाहरण के लिए:

  • जनवरी 2022 में, ****Opensea(ओपन सी),**** इथिरियम के सबसे बड़े एनएफटी मार्केटप्लेस ने ~2.5 मिलियन एनएफटी बेचे और वॉल्यूम(volume) में $5 बिलियन का कारोबार किया।
  • मई 2022 में, Magic Eden(मैजिक ईडन), सोलाना के सबसे बड़े एनएफटी मार्केटप्लेस में ~11.3 मिलियन की ट्रांसक्शन्स और वॉल्यूम(volume) में $200 मिलियन थे।

इस तरह का पैमाना(scale) केवल बड़े स्मार्ट कॉन्ट्रैक्ट और स्केलेबल इंफ्रास्ट्रक्चर के साथ हासिल किया जाता है। इसलिए यदि आप एक वेब3 डेवलपर हैं जो अपने वेब3 विकास कौशल में सुधार करना चाहते हैं, तो एल्केमी, आईपीएफएस, हार्डहैट और ईथर.जेएस(ethers.js)का उपयोग करके एनएफटी मार्केटप्लेस बनाने पर इस ट्यूटोरियल को फॉलो करें।

ध्यान में रखने योग्य कुछ बातें:

  • इस ट्यूटोरियल का फोकस स्मार्ट कॉन्ट्रैक्ट बनाने पर होगा न कि फ्रंटएंड बनाने पर। हालाँकि, NFT मार्केटप्लेस के लिए फ्रंटएंड कोड GitHub पर उपलब्ध है
  • इस ट्यूटोरियल में कोई बैकएंड या डेटाबेस शामिल नहीं है। एक बैकएंड और डेटाबेस की आवश्यकता तभी होगी जब आप डेटा संग्रहित(archive) करना शुरू करेंगे और पंजीकरण या लॉगिन(registration or login) सुविधाओं को इंटिग्रेटे करेंगे।

चरण 0: एक एल्केमी खाते के लिए साइन अप करें और एक नया ऐप बनाएं

यदि आपने पहले से साइन अप नहीं किया है, तो अपने निःशुल्क एल्केमी खाते के लिए साइन अप करें

फिर आप एक नया ऐप बना सकते हैं और ऐप डैशबोर्ड से एपीआई keys (कीस/कुंजियाँ) बना सकते हैं।

ऐप बनाने के तरीके को जानने के लिए यह वीडियो देखें:

📘

एक नया एल्केमी ऐप बनाने के तरीके को जानने के लिए वीडियो ट्यूटोरियल


या नीचे लिखित चरणों का पालन करें:

  1. "Apps" टैब में "create app" बटन पर जाए
3584

एक सैम्पल डैशबोर्ड का स्क्रीनशॉट

अपनी नई key(की/कुंजी) प्राप्त करने के लिए पॉपअप पर विवरण भरें। इस ट्यूटोरियल के लिए, आपको "Ethereum" को चेन के रूप में और "Goerli" को टेस्ट नेटवर्क के रूप में चुनना चाहिए।

991

ऐप पॉपअप बनाएं

आप "Apps" पर होवर करके मौजूदा API keys को भी प्राप्त सकते हैं और किसी एक को चुन सकते हैं।

आप "View Key" पर क्लिक कर के Key को देख सकते हैं, साथ ही "Edit App" पर क्लिक कर के विशिष्ट डोमेन्स को whitelist में डाल सकते है तथा कई डेवलपर टूल्स और analytics(एनालिटिक्स) भी देख सकते है।

चरण 1: अपने मेटामास्क वॉलेट को डेवलपमेंट के लिए सेट करें

यदि आपके पास पहले से Goerli एड्रेस वाला मेटामास्क है और उस पर कम से कम 0.1 Goerli ETH(गोएरली ईथर) है, तो चरण 2 पर जाएं।

यदि आपके पास गोएर्ली पता नहीं है, तो मेटामास्क को गोएरली नेटवर्क से कनेक्ट करें, और फिर गोएरली ईथर को पाने के लिए गोएरली फॉसेट का उपयोग करें। स्मार्ट कॉन्ट्रैक्ट को तैनात(deploy) करने और अपने एनएफटी बाज़ार में एनएफटी अपलोड करने के लिए आपको गोएर्ली ईथर की आवश्यकता होगी।

नया नेटवर्क जोड़ते समय सुनिश्चित करें कि आप नीचे दिए गए डिटेल्स जोड़ते हैं:

  1. Network Name(नेटवर्क का नाम): Goerli Test Network(गोएरली टेस्ट नेटवर्क)

  2. RPC base URL(RPC बेस यूआरएल): https://eth-goerli.g.alchemy.com/v2/{अपनी एपीआई key यहाँ डालें}

  3. Chain ID(चेन आईडी): 5

  4. Block Explorer URL(ब्लॉक एक्सप्लोरर यूआरएल): https://goerli.etherscan.io/

  5. Symbol (प्रतीक) (यह वैकल्पिक है): ETH

चरण 2: रिपॉजिटरी(repository) सेट करें

इसे आसान बनाने के लिए, हमने बेस कोड को नीचे GitHub रिपॉजिटरी में अपलोड कर दिया है। इस कोड में फ्रंटएंड पूरी तरह से लिखा हुआ है, लेकिन इसमें स्मार्ट कॉन्ट्रैक्ट या फ्रंटएंड के साथ इंटीग्रेशनस नहीं है।

इस ट्यूटोरियल के लिए उपयोग की जाने वाली गीटहब रिपॉजिटरी

रिपॉजिटरी को क्लोन करने के लिए, अपने कमांड प्रॉम्प्ट में निम्न आदेश/कमांड्स चलाएँ:

git clone https://github.com/alchemyplatform/RTW3-Week7-NFT-Marketplace.git
cd RTW3-Week7-NFT-Marketplace
npm install
npm start

📘

ध्यान दें

उपरोक्त गिटहब रेपो बेस रेपो है जिसके ऊपर आपको बाकी की चीजें बनानी चाहिए।

एक अलग गिटहब रेपो फाइनल NFT मार्केटप्लेस कोड के साथ भी है।

यदि आप ट्यूटोरियल के साथ अनुसरण करते हुए अटक जाते हैं तो इसकी मदत लें।

चरण 3: अपने एनवायरनमेंट वेरिएबल्स और हार्डहैट कॉन्फ़िगरेशन को सेट करें

अपने प्रोजेक्ट के रूट में एक नई .env फ़ाइल बनाएँ, जो RTW3-Week7-NFT-Marketplace फ़ोल्डर के ठीक अंदर है, और निमन्लिखित को जोड़ें:

  • एल्केमी एपीआई यूआरएल जिसे आपने चरण 1 में बनाया था
  • मेटामास्क वॉलेट प्राइवेट key जिसे आप डेवलपमेंट के लिए उपयोग करेंगे

जब आप यह कर लें, तो आपकी .env फ़ाइल इस तरह दिखनी चाहिए:

REACT_APP_ALCHEMY_API_URL="<YOUR_API_URL>"
REACT_APP_PRIVATE_KEY="<YOUR_PRIVATE_KEY>"

यदि पहले से इंस्टॉल्ड नहीं है, तो dotenv को अपने रूट फ़ोल्डर में इंस्टॉल करें

npm install dotenv --save

dotenv आपको .env फ़ाइल में वर्णित एनवायरनमेंट वेरिएबल्स को manage(प्रबंधित) करने में मदत करता है, जिससे आपके प्रोजेक्ट को इन्हें एक्सेस करना आसान हो जाए।

❗️

चेतावनी

किसी प्रोडक्शन ऐप को .env फ़ाइल में सीक्रेट्स के साथ शिप न करें। यह ट्यूटोरियल आपको केवल एक प्रदर्शन के रूप में React Client(रियेक्ट क्लाइंट) के माध्यम से IPFS पर कैसे अपलोड करे उसका तरीका दिखाता है।

जब आप प्रोडक्शन के लिए तैयार हों, तो आपको बैकएंड सेवा का उपयोग करके आईपीएफएस फाइलों को अपलोड करने के लिए अपनी एप्लीकेशन को दोबारा सुधारना(रीफैक्टर करना) चाहिए।

React Environment Variables(रियेक्ट एनवायरनमेंट वेरिएबल्स) पर अधिक संदर्भ(context) के लिए इसे पढ़ें।

अपनी होम डायरेक्टरी में, सुनिश्चित करें कि नीचे दिया गया कोड आपकी hardhat.config.js फ़ाइल में जोड़ा गया है

require("@nomiclabs/hardhat-waffle");
require("@nomiclabs/hardhat-ethers");
const fs = require('fs');
// const infuraId = fs.readFileSync(".infuraid").toString().trim() || "";
require('dotenv').config();

task("accounts", "Prints the list of accounts", async (taskArgs, hre) => {
  const accounts = await hre.ethers.getSigners();

  for (const account of accounts) {
    console.log(account.address);
  }
});

module.exports = {
  defaultNetwork: "hardhat",
  networks: {
    hardhat: {
      chainId: 1337
    },
    goerli: {
      url: process.env.REACT_APP_ALCHEMY_API_URL,
      accounts: [ process.env.REACT_APP_PRIVATE_KEY ]
    }
  },
  solidity: {
    version: "0.8.4",
    settings: {
      optimizer: {
        enabled: true,
        runs: 200
      }
    }
  }
};

📘

टिप्पणी

उपरोक्त हार्डहैट कॉन्फ़िगरेशन में dotenv को स्थापित करने के बाद भी process.env को इस्तेमाल करने में आपको समस्याओं का सामना करना पड़ सकता है। उस स्थिति में, बस goerli URL और प्राइवेट की(private key) को सीधे इस कॉन्फ़िगरेशन में पेस्ट करें। सुनिश्चित करें कि इसे GitHub पर न डाले (या पुश करें)।

चरण 4: IPFS में अपना डेटा अपलोड करने के लिए Piñata का उपयोग करें

यदि आपके पास Piñata(पिनाटा) खाता नहीं है, तो निःशुल्क Piñata खाते के लिए साइन अप करें और अपना ईमेल सत्यापित(verify) करें।

अपनी पिनाटा एपीआई Key बनाएं

अपनी पिनाटा key बनाने के लिए:

  • https://pinata.cloud/keys पर नेविगेट करें
  • सबसे ऊपर "New Key" बटन का सेलेक्ट करें
  • Admin widget को enabled के रूप में सेट करें
  • अपनी Key को नाम दें
2880

इसके बाद आपको अपनी एपीआई जानकारी के साथ एक पॉपअप दिखाया जाएगा। इसे किसी सुरक्षित स्थान पर कॉपी करें।

2000

अब जब Piñata(पिनाटा) key सेट हो गई है, तो इसे अपने प्रोजेक्ट में जोड़ें ताकि आप इसका उपयोग कर सकें।

अपनी एपीआई की और सीक्रेट(API key and secret) जोड़ें ताकि .env फ़ाइल ऐसी दिखाई दे:

REACT_APP_ALCHEMY_API_URL="<आपका_एपीआई_यूआरएल>"
REACT_APP_PRIVATE_KEY="<आपकी_प्राइवेट_KEY>"
REACT_APP_PINATA_KEY="<आपकी_पिनाटा_KEY>"
REACT_APP_PINATA_SECRET="<आपकी_पिनाटा_सीक्रेट>"

चरण 5: आवश्यकताओं को समझें

नीचे एनएफटी मार्केटप्लेस है जिसे आप इस ट्यूटोरियल के अंत तक बना रहे होंगे।

हमने इस मार्केटप्लेस के लिए डॉग्स को चुना है। अपनी पसंद की किसी भी अन्य फ़ोटो पर स्विच करने के लिए स्वतंत्र महसूस करें!

2992

इससे पहले कि हम कोड लिखने में गहराई से उतरें, आइए अलग-अलग पेजों पर चलते हैं ताकि हम आवश्यक फीचर सेट को समझ सकें, फ्रंटएंड और स्मार्ट कॉन्ट्रैक्ट दोनों के नजरिए से।

अपना एनएफटी पेज लिस्ट करें

3024

अपना एनएफटी पेज लिस्ट करें

किसी भी कलाकार या रचनाकार के लिए, यह वह पेज है जहाँ वे मार्केटप्लेस में बिक्री के लिए अपने NFT को लिस्ट कर सकते हैं।

जैसा कि आप देख सकते हैं, यह निम्नलिखित एनएफटी विशेषताओं लेता है:

  • NFT Name(एनएफटी का नाम)
  • Description(विवरण)
  • Price (in Eth)मूल्य (ईथर में)
  • NFT Image(एनएफटी छवि)

एक बार पूरा हो जाने पर, यह कंटेंट(content) NFT मार्केटप्लेस पर अपलोड कर दिया जायेगा।

ऐसा करने के लिए, हमें निम्नलिखित की आवश्यकता है:

स्मार्ट कॉन्ट्रैक्टफ़्रंटएंड
createToken() फंक्शन

Input(इनपुट)
एक IPFS URL जिसमें मेटाडेटा है
एनएफटी के लिए लिस्टिंग मूल्य

यह क्या करता है?
आपके NFT को एक _tokenId असाइन करता है
मार्केटप्लेस कॉन्ट्रैक्ट के अनुरूप डेटा सहेजता है
* एक बार हो जाने के बाद Listing Success(लिस्टिंग सक्सेस) इवेंट का उत्सर्जन(emit) करता है

इसका कार्यान्वयन/इम्प्लीमेंटेशन यहाँ देखें
स्क्रिप्ट जो यह करती है:


एनएफटी के सभी रेलेवेंट डिटेल्स का इनपुट लें
आईपीएफएस में एनएफटी छवि अपलोड करें
IPFS को छवि लिंक के साथ NFT मेटाडेटा अपलोड करें
स्मार्ट कॉन्ट्रैक्ट में createToken() फंक्शन के लिए IPFS लिंक और मूल्य भेजें
* एक सफल अपलोड का उपयोगकर्ता को सूचित करें

आप इम्प्लीमेंटेशन/कार्यान्वयन को src/contracts/SellNFT.js में पा सकते हैं

मार्केटप्लेस होम पेज

2992

एनएफटी मार्केटप्लेस होम पेज का उदाहरण

यह मार्केटप्लेस का होम पेज है जहां सभी एनएफटी लिस्टेड/सूचीबद्ध हैं।

ऐसा करने के लिए, हमें चाहिए:

स्मार्ट कॉन्ट्रैक्टफ़्रंटएंड
getAllNFTs() फंक्शन

Input(इनपुट)
कोई भी नहीं

Output(उत्पादन/आउटपुट)
वर्तमान में बिक्री के लिए मौजूद सभी एनएफटी की सूची उनके मेटाडेटा के साथ

इसका कार्यान्वयन/इम्प्लीमेंटेशन यहाँ देखें
स्मार्ट कॉन्ट्रैक्ट में getAllNFTs() फ़ंक्शन का उपयोग करके बिक्री के लिए उपलब्ध सभी NFT प्राप्त करें
उन्हें ग्रिड प्रारूप/फॉर्मेट में प्रदर्शित करें
* अधिक विवरण देखने के लिए उपयोगकर्ताओं को एक व्यक्तिगत एनएफटी में क्लिक करने दें

आप इम्प्लीमेंटेशन को
src/components/Marketplace.js , src/components/NFTPage.js और src/components/NFTTile.js में पा सकते हैं।

उपयोगकर्ता प्रोफ़ाइल पृष्ठ

2992

प्रोफ़ाइल पृष्ठ

यह NFT मार्केटप्लेस पर एक उपयोगकर्ता की प्रोफ़ाइल है और जो निचे दी गई चीजें प्रदर्शित करता हैं:

  • उपयोगकर्ता का वॉलेट पता(एड्रेस)
  • उपयोगकर्ता के स्वामित्व वाले एनएफटीज (user’s owned NFTs) के बारे में डेटा
  • विवरण(details) के साथ उन सभी एनएफटीज का ग्रिड व्यू

इसे प्राप्त करने के लिए, हमें चाहिए:

स्मार्ट कॉन्ट्रैक्ट/अनुबंधफ़्रंटएंड
getMyNFTs() फ़ंक्शन उपयोगकर्ता द्वारा अतीत में बेचे गए सभी NFT लौटाता है

इसका कार्यान्वयन/इम्प्लीमेंटेशन यहां पाया जा सकता है।
स्मार्ट कॉन्ट्रैक्ट से getMyNFTs() का इस्तेमाल कर के डेटा प्राप्त करें
कुल संख्या और आँकड़े प्राप्त करने के लिए डेटा का विश्लेषण करें

* उपरोक्त प्रारूप(format) में डेटा प्रदर्शित करें

व्यक्तिगत एनएफटी पृष्ठ

2992

एनएफटी मार्केटप्लेस पर एक व्यक्तिगत एनएफटी के लिए लैंडिंग पृष्ठ।

यदि आप मार्केटप्लेस पेज या प्रोफाइल पेज से किसी एनएफटी पर क्लिक करते हैं, तो यह वह पेज है जिसे आगंतुक(विजीटर्स) देखेंगे। यह पृष्ठ प्रदर्शित करता है:

  • एनएफटी का मेटाडेटा
  • एक "Buy this NFT" बटन जो दूसरे उपयोगकर्ता को एनएफटी खरीदने देता है

इसे प्राप्त करने के लिए, हमें चाहिए:

स्मार्ट कॉन्ट्रैक्ट/अनुबंधफ़्रंटएंड
कुछ फ़ंक्शंस:

1. एक tokenURI फ़ंक्शन जो tokenId के लिए tokenURI लौटाता है। फिर हम उस tokenURI के लिए मेटाडेटा प्राप्त करते हैं।

2. एक executeSale() फ़ंक्शन जो उपयोगकर्ता द्वारा "Buy this NFT" बटन पर क्लिक करने पर आवश्यक जांच करने और स्वामित्व स्थानांतरित करने में मदत करता है। इम्प्लीमेंटेशन यहाँ पाया जा सकता है =>
(#executeSale/#निष्पादित बिक्री)
स्क्रिप्ट जो:

tokenURI मेथड का उपयोग करके tokenURI प्राप्त करें

axios का उपयोग करके उस IPFS tokenURI से डेटा प्राप्त करें

डेटा प्रदर्शित करें

इसके अलावा, जब "Buy this NFT" बटन पर क्लिक किया जाता है, तो executeSale() फ़ंक्शन को कॉल करें

अब आपको NFT मार्केटप्लेस बनाने के लिए आवश्यक सुविधाओं की पूरी समझ है।

इसे जारी रखें! 🎉

चरण 6: स्मार्ट कॉन्ट्रैक्ट लिखें

चलिए एक NFT मार्केटप्लेस बनाना शुरू करते हैं! यदि आप भ्रमित हो जाते हैं, तो तैयार स्मार्ट कॉन्ट्रैक्ट देखें

आयात/इम्पोर्ट्स जोड़ें

आपके कॉन्ट्रैक्ट फ़ोल्डर में एक NFTMarketplace.sol फ़ाइल है।

इस फ़ाइल के शीर्ष पर निम्न आयात जोड़ें और एक कंस्ट्रक्टर के साथ एक खाली क्लास जोड़ें:

//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

//जावास्क्रिप्ट कंसोल की तरह ही स्मार्ट कॉन्ट्रैक्ट को डीबग करने के लिए कंसोल फ़ंक्शंस
import "hardhat/console.sol";
//OpenZeppelin का NFT स्टैण्डर्ड/मानक कॉन्ट्रैक्ट। हम अपने कार्यान्वयन(implementation) में इससे फंक्शन्स को एक्सटेंड करेंगे
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract NFTMarketplace is ERC721URIStorage {
    constructor() ERC721("NFTMarketplace", "NFTM") {
        owner = payable(msg.sender);
    }
}

कोड कमैंट्स/टिप्पणियों में समझाया गया है।

ग्लोबल वेरिएबल्स जोड़ें

अपने स्मार्ट कॉन्ट्रैक्ट के शीर्ष पर क्लास डिक्लेरेशन/घोषणा के अंदर नीचे दिए गए ग्लोबल वेरिएबल्स जोड़ें:

using Counters for Counters.Counter;
    //_tokenIds वैरिएबल में हाल ही में मिंट किया गया tokenId है
    Counters.Counter private _tokenIds;
    //मार्केटप्लेस में बिकने वाली items की संख्या पर नज़र रखता है
    Counters.Counter private _itemsSold;
    //owner वह कॉन्ट्रैक्ट एड्रेस है जिसने स्मार्ट कॉन्ट्रैक्ट बनाया है
    address payable owner;
    //NFT को सूचीबद्ध करने के लिए मार्केटप्लेस द्वारा लिया जाने वाला शुल्क
    uint256 listPrice = 0.01 ether;

    //सूचीबद्ध(listed) टोकन के बारे में जानकारी संग्रहीत करने की संरचना(structure)
    struct ListedToken {
        uint256 tokenId;
        address payable owner;
        address payable seller;
        uint256 price;
        bool currentlyListed;
    }

    //एक टोकन सफलतापूर्वक सूचीबद्ध(list) होने पर उत्सर्जित(emit) होने वाला इवेंट(event)
    event TokenListedSuccess (
        uint256 indexed tokenId,
        address owner,
        address seller,
        uint256 price,
        bool currentlyListed
    );

    //यह मैपिंग tokenId को token info(टोकन जानकारी) से मैप करती है और टोकन आईडी के बारे में विवरण पुनःप्राप्त करते समय सहायक होती है
    mapping(uint256 => ListedToken) private idToListedToken;
  • _tokenIds: यह नवीनतम/latest टोकन आईडी है जो इस स्मार्ट कॉन्ट्रैक्ट के साथ मिन्टेड एनएफटी से कोर्रेसपोंड/correspond करती है। tokenIDs, tokenURI से मैप की गयी है जो एक URL है जिसमें संबंधित NFT का मेटाडेटा है
  • _itemsSold: मार्केटप्लेस पर बेचे गए आइटम की संख्या की गणना है
  • owner: यह स्मार्ट कॉन्ट्रैक्ट का ओनर है। एकमात्र पता(address) जो निकासी अनुरोध(withdrawal request) जारी कर सकता है।
  • listPrice: मूल्य (ETH में) जो किसी भी उपयोगकर्ता को मार्केटप्लेस(बाज़ार) में अपने NFT सूचीबद्ध करने के लिए भुगतान करने की आवश्यकता होती है
  • ListedToken: एक सॉलिडिटी स्ट्रक्ट/struct (जावास्क्रिप्ट ऑब्जेक्ट के समान) जो यह निर्धारित करता है की किसी NFT का डाटा किस फॉर्मेट में स्टोर होगा
  • TokenListedSuccess: एक टोकन सफलतापूर्वक सूचीबद्ध होने पर उत्सर्जित(emit) होने वाला इवेंट(event)
  • idToListedToken: यह मौजूदा सभी tokenId’s(टोकन आईडीज) और उनसे संबंधित NFT टोकन की मैपिंग है

createToken और createListedToken

यह फ़ंक्शन tokenURI(मेटाडेटा के साथ यूआरएल) को चेन पर(ऑन-चेन) वास्तविक एनएफटी में बदल देता है, जिसके विवरण(details) स्मार्ट कॉन्ट्रैक्ट में संग्रहीत होते हैं। यह आपके एनएफटी पृष्ठ की सूची के लिए उपयोगी है।

ग्लोबल वेरिएबल डिक्लेरेशन के निचे अपने कॉन्ट्रैक्ट क्लास के अंदर नीचे दिए गए फ़ंक्शंस को जोड़ें:

//जब पहली बार एक टोकन बनाया जाता है, वह यहाँ सूचीबद्ध(list) होता है
    function createToken(string memory tokenURI, uint256 price) public payable returns (uint) {
        //टोकनआईड काउंटर बढ़ाएँ, जो मिंट किए गए एनएफटी की संख्या पर नज़र रखता है
        _tokenIds.increment();
        uint256 newTokenId = _tokenIds.current();

        //tokenId, newTokenId के साथ NFT को उस पते पर मिंट करें जिसने createToken को कॉल किया
        _safeMint(msg.sender, newTokenId);

        //tokenId को tokenURI के साथ मैप करें (जो एनएफटी मेटाडेटा के साथ एक आईपीएफएस यूआरएल है)
        _setTokenURI(newTokenId, tokenURI);

        //ग्लोबल वेरिएबल्स को अपडेट करने और किसी ईवेंट को उत्सर्जित करने के लिए हेल्पर फ़ंक्शन
        createListedToken(newTokenId, price);

        return newTokenId;
    }

    function createListedToken(uint256 tokenId, uint256 price) private {
        //सुनिश्चित करें कि sender(प्रेषक) ने लिस्टिंग के लिए भुगतान करने के लिए पर्याप्त ETH भेजा है
        require(msg.value == listPrice, "Hopefully sending the correct price");
        //बस विवेक जांच
        require(price > 0, "Make sure the price isn't negative");

        //tokenId's की मैपिंग को टोकन विवरण/डिटेल्स में अपडेट करें, पुनर्प्राप्ति कार्यों के लिए उपयोगी
        idToListedToken[tokenId] = ListedToken(
            tokenId,
            payable(address(this)),
            payable(msg.sender),
            price,
            true
        );

        _transfer(msg.sender, address(this), tokenId);
        //सफल ट्रांसफर/हस्तांतरण के लिए ईवेंट का उत्सर्जन करें। फ्रंटएंड इस मैसेज को पार्स करता है और अंतिम उपयोगकर्ता को अपडेट करता है
        emit TokenListedSuccess(
            tokenId,
            address(this),
            msg.sender,
            price,
            true
        );
    }

टिप्पणियों में कोड की प्रत्येक पंक्ति की प्रासंगिकता(relevance) का उल्लेख किया गया है। इसे जानने के लिए 2 मिनट का समय लें।

getAllNFTs

यह फ़ंक्शन मार्केटप्लेस में सभी "सक्रिय"(active) एनएफटीज (वर्तमान में बिक्री के लिए उपलब्ध) लौटाता है। यह मार्केटप्लेस होम पेज के लिए उपयोगी है।

createListedToken फ़ंक्शन के ठीक नीचे अपने कॉन्ट्रैक्ट क्लास में निम्न फ़ंक्शन जोड़ें:

//यह वर्तमान में मार्केटप्लेस पर बेचे जाने के लिए सूचीबद्ध सभी NFT लौटाएगा
    function getAllNFTs() public view returns (ListedToken[] memory) {
        uint nftCount = _tokenIds.current();
        ListedToken[] memory tokens = new ListedToken[](nftCount);
        uint currentIndex = 0;

        //फिलहाल currentlyListed सभी के लिए true है, अगर यह भविष्य में false हो जाता है
				//तो हम currentlyListed == false को यहां से फ़िल्टर कर देंगे
        for(uint i=0;i<nftCount;i++)
        {
            uint currentId = i + 1;
            ListedToken storage currentItem = idToListedToken[currentId];
            tokens[currentIndex] = currentItem;
            currentIndex += 1;
        }
        //'tokens' ऐरे के अंदर मार्केटप्लेस में सभी एनएफटीज की सूची है
        return tokens;
    }

टिप्पणियों में कोड की प्रत्येक पंक्ति की प्रासंगिकता(relevance) का उल्लेख किया गया है।

getMyNFTs
यह फ़ंक्शन मार्केटप्लेस में सभी "सक्रिय"(active) NFTs (वर्तमान में बिक्री पर) लौटाता है, जो कि वर्तमान लॉगड इन उपयोगकर्ता(user) के पास है। यह प्रोफाइल पेज के लिए उपयोगी है।

getAllNFTs फ़ंक्शन के ठीक नीचे अपने कॉन्ट्रैक्ट क्लास(class) में निम्न फ़ंक्शन जोड़ें:

//उन सभी NFTs को लौटाता है जिनका वर्तमान उपयोगकर्ता owner(स्वामी) या seller(विक्रेता) है
    function getMyNFTs() public view returns (ListedToken[] memory) {
        uint totalItemCount = _tokenIds.current();
        uint itemCount = 0;
        uint currentIndex = 0;
        
        //उपयोगकर्ता के लिए एक array(सरणी)बनाने से पहले जो उपयोगकर्ता से संबंधित NFTs हैं उन सभी की गिनती करना महत्वपूर्ण है 
        for(uint i=0; i < totalItemCount; i++)
        {
            if(idToListedToken[i+1].owner == msg.sender || idToListedToken[i+1].seller == msg.sender){
                itemCount += 1;
            }
        }

        //एक बार उपयोगकर्ता से संबंधित एनएफटीज की गिनती होने के बाद, एक सरणी(array) बनाएं और उसमें सभी NFTs स्टोर करें
        ListedToken[] memory items = new ListedToken[](itemCount);
        for(uint i=0; i < totalItemCount; i++) {
            if(idToListedToken[i+1].owner == msg.sender || idToListedToken[i+1].seller == msg.sender) {
                uint currentId = i+1;
                ListedToken storage currentItem = idToListedToken[currentId];
                items[currentIndex] = currentItem;
                currentIndex += 1;
            }
        }
        return items;
    }

टिप्पणियों में कोड की प्रत्येक पंक्ति की प्रासंगिकता(relevance) का उल्लेख किया गया है।

executeSale
जब कोई उपयोगकर्ता प्रोफाइल पेज पर "Buy this NFT" पर क्लिक करता है, तो executeSale फ़ंक्शन चालू(trigger) हो जाता है।

यदि उपयोगकर्ता ने एनएफटी की कीमत के बराबर पर्याप्त ETH(ईथर) का भुगतान किया है, तो एनएफटी को नए पते(address) पर स्थानांतरित कर दिया जाता है और बिक्री की आय विक्रेता को भेज दी जाती है।

नीचे दिए गए फ़ंक्शन को अपने स्मार्ट कॉन्ट्रैक्ट में जोड़ें:

function executeSale(uint256 tokenId) public payable {
        uint price = idToListedToken[tokenId].price;
        address seller = idToListedToken[tokenId].seller;
        require(msg.value == price, "Please submit the asking price in order to complete the purchase");

        //टोकन का विवरण(details) अपडेट करें
        idToListedToken[tokenId].currentlyListed = true;
        idToListedToken[tokenId].seller = payable(msg.sender);
        _itemsSold.increment();

        //वास्तव में टोकन को नए owner(स्वामी) को स्थानांतरित करें
        _transfer(address(this), msg.sender, tokenId);
        //मार्केटप्लेस को एनएफटी बेचने की अनुमती दे 
        approve(address(this), tokenId);

        //लिस्टिंग शुल्क को मार्केटप्लेस क्रिएटर को ट्रांसफर करें
        payable(owner).transfer(listPrice);
        //बिक्री से आय को NFT के विक्रेता को स्थानांतरित करें
        payable(seller).transfer(msg.value);
    }

अन्य सहायक कार्य
नीचे अन्य सहायक कार्य हैं, जो परीक्षण(testing) के लिए आपके स्मार्ट कॉन्ट्रैक्टस में होना अच्छा है और यदि आप अधिक कार्यात्मकताओं का विस्तार करने का निर्णय लेते हैं तो यह सहायक होगा।

बेझिझक इन्हें अपनी class(क्लास) में कहीं भी जोड़ें:

function updateListPrice(uint256 _listPrice) public payable {
        require(owner == msg.sender, "Only owner can update listing price");
        listPrice = _listPrice;
    }

    function getListPrice() public view returns (uint256) {
        return listPrice;
    }

    function getLatestIdToListedToken() public view returns (ListedToken memory) {
        uint256 currentTokenId = _tokenIds.current();
        return idToListedToken[currentTokenId];
    }

    function getListedTokenForId(uint256 tokenId) public view returns (ListedToken memory) {
        return idToListedToken[tokenId];
    }

    function getCurrentToken() public view returns (uint256) {
        return _tokenIds.current();
    }

उपरोक्त सभी को करने के बाद, आपका स्मार्ट कॉन्ट्रैक्ट ऐसा दिखना चाहिए:

//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

import "hardhat/console.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract NFTMarketplace is ERC721URIStorage {

    using Counters for Counters.Counter;
    //_tokenIds वैरिएबल में हाल ही में मिंट किया गया tokenId है
    Counters.Counter private _tokenIds;
    //मार्केटप्लेस में बिकने वाली वस्तुओं की संख्या पर नज़र रखता है
    Counters.Counter private _itemsSold;
    //owner वह कॉन्ट्रैक्ट एड्रेस है जिसने स्मार्ट कॉन्ट्रैक्ट बनाया है
    address payable owner;
    //NFT को सूचीबद्ध करने के लिए मार्केटप्लेस द्वारा लिया जाने वाला शुल्क
    uint256 listPrice = 0.01 ether;

    //सूचीबद्ध(listed) टोकन के बारे में जानकारी संग्रहीत करने की संरचना
    struct ListedToken {
        uint256 tokenId;
        address payable owner;
        address payable seller;
        uint256 price;
        bool currentlyListed;
    }

    //एक टोकन सफलतापूर्वक सूचीबद्ध(list) होने पर उत्सर्जित होने वाला इवेंट(event)
    event TokenListedSuccess (
        uint256 indexed tokenId,
        address owner,
        address seller,
        uint256 price,
        bool currentlyListed
    );

    //यह मैपिंग tokenId को टोकन जानकारी(token info) से मैप करती है और टोकन आईडी के बारे में विवरण पुनर्प्राप्त करते समय सहायक होती है
    mapping(uint256 => ListedToken) private idToListedToken;

    constructor() ERC721("NFTMarketplace", "NFTM") {
        owner = payable(msg.sender);
    }

    function updateListPrice(uint256 _listPrice) public payable {
        require(owner == msg.sender, "Only owner can update listing price");
        listPrice = _listPrice;
    }

    function getListPrice() public view returns (uint256) {
        return listPrice;
    }

    function getLatestIdToListedToken() public view returns (ListedToken memory) {
        uint256 currentTokenId = _tokenIds.current();
        return idToListedToken[currentTokenId];
    }

    function getListedTokenForId(uint256 tokenId) public view returns (ListedToken memory) {
        return idToListedToken[tokenId];
    }

    function getCurrentToken() public view returns (uint256) {
        return _tokenIds.current();
    }

    //जब पहली बार एक टोकन बनाया जाता है, वह यहाँ सूचीबद्ध(list) होता है
    function createToken(string memory tokenURI, uint256 price) public payable returns (uint) {
        //टोकनआईड काउंटर बढ़ाएँ, जो मिंट किए गए एनएफटी की संख्या पर नज़र रखता है
        _tokenIds.increment();
        uint256 newTokenId = _tokenIds.current();

        //tokenId, newTokenId के साथ NFT को उस पते पर मिंट करें जिसने createToken को कॉल किया
        _safeMint(msg.sender, newTokenId);

        //tokenId को tokenURI के साथ मैप करें (जो एनएफटी मेटाडेटा के साथ एक आईपीएफएस यूआरएल है)
        _setTokenURI(newTokenId, tokenURI);

        //ग्लोबल वेरिएबल्स को अपडेट करने और किसी ईवेंट को उत्सर्जित करने के लिए हेल्पर फ़ंक्शन
        createListedToken(newTokenId, price);

        return newTokenId;
    }

    function createListedToken(uint256 tokenId, uint256 price) private {
        //सुनिश्चित करें कि sender(प्रेषक) ने लिस्टिंग के लिए भुगतान करने के लिए पर्याप्त ETH भेजा है
        require(msg.value == listPrice, "Hopefully sending the correct price");
        //बस विवेक जांच
        require(price > 0, "Make sure the price isn't negative");

        //tokenId's की मैपिंग को टोकन विवरण/डिटेल्स में अपडेट करें, पुनर्प्राप्ति कार्यों के लिए उपयोगी
        idToListedToken[tokenId] = ListedToken(
            tokenId,
            payable(address(this)),
            payable(msg.sender),
            price,
            true
        );

        _transfer(msg.sender, address(this), tokenId);
        //सफल ट्रांसफर/हस्तांतरण के लिए ईवेंट का उत्सर्जन करें। फ्रंटएंड इस मैसेज को पार्स करता है और अंतिम उपयोगकर्ता को अपडेट करता है
        emit TokenListedSuccess(
            tokenId,
            address(this),
            msg.sender,
            price,
            true
        );
    }
    
   //यह वर्तमान में मार्केटप्लेस पर बेचे जाने के लिए सूचीबद्ध सभी NFT लौटाएगा
    function getAllNFTs() public view returns (ListedToken[] memory) {
        uint nftCount = _tokenIds.current();
        ListedToken[] memory tokens = new ListedToken[](nftCount);
        uint currentIndex = 0;

        //फिलहाल currentlyListed सभी के लिए true है, अगर यह भविष्य में false हो जाता है
				//तो हम currentlyListed == false को यहां से फ़िल्टर कर देंगे
        for(uint i=0;i<nftCount;i++)
        {
            uint currentId = i + 1;
            ListedToken storage currentItem = idToListedToken[currentId];
            tokens[currentIndex] = currentItem;
            currentIndex += 1;
        }
        //'tokens' ऐरे के अंदर मार्केटप्लेस में सभी एनएफटीज की सूची है
        return tokens;
    }
    
    //उन सभी NFTs को लौटाता है जिनका वर्तमान उपयोगकर्ता स्वामी(owner) या विक्रेता(seller) है
    function getMyNFTs() public view returns (ListedToken[] memory) {
        uint totalItemCount = _tokenIds.current();
        uint itemCount = 0;
        uint currentIndex = 0;
        
        //उपयोगकर्ता के लिए एक array(सरणी)बनाने से पहले जो उपयोगकर्ता से संबंधित NFTs हैं उन सभी की गिनती करना महत्वपूर्ण है 
        for(uint i=0; i < totalItemCount; i++)
        {
            if(idToListedToken[i+1].owner == msg.sender || idToListedToken[i+1].seller == msg.sender){
                itemCount += 1;
            }
        }

        //एक बार आपके पास उपयोगकर्ता से संबंधित एनएफटी की गिनती होने के बाद, एक सरणी(array) बनाएं और उसमें सभी NFTs स्टोर करें
        ListedToken[] memory items = new ListedToken[](itemCount);
        for(uint i=0; i < totalItemCount; i++) {
            if(idToListedToken[i+1].owner == msg.sender || idToListedToken[i+1].seller == msg.sender) {
                uint currentId = i+1;
                ListedToken storage currentItem = idToListedToken[currentId];
                items[currentIndex] = currentItem;
                currentIndex += 1;
            }
        }
        return items;
    }

    function executeSale(uint256 tokenId) public payable {
        uint price = idToListedToken[tokenId].price;
        address seller = idToListedToken[tokenId].seller;
        require(msg.value == price, "Please submit the asking price in order to complete the purchase");

        //टोकन का विवरण(details) अपडेट करें
        idToListedToken[tokenId].currentlyListed = true;
        idToListedToken[tokenId].seller = payable(msg.sender);
        _itemsSold.increment();

        //वास्तव में टोकन को नए स्वामी को स्थानांतरित करें
        _transfer(address(this), msg.sender, tokenId);
        //मार्केटप्लेस को एनएफटी बेचने की अनुमती दे 
        approve(address(this), tokenId);

        //लिस्टिंग शुल्क को मार्केटप्लेस क्रिएटर को ट्रांसफर करें
        payable(owner).transfer(listPrice);
        //बिक्री से आय को NFT के विक्रेता को स्थानांतरित करें
        payable(seller).transfer(msg.value);
    }

    //हम भविष्य में एक पुनर्विक्रय(resell) टोकन फंक्शन जोड़ सकते हैं
    //उस स्थिति में, टोकन डिफ़ॉल्ट रूप से सूचीबद्ध(list) नहीं होंगे, लेकिन उपयोगकर्ता वास्तव में टोकन सूचीबद्ध करने के लिए अनुरोध भेज सकते हैं
    //वर्तमान में एनएफटी डिफ़ॉल्ट रूप से सूचीबद्ध(listed) हैं
}

चरण 7: गोएर्ली पर स्मार्ट कॉन्ट्रैक्ट तैनात करें

आपने उस विशाल स्मार्ट कॉन्ट्रैक्ट को कोड किया! आप कमाल हो! 💖

अब हमें कॉन्ट्रैक्ट को तैनात(deploy) करने की जरूरत है। एल्केमी गोएर्ली टेस्टनेट को रेकेमेंड
(की सिफारिश) करता है क्योंकि आने वाले इथिरियम मर्ज(Ethereum Merge) के साथ रिंकीबी को पदावनत(depreciate) कर दिया जाएगा।

scripts/ फ़ोल्डर के अंदर एक स्क्रिप्ट है जिसका नाम Deploy.js है। उस फाइल में, निचे दिए गए कोड को डाले:

const { ethers } = require("hardhat");
const hre = require("hardhat");
const fs = require("fs");

async function main() {
  //signer(हस्ताक्षरकर्ता) प्राप्त करें जिसका उपयोग हम परिनियोजित(deploy) करने के लिए करेंगे
  const [deployer] = await ethers.getSigners();
  
  //NFTMarketplace स्मार्ट कॉन्ट्रैक्ट ऑब्जेक्ट प्राप्त करें और इसे तैनात(deploy) करें
  const Marketplace = await hre.ethers.getContractFactory("NFTMarketplace");
  const marketplace = await Marketplace.deploy();

  await marketplace.deployed();
  
  //तैनाती(deployment) के दौरान पता(Address) और एबीआई(ABI) को स्टोर कर लें, क्योंकि यह बाद में स्मार्ट कॉन्ट्रैक्ट के साथ बातचीत(interact)करने के लिए चाहिए होंगे
  const data = {
    address: marketplace.address,
    abi: JSON.parse(marketplace.interface.format('json'))
  }

  //यह Marketplace.json को ABI और Address(एड्रेस)लिखता है
  //यह डेटा फिर स्मार्ट कॉन्ट्रैक्ट से जुड़ने के लिए फ्रंटएंड फाइलों द्वारा उपयोग किया जाता है
  fs.writeFileSync('./src/Marketplace.json', JSON.stringify(data))
}

main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

सेव करें।

फिर अपना कमांड प्रॉम्प्ट खोलें और नीचे दिए गए आदेश को निष्पादित(execute) करें:

npx hardhat run --network goerli scripts/deploy.js

❗️

सुनिश्चित करें कि आपने स्मार्ट कॉन्ट्रैक्ट को परिनियोजित(deploy) करने में सक्षम होने के लिए चरण 3 के अनुसार अपना hardhat.config.js अपडेट किया है।

यदि आपको कोई त्रुटि या चेतावनी(errors or warnings) नहीं दिखाई देती है, तो आपका स्मार्ट कॉन्ट्रैक्ट सफलतापूर्वक डिप्लॉय हो गया था!

आपको src/Marketplace.json में वह पता(address) और स्मार्ट कॉन्ट्रैक्ट का ABI देखने में सक्षम होना चाहिए जिस पर इसे तैनात किया गया है।

चरण 8: एनएफटी मेटाडेटा को पिनाटा में अपलोड करने के लिए फ़ंक्शंस जोड़ें

अपने होम डायरेक्टरी में, pinata.js नाम की खाली फ़ाइल में यह कोड जोड़ें:

//require('dotenv').config();
const key = process.env.REACT_APP_PINATA_KEY;
const secret = process.env.REACT_APP_PINATA_SECRET;

const axios = require('axios');
const FormData = require('form-data');

export const uploadJSONToIPFS = async(JSONBody) => {
    const url = `https://api.pinata.cloud/pinning/pinJSONToIPFS`;
    //Pinata ⬇️ के लिए Axios POST request बनाना
    return axios 
        .post(url, JSONBody, {
            headers: {
                pinata_api_key: key,
                pinata_secret_api_key: secret,
            }
        })
        .then(function (response) {
           return {
               success: true,
               pinataURL: "https://gateway.pinata.cloud/ipfs/" + response.data.IpfsHash
           };
        })
        .catch(function (error) {
            console.log(error)
            return {
                success: false,
                message: error.message,
            }

    });
};

export const uploadFileToIPFS = async(file) => {
    const url = `https://api.pinata.cloud/pinning/pinFileToIPFS`;
    //Pinata ⬇️ के लिए Axios POST request बनाना
    
    let data = new FormData();
    data.append('file', file);

    const metadata = JSON.stringify({
        name: 'testname',
        keyvalues: {
            exampleKey: 'exampleValue'
        }
    });
    data.append('pinataMetadata', metadata);

    //pinataOptions वैकल्पिक(optional) हैं
    const pinataOptions = JSON.stringify({
        cidVersion: 0,
        customPinPolicy: {
            regions: [
                {
                    id: 'FRA1',
                    desiredReplicationCount: 1
                },
                {
                    id: 'NYC1',
                    desiredReplicationCount: 2
                }
            ]
        }
    });
    data.append('pinataOptions', pinataOptions);

    return axios 
        .post(url, data, {
            maxBodyLength: 'Infinity',
            headers: {
                'Content-Type': `multipart/form-data; boundary=${data._boundary}`,
                pinata_api_key: key,
                pinata_secret_api_key: secret,
            }
        })
        .then(function (response) {
            console.log("image uploaded", response.data.IpfsHash)
            return {
               success: true,
               pinataURL: "https://gateway.pinata.cloud/ipfs/" + response.data.IpfsHash
           };
        })
        .catch(function (error) {
            console.log(error)
            return {
                success: false,
                message: error.message,
            }

    });
};

दो फ़ंक्शंस हैं:

  1. uploadFileToIPFS()

यह फ़ंक्शन NFT छवि(image) फ़ाइल को IPFS पर अपलोड करता है और फिर एक IPFS URL देता है जिसे छवि प्राप्त करने के लिए क्वेरी किया जा सकती है।

  1. uploadJSONToIPFS(JSON)

यह फ़ंक्शन संपूर्ण JSON को इनपुट के रूप में अपलोड करने के लिए लेता और इसे IPFS पर अपलोड करता है। फ़ंक्शन द्वारा लौटाई गई वैल्यू एक IPFS URI है जिसे मेटाडेटा प्राप्त करने के लिए क्वेरी किया जा सकता है। जब हम NFT मेटाडेटा जानकारी को बाद में पुनःप्राप्त करना चाहते हैं तो यह URI अत्यधिक सहायक होता है।

चरण 9: फ्रंटएण्ड को स्मार्ट कॉन्ट्रैक्ट के साथ एकीकृत(integrate) करें

प्लेटफ़ॉर्म को निर्बाध(seamlessly) रूप से काम करने के लिए, स्मार्ट कॉन्ट्रैक्ट से फंक्शन्स के साथ फ्रंटएण्ड को एकीकृत(integrate) करें।

📘

फ्रंटएंड के बारे में एक नोट

इसके लिए फ्रंटएंड बनाना एक बहुत बड़ा काम है। जबकि हम अपने डेवेलपर्स को इस ट्यूटोरियल में ही यह सब सिखाना पसंद करेंगे, लेकिन हम आपको अभिभूत(overwhelm) नहीं करना चाहते हैं।

इसलिए, GitHub रिपॉजिटरी में हर अलग पेज के लिए अलग-अलग कंपोनेंट्स के साथ सभी फ्रंटएंड कोड हैं।

उदाहरण के लिए src/components/SellNFT.js जैसे प्रत्येक फ्रंटएंड कंपोनेंट,

  1. में एक ऐसा फंक्शन है जो प्रदाता, हस्ताक्षरकर्ता और कॉन्ट्रैक्ट ऑब्जेक्ट(provider, signer and a contract object) बनाता है
  2. स्मार्ट कॉन्ट्रैक्ट से प्रासंगिक डेटा प्राप्त करता है
  3. Axios के माध्यम से IPFS से प्रासंगिक(relevant) डेटा प्राप्त करता है
  4. में एक रिटर्न स्टेटमेंट है जहां यह पृष्ठ के लिए JSX/HTML लौटाता है

जबकि हम इस ट्यूटोरियल में 4 के बारे में बात नहीं कर रहे हैं, हम अभी भी आइटम 1, 2 और 3 को कवर करेंगे। हम आइटम 4 पर एक भावी ट्यूटोरियल जारी करेंगे और इस पेज को अपडेटेड रखेंगे।

src/components/SellNFT.js
सबसे महत्वपूर्ण एकीकरण src/components/SellNFT.js में होगा जहां हम 3 चरण(steps) करते हैं:

  1. छवि(इमेज) को IPFS में अपलोड करें
  2. छवि के साथ मेटाडेटा को IPFS में अपलोड करें
  3. मेटाडेटा tokenURI और मूल्य(प्राइस) को स्मार्ट कॉन्ट्रैक्ट पर भेजें

नीचे दिए गए कोड को अपने src/components/SellNFT.js फाइल में सबसे ऊपर स्टेट वेरिएबल डिक्लेरेशन के ठीक बाद जोड़ें:

//यह फ़ंक्शन NFT इमेज को IPFS में अपलोड करता है
    async function OnChangeFile(e) {
        var file = e.target.files[0];
        //फ़ाइल एक्सटेंशन के लिए जाँच करें
        try {
            //फ़ाइल को IPFS में अपलोड करें
            const response = await uploadFileToIPFS(file);
            if(response.success === true) {
                console.log("Uploaded image to Pinata: ", response.pinataURL)
                setFileURL(response.pinataURL);
            }
        }
        catch(e) {
            console.log("Error during file upload", e);
        }
    }

    //यह फ़ंक्शन मेटाडेटा को IPFS पर अपलोड करता है
    async function uploadMetadataToIPFS() {
        const {name, description, price} = formParams;
        //सुनिश्चित करें कि कोई भी फ़ील्ड खाली नहीं है
        if( !name || !description || !price || !fileURL)
            return;

        const nftJSON = {
            name, description, price, image: fileURL
        }

        try {
            //मेटाडेटा JSON को IPFS पर अपलोड करें
            const response = await uploadJSONToIPFS(nftJSON);
            if(response.success === true){
                console.log("Uploaded JSON to Pinata: ", response)
                return response.pinataURL;
            }
        }
        catch(e) {
            console.log("error uploading JSON metadata:", e)
        }
    }

    async function listNFT(e) {
        e.preventDefault();

        //IPFS में डेटा अपलोड करें
        try {
            const metadataURL = await uploadMetadataToIPFS();
            //आपके हार्डहैट नेटवर्क को मेटामास्क में जोड़ने के बाद, इस कोड को प्रोवाइडर्स एंड साइनर्स(providers and signers) मिल जाएंगे
            const provider = new ethers.providers.Web3Provider(window.ethereum);
            const signer = provider.getSigner();
            updateMessage("Please wait.. uploading (upto 5 mins)")

            //डिप्लोइड कॉन्ट्रैक्ट का इंस्टैंस खीचें
            let contract = new ethers.Contract(Marketplace.address, Marketplace.abi, signer)

            //NFT रिक्वेस्ट बनाने के लिए भेजे जाने वाले पैरामीटर्स मेसेज करे          
            const price = ethers.utils.parseUnits(formParams.price, 'ether')
            let listingPrice = await contract.getListPrice()
            listingPrice = listingPrice.toString()

            //वास्तव में एनएफटी बनाएं
            let transaction = await contract.createToken(metadataURL, price, { value: listingPrice })
            await transaction.wait()

            alert("Successfully listed your NFT!");
            updateMessage("");
            updateFormParams({ name: '', description: '', price: ''});
            window.location.replace("/")
        }
        catch(e) {
            alert( "Upload error"+e )
        }
    }

src/components/Marketplace.js
यहां हमें सभी एनएफटी को स्मार्ट कॉन्ट्रैक्ट से खीचने की आवशयकता है।

शीर्ष पर और रिटर्न(return) से पहले state variable declarations(स्टेट वेरिएबल डेक्लरेशंस) के ठीक बाद इस कोड को अपने फ़ाइल में जोड़ें:

const [dataFetched, updateFetched] = useState(false);

async function getAllNFTs() {
    const ethers = require("ethers");
    //आपके हार्डहैट नेटवर्क को मेटामास्क में जोड़ने के बाद, इस कोड को प्रोवाइडर्स एंड साइनर्स(providers and signers) मिल जाएंगे
    const provider = new ethers.providers.Web3Provider(window.ethereum);
    const signer = provider.getSigner();
    //डिप्लोयड कॉन्ट्रैक्ट इंस्टैंस(instance)खीचें
    let contract = new ethers.Contract(MarketplaceJSON.address, MarketplaceJSON.abi, signer)
    //एक एनएफटी टोकन बनाएं
    let transaction = await contract.getAllNFTs()

    //कॉन्ट्रैक्ट से प्रत्येक NFT के सभी विवरण(details) प्राप्त करें और प्रदर्शित(display) करें 
    const items = await Promise.all(transaction.map(async i => {
        const tokenURI = await contract.tokenURI(i.tokenId);
        let meta = await axios.get(tokenURI);
        meta = meta.data;

        let price = ethers.utils.formatUnits(i.price.toString(), 'ether');
        let item = {
            price,
            tokenId: i.tokenId.toNumber(),
            seller: i.seller,
            owner: i.owner,
            image: meta.image,
            name: meta.name,
            description: meta.description,
        }
        return item;
    }))

    updateFetched(true);
    updateData(items);
}

if(!dataFetched)
    getAllNFTs();

src/components/Profile.js

नीचे दिए गए कोड को जोड़ें जो लॉगड़ इन उपयोगकर्ता(logged in user) द्वारा ओन्ड सभी एनएफटी को खींचता है:

const [dataFetched, updateFetched] = useState(false);

    async function getNFTData(tokenId) {
        const ethers = require("ethers");
        let sumPrice = 0;

        //आपके हार्डहैट नेटवर्क को मेटामास्क में जोड़ने के बाद, इस कोड को प्रोवाइडर्स एंड साइनर्स(providers and signers) मिल जाएंगे
        const provider = new ethers.providers.Web3Provider(window.ethereum);
        const signer = provider.getSigner();
        const addr = await signer.getAddress();

        //डिप्लोयड कॉन्ट्रैक्ट इंस्टैंस(instance)खीचें
        let contract = new ethers.Contract(MarketplaceJSON.address, MarketplaceJSON.abi, signer)

        //एक एनएफटी टोकन बनाएं
        let transaction = await contract.getMyNFTs()

        /*
        * नीचे दिया गया फ़ंक्शन tokenURI से मेटाडेटा और डेटा जो getMyNFTs() कॉन्ट्रैक्ट फ़ंक्शन द्वारा लौटाया गया है उसे लेता है 
				* और इनफार्मेशन का एक ऑब्जेक्ट बनाता है जिसे प्रदर्शित किया जाना है
        */
        
        const items = await Promise.all(transaction.map(async i => {
            const tokenURI = await contract.tokenURI(i.tokenId);
            let meta = await axios.get(tokenURI);
            meta = meta.data;

            let price = ethers.utils.formatUnits(i.price.toString(), 'ether');
            let item = {
                price,
                tokenId: i.tokenId.toNumber(),
                seller: i.seller,
                owner: i.owner,
                image: meta.image,
                name: meta.name,
                description: meta.description,
            }
            sumPrice += Number(price);
            return item;
        }))

        updateData(items);
        updateFetched(true);
        updateAddress(addr);
        updateTotalPrice(sumPrice.toPrecision(3));
    }

    const params = useParams();
    const tokenId = params.tokenId;
    if(!dataFetched)
        getNFTData(tokenId);

src/components/NFTPage.js

यह प्रत्येक एनएफटी के लिए पृष्ठ है, जो दो कार्य करता है:

  1. किसी भी एनएफटी के सभी डेटा प्रदर्शित करें
  2. किसी भी उपयोगकर्ता को "Buy this NFT" बटन से खरीदने दें

तो नीचे दिए गए दो फ़ंक्शंस को अपने कोड में डाले:

async function getNFTData(tokenId) {
    const ethers = require("ethers");
    //आपके हार्डहैट नेटवर्क को मेटामास्क में जोड़ने के बाद, इस कोड को प्रोवाइडर्स एंड साइनर्स(providers and signers) मिल जाएंगे
    const provider = new ethers.providers.Web3Provider(window.ethereum);
    const signer = provider.getSigner();
    //डिप्लोयड कॉन्ट्रैक्ट इंस्टैंस(instance)खीचें
    let contract = new ethers.Contract(MarketplaceJSON.address, MarketplaceJSON.abi, signer)
    //एक एनएफटी टोकन बनाएं
    const tokenURI = await contract.tokenURI(tokenId);
    const listedToken = await contract.getListedTokenForId(tokenId);
    let meta = await axios.get(tokenURI);
    meta = meta.data;
    console.log(listedToken);

    let item = {
        price: meta.price,
        tokenId: tokenId,
        seller: listedToken.seller,
        owner: listedToken.owner,
        image: meta.image,
        name: meta.name,
        description: meta.description,
    }
    console.log(item);
    updateData(item);
}

async function buyNFT(tokenId) {
    try {
        const ethers = require("ethers");
        //आपके हार्डहैट नेटवर्क को मेटामास्क में जोड़ने के बाद, इस कोड को प्रोवाइडर्स एंड साइनर्स(providers and signers) मिल जाएंगे
        const provider = new ethers.providers.Web3Provider(window.ethereum);
        const signer = provider.getSigner();
         //डिप्लोयड कॉन्ट्रैक्ट इंस्टैंस(instance)खीचें
        let contract = new ethers.Contract(MarketplaceJSON.address, MarketplaceJSON.abi, signer);
        const salePrice = ethers.utils.parseUnits(data.price, 'ether')
        let transaction = await contract.executeSale(tokenId, {value:salePrice});
        await transaction.wait();

        alert('You successfully bought the NFT!');
    }
    catch(e) {
        alert("Upload Error"+e)
    }
}

चरण 10: अपने कोड का परीक्षण करें

जब आप टर्मिनल में npm start कमांड को हिट करते हैं, तो मार्केटप्लेस आपके लोकलहोस्ट में खुल जाना चाहिए और नीचे जैसा दिखेगा:

2992

📘

यदि आपका कोड इस समय काम नहीं करता है तो समाप्त NFT मार्केटप्लेस ट्यूटोरियल के GitHub रेपो का संदर्भ लें। यदि आप इसे सीधे खींचते(pull करते) हैं, तो मार्केटप्लेस सही तरीके से काम करना चाहिए!

अपने मार्केटप्लेस को कनेक्ट करें

सबसे पहले, अपने नेवबार में "Connect Wallet" बटन पर क्लिक करके अपने मार्केटप्लेस को कनेक्ट करें।

यदि आप गोएरली से भिन्न नेटवर्क पर हैं, तो मेटामास्क पहले आपको नेटवर्क स्विच करने के लिए संकेत देगा।

फिर यह आपसे आपके विशिष्ट(specific) खाते से जुड़ने के लिए कहेगा।

700

एक एनएफटी अपलोड करें
एक सफल लॉगिन के बाद, आपका मार्केटप्लेस शायद नीचे जैसा दिखता है।

चूंकि आपने अभी-अभी कॉन्ट्रैक्ट डेप्लॉय (डिप्लॉय) किया है, इसलिए इसमें NFTs अनुपलब्ध हो सकते हैं।

ताज़ा, है हैना?\

2992

अब, नेवबार में "List My NFT" पृष्ठ पर जाएं और अपना पहला एनएफटी अपलोड करने के लिए विवरण(details) भरें। सबमिट करने से पहले यह कुछ इस तरह दिखना चाहिए:

2992

एनएफटी मार्केटप्लेस अपलोड फॉर्म

📘

सुनिश्चित करें कि आपके पास इस समय पर गोएर्ली फॉसेट से कुछ गोएर्ली ईथर है। यदि आपके पास पर्याप्त गोएर्ली ईथर नहीं है, तो अपर्याप्त धन के कारण लेनदेन(transaction) विफल हो सकता है।

अब यदि आप submit दबाते हैं और थोड़ी देर (अधिकतम 5 मिनट तक) प्रतीक्षा करते हैं, तो आपको एक अलर्ट दिखाई देना चाहिए जो कहता है कि "Successfully uploaded your NFT!"।

यदि आप OK पर क्लिक करते हैं, तो यह आपको आपके मार्केटप्लेस होम पेज पर रीडायरेक्ट कर देगा।

अब यदि आप मार्केटप्लेस और अपनी प्रोफ़ाइल पर जाते हैं, तो आपको वह NFT दिखाई देनी चाहिए!

एनएफटी खरीदना

एनएफटी खरीदने की कार्यक्षमता का परीक्षण करने के लिए, पहले अपने मेटामास्क वॉलेट एक्सटेंशन में "My Account" में जाकर अपने मेटामास्क में वॉलेट को किसी अन्य वॉलेट में स्विच करें।

यह नीचे दी गई स्क्रीन दिखाएगा।

700

यदि आपके पास पहले से कोई दूसरा खाता नहीं है, तो एक बनाएं और इसे Goerli ETH से लोड करें

अगला, एक व्यक्तिगत एनएफटी के पृष्ठ पर जाएं और "Buy this NFT" बटन पर क्लिक करें।

कुछ प्रतीक्षा समय के बाद, आपको "Successfully bought the NFT!" कहने वाला एक अलर्ट दिखाई देगा।

अब यदि आप अपने प्रोफाइल सेक्शन में जाते हैं, तो एनएफटी दिखाई देगी!

2992

एनएफटी वॉलेट प्रोफाइल पेज

वोइला!

यदि वह सब आपके लिए काम किया, तो आपने अब NFT मार्केटप्लेस का एक कार्यशील v1 सफलतापूर्वक बना लिया है।

अद्भुत!

चरण 11: [वैकल्पिक] कार्यक्षमता का विस्तार

क्या आप जानते हैं कि क्या अच्छा होगा? सबसे अच्छी बात यह होगी कि आप में से कुछ लोग आगे बढ़कर इस ट्यूटोरियल में लागू की गई कुछ कार्यात्मकताओं को बढ़ाएँ!

कुछ संभावित एक्सटेंशन हो सकते हैं

  • मार्केटप्लेस और प्रोफाइल पेज के लिए एनएफटी लाने के लिए एल्केमी के getNFTs और getNFTsForCollection एंडपॉइंट्स का उपयोग करें
  • उपयोगकर्ताओं को मार्केटप्लेस में पहले से मौजूद NFTs को सूचीबद्ध करने देने के लिए कार्यक्षमता जोड़ें
  • रॉयल्टी को इस तरह से जोड़ें कि original NFT निर्माता को हर बार NFT की बिक्री पर 10% आय प्राप्त हो

यदि आप उपरोक्त या पूरी तरह से किसी अन्य कार्यक्षमता को लागू करते हैं, तो @AlchemyPlatform को टैग करें और इसे हमारे साथ ट्विटर पर साझा करें! हम इसे अपने 40k (और बढ़ते) डेवलपर्स के समुदाय के साथ साझा भी कर सकते हैं।

प्रूफ ऑफ नॉलेज (पीओके) टोकन को रिडीम करने के लिए अपना प्रोजेक्ट यहां जमा करें: https://university.alchemy.com/discord

निष्कर्ष

इस ट्यूटोरियल के साथ, आपने स्क्रैच से सफलतापूर्वक अपना NFT मार्केटप्लेस बनाया है!

Road to Web3 Week 7 पूरा करने पर बधाई!

इसके ऊपर अधिक सुविधाएँ जोड़ने के लिए स्वतंत्र महसूस करें जैसे कि एल्केमी के एपीआई का उपयोग करना और पुराने एनएफटी को सूचीबद्ध करना।

यदि आपको NFT मार्केटप्लेस बनाने के लिए यह ट्यूटोरियल अच्छा लगा हो, तो हमें ट्वीट करें @AlchemyPlatform ! (या यदि आपके पास कोई प्रश्न/फीडबैक है तो लेखक @ankg404 को एक शाउटआउट दें!)

अन्य ब्लॉकचेन डेवेलपर्स, बिल्डरों और उद्यमियों(इंटरप्रेन्योर) से मिलने के लिए हमारे डिसॉर्डर सर्वर से जुड़ना न भूलें! यह भी साझा करें कि आपने हमारे साथ क्या बनाया 🎉🎉

हम हमेशा इस सीखने की यात्रा को बेहतर बनाने की कोशिश कर रहे हैं, कृपया हमारे साथ फीडबैक साझा करें!


ReadMe