3. ऑन-चेन मेटाडेटा के साथ एनएफटी(NFT) कैसे बनाएं - हार्डहाट और जावास्क्रिप्ट

एनएफटी बनाते समय, मेटाडेटा(Metadata) को सेंट्रलाइज़्ड ऑब्जेक्ट स्टोरेज या IPFS(आईपीएफएस) जैसे डिसेंट्रलाइज़्ड समाधानों पर स्टोर करना अच्छा अभ्यास है, ताकि बड़ी मात्रा में डेटा, जैसे कि इमेजिस और JSON ऑब्जेक्ट्स को सीधे ऑन-चेन स्टोर करने से लगने वाली गैस फीस से बचा जा सके।

हालांकि इसके साथ एक समस्या है:

ब्लॉकचेन पर अपने मेटाडेटा को संग्रहीत/स्टोर नहीं करना आपके स्मार्ट कॉन्ट्रैक्ट से इसके साथ बातचीत करना असंभव बना देगा, क्योंकि ब्लॉकचेन "बाहरी दुनिया" के साथ बात नहीं कर सकता है

अगर हम अपने मेटाडेटा को सीधे अपने स्मार्ट कॉन्ट्रैक्ट से अपडेट करना चाहते हैं, तो हमें इसे ऑन-चेन स्टोर करना होगा, लेकिन गैस शुल्क के बारे में क्या?

सौभाग्य से, Polygon(पॉलीगॉन) जैसी L2 चेन्स गैस की लागत को काफी कम करने और डेवलपर्स को अपने ऍप्लिकेशन्स की कार्यक्षमता का विस्तार करने की अनुमति देती है तथा कई लाभों को पेश करती है।

इस ट्यूटोरियल में, आप सीखेंगे कि एक छोटी सी ब्लॉकचैन गेम कैसे बनाएं, ऑन-चेन मेटाडेटा के साथ एक पूरी तरह से गतिशील(dynamic) एनएफटी विकसित करें जो आपकी इसके साथ बातचीत(इंटरैक्शन) के आधार पर बदलती है, और इसे Polygon Mumbai(पॉलीगॉन मुंबई) में गैस शुल्क कम करने के लिए तैनात करता है।

अधिक सटीक रूप से, आप सीखेंगे:

  • एनएफटी मेटाडेटा को चेन पर कैसे स्टोर करें
  • Polygon(पॉलीगॉन) क्या है और गैस शुल्क कम करना क्यों महत्वपूर्ण है।
  • Polygon Mumbai(पॉलीगॉन मुंबई) पर कैसे तैनात(deploy) करें
  • ऑन-चेन SVG इमेज और JSON ऑब्जेक्ट्स को कैसे प्रोसेस और स्टोर करें?
  • NFT के साथ अपने इंटरैक्शन के आधार पर अपने मेटाडेटा को कैसे मॉडिफाई करें

अगर आप इस टुटोरिअल को वीडियो के रूप में देखना चाहते हैं तो नीचे दी गयी विडियो पे क्लिक करें:

https://youtu.be/8FJvY4zXvPE

हमारे कोड में गहराई से जाने और हमारे गतिशील(dynamic) एनएफटी स्मार्ट कॉन्ट्रैक्ट को विकसित करने से पहले, हमें कुछ चीजों को संक्षेप में समझने की जरूरत है:

  • Polygon(पॉलीगॉन) क्या है,
  • हम इसका उपयोग क्यों करने जा रहे हैं।

साथ ही, यहां एक अल्केमी खाते के लिए साइन अप करना सुनिश्चित करें, हमें बाद में इसकी आवश्यकता होगी।

आएँ शुरू करें!

Polygon PoS - कम गैस फीस और तेज़ ट्रांसेक्शन(transaction)

पॉलीगॉन एक डिसेंट्रलाइज़्ड EVM-compatible(ईवीएम-संगत) स्केलिंग प्लेटफॉर्म है जो डेवलपर्स को सुरक्षा का त्याग किए बिना कम ट्रांसेक्शन फीस के साथ स्केलेबल तथा उपयोगकर्ता के अनुकूल DApps बनाने में सक्षम बनाता है।

यह Layer 2 chains(L2) नामक chains के एक समूह से संबंधित है, जिसका अर्थ है कि इथीरीयम/एथेरियम के ऊपर इसे एथेरियम से ही सम्बंधित कुछ मुद्दों को हल करने के लिए बनाया गया है - जबकि यह इस(एथेरियम) पर कार्य करने के लिए निर्भर है।

जैसा कि हम सभी जानते हैं, एथेरियम न तो तेज है और न ही सस्ता है, और इस पर स्मार्ट कॉन्ट्रैक्ट्स को तैनात करना बहुत महंगा हो सकता है, यहीं से Polygon(पॉलीगॉन) या Optimism(ऑप्टिमिज्म) जैसे L2 समाधान काम में आते हैं।

उदाहरण के लिए पॉलीगॉन 2 मुख्य लाभों के साथ आता है:

  • तेज़ ट्रांसक्शन्स(transactions) (65,000 TX/second vs ~14)
  • एथेरियम की तुलना में प्रति ट्रांसक्शन लगभग ~10,000x कम गैस लागत

दूसरा ठीक यही कारण है कि हम पॉलीगॉन पर ऑन-चेन मेटाडेटा के साथ अपने एनएफटी स्मार्ट कॉन्ट्रैक्ट को तैनात कर रहे हैं। यदि एक तरफ, एथेरियम पर हमारे मेटाडेटा को संग्रहीत करते समय हम प्रति लेनदेन सैकड़ों डॉलर की उम्मीद कर सकते हैं, तो पॉलीगॉन पर इसकी कीमत कुछ सेंट्स(cents) से अधिक नहीं होगी

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

अब जब हमें इस बात को समझ गए है कि L2 समाधान अपने साथ क्या लेकर आते हैं, और इस मामले में पॉलीगॉन का उपयोग क्यों एक गेम-चेंजर है - आइए पॉलीगॉन मुंबई से जुड़ने के लिए अपना वॉलेट सेट करके शुरू करें, और कुछ मुफ्त मैटिक प्राप्त करें जिसकी ज़रूरत हमें बाद में गैस शुल्क के लिए भुगतान के लिए पड़ेगी।

Polygon Mumbai(पॉलीगॉन मुंबई) को अपने मेटामास्क वॉलेट में जोड़ें

सबसे पहले, आइए अपने मेटामास्क वॉलेट में पॉलीगॉन मुंबई को जोड़ें।

Mumbai.polygonscan.com पर नेविगेट करें और पेज के नीचे तक स्क्रॉल करें। आपको "Add Polygon Network" बटन दिखाई देगा, उस पर क्लिक करें और कन्फर्म करें कि आप इसे मेटामास्क में जोड़ना चाहते हैं:

12861286

बस यह इतना ही सरल था, अब आपके पास अपने मेटामास्क वॉलेट में पॉलीगॉन मुंबई जुड़ जाएगा! 🎉

अब जबकि हमारे मेटामास्क एक्सटेंशन से पॉलीगॉन मुंबई जुड़ा हुआ है, हमें गैस शुल्क का भुगतान करने के लिए कुछ Test MATIC प्राप्त करने की आवश्यकता होगी

अपने एनएफटी स्मार्ट कॉन्ट्रैक्ट को डिप्लॉए करने के लिए निःशुल्क मैटिक प्राप्त करें

Test MATIC प्राप्त करना अत्यंत सरल है, बस निम्नलिखित में से किसी एक फॉसेट(faucet) पर नेविगेट करें:

वॉलेट एड्रेस को टेक्स्ट बार में पेस्ट करें और "Send Me MATIC" पर क्लिक करें:

20282028

10-20 सेकंड के बाद आप देखेंगे कि MATIC मेटामास्क वॉलेट में दिखाई दे रहा है।

आप बिना लॉग इन किए हर 24 घंटों में 1 MATIC या अल्केमी खाते से 5 प्राप्त कर सकेंगे।

बहुत बढ़िया! अब जब हमारा वॉलेट तैयार है, तो यह हमारी परियोजना बनाने, गतिशील(dynamic) एनएफटी स्मार्ट कॉन्ट्रैक्ट विकसित करने और इसके साथ बातचीत शुरू करने का समय है!

ऑन-चेन मेटाडेटा के साथ एनएफटी कैसे बनाएं - प्रोजेक्ट सेटअप

टर्मिनल खोलें, "ChainBattled" नामक एक नया फ़ोल्डर बनाएं और निम्नलिखित कमांड चलाकर हार्डहैट इनस्टॉल करें:

yarn add hardhat

फिर प्रोजेक्ट बॉयलरप्लेट बनाने के लिए हार्डहैट को इनिशियलाइज़ करें:

npx hardhat init

"Create a basic sample project" चुनें और सभी विकल्प कन्फर्म करें:

12701270

अब हमें ERC721 स्मार्ट कॉन्ट्रैक्ट स्टैण्डर्ड तक पहुँच प्राप्त करने के लिए OpenZeppelin पैकेज इनस्टॉल करने की आवश्यकता होगी जिसका उपयोग हम अपने NFTs स्मार्ट कॉन्ट्रैक्ट के निर्माण के लिए एक टेम्पलेट के रूप में करेंगे।

OpenZeppelin स्मार्ट कॉन्ट्रैक्ट लाइब्रेरी इनस्टॉल करें:

yarn add @openzeppelin/contracts

अद्भुत! हमने अब वह सब कुछ स्थापित कर लिया है जिसकी हमें ऑन-चेन मेटाडेटा के साथ एनएफटी बनाने के लिए आवश्यकता होगी।

आइए अपने प्रोजेक्ट बॉयलरप्लेट(Boilerplate) को थोड़ा साफ और मॉडिफाई करें और डायनेमिक एनएफटी स्मार्ट कॉन्ट्रैक्ट बनाएं।

सबसे पहले, हालांकि, हमें पॉलीगॉन मुंबई और पॉलीगॉन स्कैन से जुड़ने के लिए hardhat.config.js फ़ाइल को मॉडिफाई करना होगा - कोड को वेरीफाई करने के लिए हमें बाद में इसकी आवश्यकता होगी।

Hardhat.config.js फ़ाइल को मॉडिफाई करें

आइए VSCode या अपने पसंदीदा टेक्स्ट एडिटर में प्रोजेक्ट खोलें और "contract" फ़ोल्डर के अंदर Greeter.sol स्मार्ट कॉन्ट्रैक्ट को, और "script" फ़ोल्डर के अंदर "test-deploy.js" स्क्रिप्ट को डिलीट कर दें।

अगला कदम हार्डहैट को पॉलीगॉन मुंबई से जोड़ना है। अपने प्रोजेक्ट के रूट में मौजूद hardhat.config.js फाइल को खोलें और module.exports ऑब्जेक्ट के अंदर, निम्नलिखित कोड को कॉपी करें:

module.exports = {
  solidity: "0.8.10",
  networks: {
    mumbai: {
      url: process.env.TESTNET_RPC,
      accounts: [process.env.PRIVATE_KEY]
    },
  },
};

जब हम अपने स्मार्ट कॉन्ट्रैक्ट को डिप्लॉए करेंगे, तो हम इसे mumbai.polygonscan का उपयोग करके भी वेरीफाई करना चाहेंगे, ऐसा करने के लिए हमें Hardhat को एक इथरस्कैन या, इस मामले में, Polygon scan API key प्रदान करने की आवश्यकता होगी।

हम बाद में Polygonscan API key को ले लेंगे, फिलहाल, बस निम्नलिखित कोड को hardhat.config.js फ़ाइल में जोड़ें:

etherscan: {
    apiKey: process.env.POLYGONSCAN_API_KEY
  }

इस समय पर, आपकी hardhat.config.js फ़ाइल इस प्रकार दिखनी चाहिए:

require("dotenv").config();
require("@nomiclabs/hardhat-waffle");
require("@nomiclabs/hardhat-etherscan");

module.exports = {
  solidity: "0.8.10",
  networks: {
    mumbai: {
      url: process.env.TESTNET_RPC,
      accounts: [process.env.PRIVATE_KEY]
    },
  },
  etherscan: {
    apiKey: process.env.POLYGONSCAN_API_KEY
  }
};

अब जब हमारी कॉन्फ़िगरेशन फ़ाइल तैयार है, तो चलिए स्मार्ट कॉन्ट्रैक्ट विकसित करना शुरू करते हैं!

ऑन-चेन मेटाडेटा के साथ एनएफटी: स्मार्ट कॉन्ट्रैक्ट विकसित करें

contract फ़ोल्डर में, एक नई फ़ाइल बनाएं और इसे "ChainBattles.sol" नाम दें।

हमेशा की तरह, हमें SPDX-License-Identifier तथा pragma को स्पष्ट रूप से लिखना होगा, और OpenZeppelin से कुछ लाइब्रेरी को आयात करना होगा जिनका उपयोग हम अपने स्मार्ट कॉन्ट्रैक्ट की नींव के रूप में करेंगे:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/Base64.sol";

इस मामले में, हम आयात/इम्पोर्ट कर रहे हैं:

  • ERC721URIStorage कॉन्ट्रैक्ट जिसका उपयोग हमारे ERC721 स्मार्ट कॉन्ट्रैक्ट की नींव के रूप में किया जाएगा
  • counters.sol लाइब्रेरी, हमारे tokenIDs को संभालने और संग्रहीत करने का ध्यान रखेगी
  • string.sol लाइब्रेरी "toString ()" फ़ंक्शन को लागू करने के लिए, जो डेटा को स्ट्रिंग्स में परिवर्तित करता है
  • जैसा कि हमने पहले देखा था, Base64 लाइब्रेरी हमारे ऑन-चेन एसवीजी जैसे base64 डेटा को संभालने में हमारी मदद करेगी।

अगला, आइए कॉन्ट्रैक्ट को प्रारंभ करें।

स्मार्ट कॉन्ट्रैक्ट शुरू करें

सबसे पहले, हमें एक नया कॉन्ट्रैक्ट बनाने की आवश्यकता होगी जो ERC721URIStorage एक्सटेंशन से प्राप्त होता है जिसे हमने OpenZeppelin से आयात/इम्पोर्ट किया था। हम इसे "is" कीवर्ड का उपयोग करके कर सकते हैं:

contract ChainBattles is ERC721URIStorage {}

कॉन्ट्रैक्ट के अंदर, Strings(स्ट्रिंग्स) और Counters(काउंटर्स) लाइब्रेरी को इनिशियलाइज़ करें:

contract ChainBattles is ERC721URIStorage {
    using Strings for uint256;
    using Counters for Counters.Counter; 
}

इस मामले में "using Strings for uint256" का अर्थ है कि हम "Strings" लाइब्रेरी के अंदर सभी मेथड्स को uint256 प्रकार से जोड़ रहे हैं। आप यहाँ टाइप्स को लाइब्रेरीज के साथ एसोसिएट(associating libraries to types) करने के बारे में जान सकते हैं

यही बात "using Counters for Counters.Counter" पर भी लागू होती है - आप इसके बारे में OpenZeppelin फोरम पर अधिक पढ़ सकते हैं।

अब जब हमने अपनी लाइब्रेरीज को इनिशियलाइज़ कर लिया है, तो एक नया tokenIds(टोकनआईड्स) फंक्शन घोषित करें जिसकी हमें अपनी NFT IDs(एनएफटी आईडी) को स्टोर करने की आवश्यकता होगी:

contract ChainBattles is ERC721URIStorage {
    using Strings for uint256;
    using Counters for Counters.Counter; 
    Counters.Counter private _tokenIds;
}

last global variable(अंतिम ग्लोबल वेरिएबल) जिसे हमें घोषित करने की आवश्यकता है, वह है tokenIdToLevels mapping(मैपिंग), जिसका उपयोग हम इसके टोकन से जुड़े NFT के लेवल(level) को स्टोर करने के लिए करेंगे:

mapping(uint256 => uint256) public tokenIdToLevels;

मैपिंग एक uint256, NFTId, को दूसरे uint256, NFT के लेवल(level) से जोड़ेगी।

इसके बाद, हमें अपने स्मार्ट कॉन्ट्रैक्ट के constructor(कंस्ट्रक्टर) फ़ंक्शन को घोषित करना होगा:

constructor() ERC721 ("Chain Battles", "CBTLS"){
}

इस समय पर आपका कोड निम्नानुसार दिखना चाहिए:

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

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/Base64.sol";

contract ChainBattles is ERC721URIStorage  {
    using Strings for uint256;
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    mapping(uint256 => uint256) public tokenIdToLevels;

    constructor() ERC721 ("Chain Battles", "CBTLS"){
    }
}

अब जबकि हमारे पास हमारे एनएफटी स्मार्ट कॉन्ट्रैक्ट की नींव है, हमें 4 अलग-अलग कार्यों को लागू करने की आवश्यकता होगी:

  • generateCharacter: हमारे NFT की SVG इमेज उत्पन्न और अपडेट करने के लिए
  • getLevels: NFT का वर्तमान लेवल प्राप्त करने के लिए
  • getTokenURI: किसी NFT का TokenURI प्राप्त करने के लिए
  • mint: mint करने के लिए
  • train: एनएफटी को ट्रैन करने और उसका लेवल/स्तर बढ़ाने के लिए

आइए पहले फ़ंक्शन से शुरू करें जो एक एसवीजी लेगा, इसे Base64 डेटा में परिवर्तित करेगा, और इसे ऑन-चेन में सेव करेगा - लेकिन पहले, हमें यह समझने चाहिए कि एसवीजी का उपयोग ऑन-चेन छवियों को सहेजने के लिए क्यों किया जा सकता है और उनका Base64 डेटा के साथ क्या संबंध है।

एसवीजी क्या हैं और वे क्यों मायने रखते हैं?

एक SVG(एसवीजी) फ़ाइल, scalable vector graphic(स्केलेबल वेक्टर ग्राफ़िक) फ़ाइल का शॉर्ट फॉर्म है, एक ग्राफिक्स फ़ाइल का प्रकार है जिसका उपयोग इंटरनेट पर 2D छवियों को प्रस्तुत करने के लिए किया जाता है। अन्य लोकप्रिय छवि फ़ाइल स्वरूपों के विपरीत, एसवीजी प्रारूप छवियों को वैक्टर के रूप में स्टोर करता है, जो एक प्रकार का ग्राफिक है जो गणितीय फ़ॉर्मूलास/सूत्रों के आधार पर बिंदुओं, रेखाओं, वक्रों और आकृतियों से बना होता है।

SVG(एसवीजी) फाइलें XML/एक्सएमएल में लिखी जाती हैं, एक मार्कअप भाषा जिसका उपयोग डिजिटल जानकारी को स्टोर और स्थानांतरित करने के लिए किया जाता है। एक एसवीजी फ़ाइल में एक्सएमएल कोड उन सभी आकृतियों, रंगों और पाठ को स्पेसिफाई करता है जो छवि को बनाते हैं:

<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 350">
   <style>.base { fill: white; font-family: serif; font-size: 14px; }</style>
   <rect width="100%" height="100%" fill="black" />
   <text x="50%" y="40%" class="base" dominant-baseline="middle" text-anchor="middle">Warrior</text>
   <text x="50%" y="50%" class="base" dominant-baseline="middle" text-anchor="middle">Levels: getLevels(tokenId)</text>
 </svg>

SVGs के बारे में अच्छी बात यह है:

  • कोड का उपयोग करके आसानी से संशोधित और उत्पन्न हो सकते हैं
  • आसानी से Base64 डेटा में कनवर्ट किया जा सकता है

अब, आपको आश्चर्य हो सकता है कि हम एसवीजी फाइलों को Base64 डेटा में क्यों बदलना चाहते हैं, इसका उत्तर बहुत आसान है:

आप एक होस्टिंग प्रोवाइडर की आवश्यकता के बिना ब्राउज़र में बेस 64 छवियों को प्रदर्शित कर सकते हैं।

आइए इस छवि को उदाहरण के लिए लें:

18181818

निम्नलिखित कोड को अपने ब्राउज़र URL बार में कॉपी और पेस्ट करने से वही इमेज प्रदर्शित होगी:

data:image/svg+xml;base64,IDxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWluWU1pbiBtZWV0IiB2aWV3Qm94PSIwIDAgMzUwIDM1MCI+CiAgICAgICAgPHN0eWxlPi5iYXNlIHsgZmlsbDogd2hpdGU7IGZvbnQtZmFtaWx5OiBzZXJpZjsgZm9udC1zaXplOiAxNHB4OyB9PC9zdHlsZT4KICAgICAgICA8cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJibGFjayIgLz4KICAgICAgICA8dGV4dCB4PSI1MCUiIHk9IjQwJSIgY2xhc3M9ImJhc2UiIGRvbWluYW50LWJhc2VsaW5lPSJtaWRkbGUiIHRleHQtYW5jaG9yPSJtaWRkbGUiPldhcnJpb3I8L3RleHQ+CiAgICAgICAgPHRleHQgeD0iNTAlIiB5PSI1MCUiIGNsYXNzPSJiYXNlIiBkb21pbmFudC1iYXNlbGluZT0ibWlkZGxlIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5MZXZlbHM6IGdldExldmVscyh0b2tlbklkKTwvdGV4dD4KICAgICAgICA8L3N2Zz4=

जैसा कि आप देख सकते हैं कि आपके द्वारा पेस्ट किया गया कोड एक सामान्य URL नहीं है, यह वास्तव में दो भागों से बना है:

  • Data directives(डेटा निर्देश) - ब्राउज़र को डेटा को संभालने का तरीका बताता है (data:image/svg+xml;base64,)
  • Base64 डेटा - वास्तविक डेटा रखता है

यह उपयोगी है क्योंकि, भले ही Solidity(सॉलिडिटी) छवियों/इमेजेज को संभालने में सक्षम नहीं है, लेकिन यह स्ट्रिंग्स को संभालने में सक्षम है और एसवीजी टैग और स्ट्रिंग्स के अलावा और कुछ नहीं हैं, जिन्हे हम आसानी से रनटाइम के दौरान पुनः प्राप्त कर सकते हैं, साथ ही, सब कुछ base64 में परिवर्तित करने से हम ऑब्जेक्ट स्टोरेज की आवश्यकता के बिना हमारी छवियों/इमेजेज को ऑन-चेन स्टोर कर सकते हैं।

अब जबकि हमने बताया है कि एसवीजी क्यों महत्वपूर्ण हैं, आइए जानें कि अपने ऑन-चेन एसवीजी कैसे उत्पन्न करें और उन्हें base64 डेटा में परिवर्तित करें।

SVG इमेज बनाने के लिए GenerateCharacter फ़ंक्शन बनाएं

हमें एक फ़ंक्शन की आवश्यकता होगी जो NFT के लेवल को ध्यान में रखते हुए, कुछ SVG कोड का उपयोग करके NFT इमेज को ऑन-चेन उत्पन्न करेगा

इसे सॉलिडिटी में करना थोड़ा मुश्किल है, इसलिए चलिए पहले निम्न कोड को कॉपी करते हैं, और फिर इसके विभिन्न हिस्सों को समझेंगे:

function generateCharacter(uint256 tokenId) public returns(string memory){

    bytes memory svg = abi.encodePacked(
        '<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 350">',
        '<style>.base { fill: white; font-family: serif; font-size: 14px; }</style>',
        '<rect width="100%" height="100%" fill="black" />',
        '<text x="50%" y="40%" class="base" dominant-baseline="middle" text-anchor="middle">',"Warrior",'</text>',
        '<text x="50%" y="50%" class="base" dominant-baseline="middle" text-anchor="middle">', "Levels: ",getLevels(tokenId),'</text>',
        '</svg>'
    );
    return string(
        abi.encodePacked(
            "data:image/svg+xml;base64,",
            Base64.encode(svg)
        )    
    );
}

पहली चीज जो आपको नोटिस करनी चाहिए, वह है "bytes" type, 32 bytes तक का एक डायनमिक रूप का ऐरे जहां आप स्ट्रिंग्स और इंटिजर्स स्टोर कर सकते हैं।

यदि आप Bytes के बारे में ज्यादा जानना चाहते हैं, तो आप Jean Cvllr द्वारा इस गाइड को पढ़ें

इस मामले में, हम इसका उपयोग SVG कोड को स्टोर करने के लिए कर रहे हैं जो हमारी NFT की इमेज को रिप्रेजेंट कर रहा है, जो abi.encodePacked() फ़ंक्शन की मदद से एक बाइट्स के ऐरे में बदल जाता है जो एक या अधिक वेरिएबल्स लेता है और उन्हें ABI में एन्कोड करता है।

आप ABI Global Solidity Object(एबीआई ग्लोबल सॉलिडिटी ऑब्जेक्ट) और एनकोड फ़ंक्शन के बारे में सॉलिडिटी डॉक्यूमेंटेशन पर अधिक पढ़ सकते हैं।

जैसा कि आप नोटिस कर सकते हैं कि एसवीजी कोड एक getLevels() फ़ंक्शन का रिटर्न वैल्यू लेता है और इसका उपयोग हम "Levels:" प्रॉपर्टी को पॉप्युलेट करने के लिए करते हैं - हम इस फ़ंक्शन को का उपयोग थोड़ी देर में करेंगे, लेकिन ध्यान दें कि आप फ़ंक्शंस और वेरिएबल्स का उपयोग डायनमिक रूप से अपने SVGs को बदलें के लिए कर सकते हैं

जैसा कि हमने पहले देखा है, ब्राउज़र पर एक इमेज को दिखाने के लिए हमें इसके Base64 वर्शन की आवश्यकता होगी, न कि बाइट्स वर्शन - और, हमें "data:image/svg+xml;base64,” स्ट्रिंग ब्राउज़र को प्रस्तुत करने की आवश्यकता होगी ताकि उसे यह बता सके कि Base64 स्ट्रिंग एक एसवीजी इमेज है और इसे कैसे खोलें।

ऐसा करने के लिए, ऊपर दिए गए कोड में, हम अपने SVG के एन्कोडेड वर्शन को Base64.Encode() का उपयोग करके Base64 में बदलकर वापस कर रहे हैं ब्राउज़र स्पेसिफिकेशन स्ट्रिंग के साथ abi.encodePacker() फ़ंक्शन का उपयोग करके।

अब जब हमने अपनी इमेज उत्पन्न करने के लिए फ़ंक्शन को बना लिया है, तो हमें अपने एनएफटी के लेवल को प्राप्त करने के लिए एक फ़ंक्शन को बनाने की आवश्यकता है।

NFT Level को पुनः प्राप्त करने के लिए getLevels फ़ंक्शन बनाएं

हमारे NFT के लेवल को प्राप्त करने के लिए, हमें अपने स्मार्ट कॉन्ट्रैक्ट में tokenIdToLevels mapping(मैपिंग) का उपयोग करना होगा, तथा उस tokenId को फंक्शन में पास करना जिसका हम लेवल चाहते हैं :

function getLevels(uint256 tokenId) public view returns (string memory) {
    uint256 levels = tokenIdToLevels[tokenId];
    return levels.toString();
}

जैसा कि आप देख सकते हैं कि यह बहुत आसन था, ध्यान देने वाली एकमात्र चीज toString() फ़ंक्शन है, जो OpenZeppelin Strings लाइब्रेरी से आ रही है, और हमारे लेवल को एक स्ट्रिंग में बदल देती है, जो कि एक uint256 है - जिसका उपयोग generateCharater फ़ंक्शन द्वारा किया जाएगा जैसा कि हमने पहले देखा है।

इसके बाद, हमें अपने NFT TokenURI को उत्पन्न करने और पुनः प्राप्त करने के लिए getTokenURI फ़ंक्शन बनाने की आवश्यकता होगी।

tokenURI उत्पन्न करने के लिए getTokenURI फ़ंक्शन बनाएं

getTokenURI फ़ंक्शन को एक पैरामीटर, tokenId की आवश्यकता होगी, इमेज उत्पन्न करने और एनएफटी का नाम बनाने के लिए इसका उपयोग करेगा।

हमेशा की तरह, आइए पहले कोड और इसके विभिन्न भागों को देखें:

function getTokenURI(uint256 tokenId) public returns (string memory){
    bytes memory dataURI = abi.encodePacked(
        '{',
            '"name": "Chain Battles #', tokenId.toString(), '",',
            '"description": "Battles on chain",',
            '"image": "', generateCharacter(tokenId), '"',
        '}'
    );
    return string(
        abi.encodePacked(
            "data:application/json;base64,",
            Base64.encode(dataURI)
        )
    );
}

ध्यान देने वाली पहली बात यह है कि हम फिर से abi.encodePacked फ़ंक्शन का उपयोग कर रहे हैं, इस बार हालांकि, JSON ऑब्जेक्ट बनाने के लिए

यदि आप नहीं जानते कि JSON ऑब्जेक्ट क्या हैं, तो आइए संक्षेप में कहें कि यह “कीय” और “वैल्यू” पेअर(key and value pair) की एक श्रृंखला है, एक प्रॉपर्टी का नाम और दूसरा प्रॉपर्टी की वैल्यू है।

इस मामले में "name" की वैल्यू है: "Chain Battles #" तथा tokenId.toString(), दूसरी ओर, "image" प्रॉपर्टी की वैल्यू , generateCharacter() फ़ंक्शन से लौटाई गई वैल्यू है

अंत में, हम JSON डेटा निर्देशों के साथ dataURI के Base64 एन्कोडेड वर्शन को रिप्रेजेंट करने वाले बाइट्स की ऐरे(array) वाली एक स्ट्रिंग लौटाते हैं - जैसा कि हमने अपनी SVG Image के साथ किया था।

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

ऑन-चेन मेटाडेटा के साथ एनएफटी बनाने के लिए मिंट फंक्शन बनाएं

इस मामले में मिंट फंक्शन के 3 लक्ष्य होंगे:

  • एक नया एनएफटी बनाना,
  • lलेवल वैल्यू प्रारंभ करना(Initialize the level value),
  • टोकन token URIयूआरआई सेट करना।

निम्नलिखित कोड को कॉपी करें:

function mint() public {
    _tokenIds.increment();
    uint256 newItemId = _tokenIds.current();
    _safeMint(msg.sender, newItemId);
    tokenIdToLevels[newItemId] = 0;
    _setTokenURI(newItemId, getTokenURI(newItemId));
}

हमेशा की तरह, हम पहले अपने _tokenIds वेरिएबल की वैल्यू को बढ़ाते हैं, और इसकी वर्तमान वैल्यू को एक नए uint256 वेरिएबल पर स्टोर करते हैं, इस मामले में, "newItemId"।

इसके बाद, हम OpenZeppelin ERC721 लाइब्रेरी से _safeMint() फ़ंक्शन को कॉल करते हैं, जिसमे हम msg.sender वेरिएबल और current id को पास करेंगे।

फिर हम tokenIdToLevels मैपिंग में एक नया आइटम बनाते हैं और उसकी वैल्यू 0 असाइन करते हैं, इसका मतलब है कि हमारे NFTs/character इस लेवल से शुरू होंगे।

आखिरी चीज के रूप में, हमने token URI को सेट किया है getTokenURI() के रिटर्न वैल्यू और newItemId को में पास करते हुए

यह एक एनएफटी मिंट करेगा जिसमें इमेज सहित मेटाडेटा पूरी तरह से ऑन-चेन संग्रहीत है 🔥

इसका मतलब यह भी है कि हम स्मार्ट कॉन्ट्रैक्ट से सीधे मेटाडेटा को अपडेट करने में सक्षम होंगे, आइए देखें कि हमारे एनएफटी को ट्रैन करने के लिए एक फ़ंक्शन कैसे बनाया जाए और उन्हें लेवल अप किया जाए!

अपना एनएफटी के स्तर/लेवल को बढ़ाने के लिए ट्रेन फ़ंक्शन बनाएं

जैसा कि हमने कहा, अब जबकि हमारे एनएफटी का मेटाडेटा पूरी तरह से ऑन-चेन है, हम इसके साथ सीधे स्मार्ट कॉन्ट्रैक्ट से बातचीत करने में सक्षम होंगे।

मान लीजिए कि हम गहन प्रशिक्षण/ट्रेनिंग के बाद अपने एनएफटी के स्तर/लेवल को बढ़ाना चाहते हैं, ऐसा करने के लिए, हमें एक train function(ट्रेन फ़ंक्शन) बनाना होगा जो:

  • सुनिश्चित करें कि प्रशिक्षित एनएफटी मौजूद है और आप इसके ओनर/मालिक हैं।
  • अपने NFT के स्तर को 1 से बढ़ाएँ।
  • प्रशिक्षण को दर्शाने के लिए token URI को अपडेट करें।
function train(uint256 tokenId) public {
    require(_exists(tokenId), "Please use an existing token");
    require(ownerOf(tokenId) == msg.sender, "You must own this token to train it");
    uint256 currentLevel = tokenIdToLevels[tokenId];
    tokenIdToLevels[tokenId] = currentLevel + 1;
    _setTokenURI(tokenId, getTokenURI(tokenId));
}

जैसा कि आप देख सकते हैं, require() फ़ंक्शन का उपयोग करके, हम दो चीजों की जाँच कर रहे हैं:

  • ERC721 स्टैण्डर्ड से _exists() फंक्शन का उपयोग करके यह देखना की टोकन मौजूद है या नहीं,
  • NFT का ओनर msg.sender (फ़ंक्शन को कॉल करने वाला वॉलेट) है।

एक बार दोनों चेक पास हो जाने के बाद, हम मैपिंग से NFT का वर्तमान स्तर प्राप्त करते हैं, और इसे एक-एक करके बढ़ाते हैं।

अंत में, हम tokenId और getTokenURI() की रिटर्न वैल्यू को पास करके _setTokenURI फ़ंक्शन को कॉल कर रहे हैं,

train function(ट्रेन फ़ंक्शन) को कॉल करने से अब NFT का स्तर बढ़ जाएगा और यह इमेज में अपने आप दिखाई देगा।

बधाई हो! आपने अभी-अभी ऑन-चेन मेटाडेटा के साथ NFTs के लिए स्मार्ट कॉन्ट्रैक्ट लिखना पूरा किया है। 🏆

अगला कदम Polygon Mumbai(पॉलीगॉन मुंबई) पर स्मार्ट कॉन्ट्रैक्ट को तैनात करना और Polygonscan(पॉलीगॉनस्कैन) के माध्यम से इसके साथ बातचीत करना है। ऐसा करने के लिए, हमें अपनी अल्केमी और पॉलीगॉनस्कैन key को लेना होगा।

एनएफटी को ऑन-चेन मेटाडेटा स्मार्ट कॉन्ट्रैक्ट के साथ डिप्लॉय करें

सबसे पहले, हमारे प्रोजेक्ट के रूट फोल्डर में एक नई .env फाइल बनाते हैं, और निम्नलिखित वेरिएबल्स को लिखते हैं:

TESTNET_RPC=""
PRIVATE_KEY=""
POLYGONSCAN_API_KEY=""

फिर, alchemy.com पर नेविगेट करें और एक नया पॉलीगॉन मुंबई एप्लिकेशन(Polygon Mumbai Application) बनाएं:

नए बनाए गए ऐप पर क्लिक करें, API HTTP URL को कॉपी करें, और ऊपर बनाई गई .env फाइल में API को "TESTNET_RPC" वैल्यू के आगे पेस्ट करें।

अपना मेटामास्क वॉलेट खोलें, तीन बिंदुओं वाले मेनू पर क्लिक करें > फिर account details पर क्लिक करें > और .env में अपनी प्राइवेट कीय को "PRIVATE_KEY" वैल्यू के आगे कॉपी-पेस्ट करें।

अंत में, polygonscan.com पर जाएं और एक नया अकाउंट बनाएं:

731731

लॉग इन करने के बाद, अपने profile menu पर जाएं और API Keys पर क्लिक करें:

191191

फिर "Add" पर क्लिक करें और अपने ऐप को एक नाम दें:

10351035

अब Api-key Token को "POLYGONSCANAPI_KEY" वैल्यू के आगे .env में कॉपी-पेस्ट करें।

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

डिप्लॉय स्क्रिप्ट बनाएँ

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

इस मामले में, हमारी डिप्लॉय स्क्रिप्ट बहुत सीधी है:

const main = async () => {
  try {
    const nftContractFactory = await hre.ethers.getContractFactory(
      "ChainBattles"
    );
    const nftContract = await nftContractFactory.deploy();
    await nftContract.deployed();

    console.log("Contract deployed to:", nftContract.address);
    process.exit(0);
  } catch (error) {
    console.log(error);
    process.exit(1);
  }
};
  
main();

हम get.contractFactory को कॉल कर रहे हैं, और Hardhat Ethers(हार्डहैट ईथर्स)की मदद हमारे स्मार्ट कॉन्ट्रैक्ट का नाम पास रहे हैं। फिर हम deploy() फ़ंक्शन को कॉल करते हैं और एड्रेस को लोग(log) करते हुए इसके डिप्लॉय होने की प्रतीक्षा करते हैं।

किसी भी एरर(error) को पकड़ने और डिबगिंग करने के साथ साथ इसे प्रिंट करने के लिए सब कुछ एक try{} catch{} ब्लॉक में लपेटा(रैप किया) गया है।

अब जब हमारी डिप्लॉय/परिनियोजन स्क्रिप्ट तैयार हो गई है, तो पॉलीगॉन मुंबई पर हमारे गतिशील एनएफटी स्मार्ट कॉन्ट्रैक्ट को कम्पाइल और डिप्लॉय करने का समय आ गया है।

स्मार्ट कॉन्ट्रैक्ट कम्पाइल और डिप्लॉय करें

स्मार्ट कॉन्ट्रैक्ट को संकलित करने के लिए प्रोजेक्ट के अंदर टर्मिनल में निम्न कमांड चलाएँ:

npx hardhat compile

यदि सब कुछ अपेक्षित रूप से होता है, तो आप अपने स्मार्ट कॉन्ट्रैक्ट को artifacts के फ़ोल्डर में कम्पाइलड देखेंगे।

अब, चलिये Polygon Mumbai(पॉलीगॉन मुंबई) चेन पर स्मार्ट कॉन्ट्रैक्ट को डिप्लॉय करते हैं:

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

10-15 सेकंड प्रतीक्षा करें और आपको अपने टर्मिनल में अपने स्मार्ट कॉन्ट्रैक्ट का एड्रेस प्रिंट हुआ दिखना चाहिए

838838

बहुत बढ़िया, आपने अभी-अभी अपना पहला स्मार्ट कॉन्ट्रैक्ट मुंबई पर तैनात किया है! इसके बाद, हमें पॉलीगॉनस्कैन(Polygonscan) के माध्यम से इसके साथ इंटरैक्ट करने के लिए अपने स्मार्ट कॉन्ट्रैक्ट कोड को वेरीफाई करना होगा।

पॉलीगॉनस्कैन पर अपने स्मार्ट कॉन्ट्रैक्ट को चेक करें

हाल ही में डिप्लोइड स्मार्ट कॉन्ट्रैक्ट के पते को कॉपी करें, mumbai.polygonscan.com पर जाएँ, और सर्च बार में स्मार्ट कॉन्ट्रैक्ट का पता पेस्ट करें।

एक बार जब आप स्मार्ट कॉन्ट्रैक्ट पृष्ठ पर पहुँच जाएँ तब, "Contract" टैब पर क्लिक करें।

आप देखेंगे कि कॉन्ट्रैक्ट कोड पढ़ने योग्य नहीं है:

13831383

ऐसा इसलिए है क्योंकि हमने अभी तक अपना कोड वेरीफाई नहीं किया है।

अपने स्मार्ट कॉन्ट्रैक्ट को वेरीफाई करने के लिए हमें अपने प्रोजेक्ट पर वापस जाना होगा, और टर्मिनल में निम्नलिखित कोड चलाना होगा:

"YOUR_SMARTCONTRACT_ADDRESS" की जगह अपना स्मार्ट कॉन्ट्रैक्ट एड्रेस डालें जो आपको डेप्लॉय करने का बाद प्राप्त हुआ है
npx hardhat verify --network mumbai YOUR_SMARTCONTRACT_ADDRESS
834834

कभी-कभी आपको "failed to send contract verification request" एरर मिल सकता है - बस पुनः प्रयास करें और दूसरी बार इसे सही से चल जाना चाहिए।

यह पॉलीगॉन स्कैन API key का उपयोग करेगा जिसे हमने स्मार्ट कॉन्ट्रैक्ट कोड को वेरीफाई करने के लिए hardhat.config.js फ़ाइल में ऐड किया था। अब हम पॉलीगॉन स्कैन के माध्यम से इसके साथ इंटरैक्ट करने में सक्षम होंगे, आइए इसे आजमाएं।

पॉलीगॉन स्कैन के माध्यम से अपने स्मार्ट कॉन्ट्रैक्ट के साथ इंटरैक्ट करें

अब जब स्मार्ट कॉन्ट्रैक्ट वेरिफाइ हो गया है, तो mumbai.polygonscan.com पर जाने के बाद, ”contract” टैब एक छोटा हरा टिक दिखाएगा:

355355

इसके साथ इंटरैक्ट करने के लिए, और पहली एनएफटी को मिंट करने के लिए, "contract" टैब के अंदर "Write Contract" बटन पर क्लिक करें, और फिर"connect to Web3" पर क्लिक करें।

13791379

फिर "mint" फ़ंक्शन ढूंढे और Write पर क्लिक करें:

560560

यह एक मेटामास्क पॉपअप खोलेगा जो आपसे गैस फीस का भुगतान करने के लिए कहेगा, तो “sign” बटन पर क्लिक करें।

बधाई हो! आपने अभी-अभी अपना पहला डायनेमिक NFT बनाया है - इसे लाइव देखने के लिए OpenSea Testnet पर चलते हैं।

OpenSea पर अपना डायनामिक NFT देखें

स्मार्ट कॉन्ट्रैक्ट एड्रेस को कॉपी करें, testnet.opensea.com पर जाएं और इसे सर्च बार में पेस्ट करें:

12751275

यदि सब कुछ अपेक्षित रूप से काम करता है, तो अब आपको अपने NFT को OpenSea पर उसकी गतिशील इमेज, शीर्षक और विवरण के साथ प्रदर्शित होते हुए देखना चाहिए।

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

आइए पॉलीगॉन स्कैन पर वापस जाएं।

NFT को ट्रैन कर डायनामिक NFT Image को अपडेट करें

mumbai.polygonscan.com पर वापस नेविगेट करें, contract टैब पर क्लिक करें > फिर Write Contract पर क्लिक करें और "train" फ़ंक्शन को ढूंढे।

इस मामले में अपने एनएफटी - "1" की आईडी डालें, क्योंकि हमने केवल एक ही बनाया है, और Write पर क्लिक करें:

952952

फिर testnets.opensea.com पर वापस जाएं और पेज को रिफ्रेश करें:

12461246

जैसा कि आप देख सकते हैं कि आपके NFT की इमेज अभी-अभी बदली है जो नए स्तर को दर्शाती है!

बधाई हो आपकी NFT का अभी-अभी लेवल अप हुआ है! बहुत बढ़िया! 🎉

अब इस सप्ताह की चुनौती को अगले स्तर पर लाने का समय आ गया है!

इस हफ्ते की चुनौती

इस समय हम केवल अपने एनएफटी के लेवल को ही स्टोर कर रहे हैं, क्यों न अधिक स्टोर किया जाए?

current tokenIdToLevels[] मैपिंग को struct के साथ बदले जो निचे दी गयी चीज़ों को स्टोर करता है :

  • Level(स्तर)
  • Speed
  • Strength
  • Life

आप इस गाइड में structs के बारे में अधिक पढ़ सकते हैं।

एक बार जब आप struct बना लेंगे, तो mint() फ़ंक्शन में stats प्रारंभ करें, ऐसा करने के लिए आप सॉलिडिटी पर pseduo number generation को देखना चाहेंगे।

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

Resources used:

  1. Google Translate
    translate.google.com
  2. Collins Dictionary
    https://www.collinsdictionary.com/dictionary/english-hindi/
  3. Hinkhoj Dictionary
    https://dict.hinkhoj.com/