मुख्य सामग्री पर जाएँ

वाइपर ERC-721 अनुबंध वॉकथ्रू

Vyper
erc-721
Python
शुरआती
ओरी पोमेरेंट्ज़
1 अप्रैल 2021
23 मिनट का पठन

परिचय

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

इस लेख में हम रयुया नाकामुरा के ERC-721 अनुबंध (opens in a new tab) का विश्लेषण करेंगे। यह अनुबंध वाइपर (opens in a new tab) में लिखा गया है, जो एक पायथन-जैसी अनुबंध भाषा है जिसे सॉलिडिटी की तुलना में असुरक्षित कोड लिखना कठिन बनाने के लिए डिज़ाइन किया गया है।

अनुबंध

1# @dev ERC-721 नॉन-फंजिबल टोकन मानक का कार्यान्वयन।
2# @author रयुया नाकामुरा (@nrryuya)
3# इससे संशोधित: https://github.com/vyperlang/vyper/blob/de74722bf2d8718cca46902be165f9fe0e3641dd/examples/tokens/ERC721.vy

वाइपर में टिप्पणियाँ, पायथन की तरह, हैश (#) से शुरू होती हैं और लाइन के अंत तक जारी रहती हैं। @<keyword> वाली टिप्पणियों का उपयोग नैटस्पेक (opens in a new tab) द्वारा मानव-पठनीय दस्तावेज़ीकरण बनाने के लिए किया जाता है।

1from vyper.interfaces import ERC721
2
3implements: ERC721

ERC-721 इंटरफ़ेस वाइपर भाषा में अंतर्निहित है। आप कोड परिभाषा यहाँ देख सकते हैं (opens in a new tab)। इंटरफ़ेस परिभाषा पायथन में लिखी गई है, न कि वाइपर में, क्योंकि इंटरफ़ेस का उपयोग न केवल ब्लॉकचेन के भीतर किया जाता है, बल्कि एक बाहरी क्लाइंट से ब्लॉकचेन में एक लेनदेन भेजते समय भी किया जाता है, जो पायथन में लिखा जा सकता है।

पहली लाइन इंटरफ़ेस को आयात करती है, और दूसरी यह निर्दिष्ट करती है कि हम इसे यहाँ लागू कर रहे हैं।

ERC721Receiver इंटरफ़ेस

1# safeTransferFrom() द्वारा बुलाए गए अनुबंध के लिए इंटरफ़ेस
2interface ERC721Receiver:
3 def onERC721Received(

ERC-721 दो प्रकार के हस्तांतरण का समर्थन करता है:

  • transferFrom, जो प्रेषक को किसी भी गंतव्य पते को निर्दिष्ट करने देता है और हस्तांतरण की जिम्मेदारी प्रेषक पर डालता है। इसका मतलब है कि आप एक अमान्य पते पर स्थानांतरित कर सकते हैं, इस मामले में एनएफटी हमेशा के लिए खो जाता है।
  • safeTransferFrom, जो जांचता है कि गंतव्य पता एक अनुबंध है या नहीं। यदि ऐसा है, तो ERC-721 अनुबंध प्राप्त करने वाले अनुबंध से पूछता है कि क्या वह एनएफटी प्राप्त करना चाहता है।

safeTransferFrom अनुरोधों का उत्तर देने के लिए एक प्राप्त करने वाले अनुबंध को ERC721Receiver लागू करना होगा।

1 _operator: address,
2 _from: address,

_from पता टोकन का वर्तमान स्वामी है। _operator पता वह है जिसने हस्तांतरण का अनुरोध किया था (भत्ते के कारण ये दोनों समान नहीं हो सकते हैं)।

1 _tokenId: uint256,

ERC-721 टोकन आईडी 256 बिट्स हैं। आमतौर पर वे टोकन का प्रतिनिधित्व करने वाली किसी भी चीज़ के विवरण को हैश करके बनाए जाते हैं।

1 _data: Bytes[1024]

अनुरोध में 1024 बाइट्स तक का उपयोगकर्ता डेटा हो सकता है।

1 ) -> bytes32: view

उन मामलों को रोकने के लिए जिनमें एक अनुबंध गलती से एक हस्तांतरण स्वीकार कर लेता है, वापसी मान एक बूलियन नहीं है, बल्कि एक विशिष्ट मान के साथ 256 बिट्स है।

यह फ़ंक्शन एक view है, जिसका अर्थ है कि यह ब्लॉकचेन की स्थिति को पढ़ सकता है, लेकिन इसे संशोधित नहीं कर सकता है।

घटनाएँ

इवेंट्स (opens in a new tab) को ब्लॉकचेन के बाहर के उपयोगकर्ताओं और सर्वरों को इवेंट्स के बारे में सूचित करने के लिए उत्सर्जित किया जाता है। ध्यान दें कि इवेंट्स की सामग्री ब्लॉकचेन पर अनुबंधों के लिए उपलब्ध नहीं है।

1# @dev किसी भी तंत्र द्वारा किसी भी NFT का स्वामित्व बदलने पर उत्सर्जित होता है। यह इवेंट तब उत्सर्जित होता है जब NFTs बनाए जाते हैं (`from` == 0) और नष्ट हो जाते हैं (`to` == 0)। अपवाद: अनुबंध निर्माण के दौरान, बिना Transfer उत्सर्जित किए किसी भी संख्या में NFTs बनाए और असाइन किए जा सकते हैं। किसी भी हस्तांतरण के समय, उस NFT के लिए स्वीकृत पता (यदि कोई हो) रीसेट हो जाता है।
2# @param _from NFT का प्रेषक (यदि पता शून्य पता है तो यह टोकन निर्माण को इंगित करता है)।
3# @param _to NFT का रिसीवर (यदि पता शून्य पता है तो यह टोकन विनाश को इंगित करता है)।
4# @param _tokenId वह NFT जिसे स्थानांतरित किया गया था।
5event Transfer:
6 sender: indexed(address)
7 receiver: indexed(address)
8 tokenId: indexed(uint256)

यह ERC-20 Transfer इवेंट के समान है, सिवाय इसके कि हम राशि के बजाय tokenId की रिपोर्ट करते हैं। शून्य पते का कोई स्वामी नहीं है, इसलिए परंपरा के अनुसार हम इसका उपयोग टोकन के निर्माण और विनाश की रिपोर्ट करने के लिए करते हैं।

1# @dev यह तब उत्सर्जित होता है जब किसी NFT के लिए स्वीकृत पता बदल दिया जाता है या उसकी पुष्टि की जाती है। शून्य पता इंगित करता है कि कोई स्वीकृत पता नहीं है। जब एक Transfer इवेंट उत्सर्जित होता है, तो यह यह भी इंगित करता है कि उस NFT के लिए स्वीकृत पता (यदि कोई हो) रीसेट हो जाता है।
2# @param _owner NFT का स्वामी।
3# @param _approved पता जिसे हम स्वीकृत कर रहे हैं।
4# @param _tokenId NFT जिसे हम स्वीकृत कर रहे हैं।
5event Approval:
6 owner: indexed(address)
7 approved: indexed(address)
8 tokenId: indexed(uint256)

एक ERC-721 अनुमोदन एक ERC-20 भत्ते के समान है। एक विशिष्ट पते को एक विशिष्ट टोकन स्थानांतरित करने की अनुमति है। यह अनुबंधों को टोकन स्वीकार करने पर प्रतिक्रिया देने के लिए एक तंत्र देता है। अनुबंध इवेंट्स को नहीं सुन सकते हैं, इसलिए यदि आप केवल टोकन को उनके पास स्थानांतरित करते हैं तो वे इसके बारे में "नहीं जानते" हैं। इस तरह मालिक पहले एक अनुमोदन प्रस्तुत करता है और फिर अनुबंध को एक अनुरोध भेजता है: "मैंने आपको टोकन X को स्थानांतरित करने के लिए अनुमोदित किया है, कृपया करें ..."।

यह ERC-721 मानक को ERC-20 मानक के समान बनाने के लिए एक डिज़ाइन विकल्प है। क्योंकि ERC-721 टोकन फंजिबल नहीं हैं, एक अनुबंध यह भी पहचान सकता है कि उसे टोकन के स्वामित्व को देखकर एक विशिष्ट टोकन मिला है।

1# @dev यह तब उत्सर्जित होता है जब किसी मालिक के लिए एक ऑपरेटर सक्षम या अक्षम होता है। ऑपरेटर मालिक के सभी NFTs का प्रबंधन कर सकता है।
2# @param _owner NFT का स्वामी।
3# @param _operator पता जिस पर हम ऑपरेटर अधिकार सेट कर रहे हैं।
4# @param _approved ऑपरेटर अधिकारों की स्थिति (सही यदि ऑपरेटर अधिकार दिए गए हैं और गलत यदि रद्द कर दिए गए हैं)।
5event ApprovalForAll:
6 owner: indexed(address)
7 operator: indexed(address)
8 approved: bool

कभी-कभी एक ऑपरेटर होना उपयोगी होता है जो एक विशिष्ट प्रकार के खाते के सभी टोकन (वे जो एक विशिष्ट अनुबंध द्वारा प्रबंधित होते हैं) का प्रबंधन कर सकता है, जो एक पावर ऑफ अटॉर्नी के समान है। उदाहरण के लिए, मैं एक अनुबंध को ऐसी शक्ति देना चाह सकता हूं जो यह जांचता है कि मैंने छह महीने से इससे संपर्क नहीं किया है, और यदि ऐसा है तो मेरी संपत्ति को मेरे उत्तराधिकारियों में वितरित कर देता है (यदि उनमें से कोई इसके लिए पूछता है, तो अनुबंध बिना लेनदेन के बुलाए कुछ नहीं कर सकते)। ERC-20 में हम बस एक विरासत अनुबंध को एक उच्च भत्ता दे सकते हैं, लेकिन यह ERC-721 के लिए काम नहीं करता है क्योंकि टोकन फंजिबल नहीं हैं। यह समतुल्य है।

approved मान हमें बताता है कि क्या इवेंट एक अनुमोदन के लिए है, या एक अनुमोदन की वापसी के लिए है।

स्टेट चर

इन चरों में टोकन की वर्तमान स्थिति होती है: कौन से उपलब्ध हैं और उनके मालिक कौन हैं। इनमें से अधिकांश HashMap ऑब्जेक्ट हैं, दो प्रकारों के बीच मौजूद एकदिशीय मैपिंग (opens in a new tab)

1# @dev NFT आईडी से उस पते पर मैपिंग जो इसका मालिक है।
2idToOwner: HashMap[uint256, address]
3
4# @dev NFT आईडी से स्वीकृत पते पर मैपिंग।
5idToApprovals: HashMap[uint256, address]

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

1# @dev मालिक के पते से उसके टोकन की गिनती तक मैपिंग।
2ownerToNFTokenCount: HashMap[address, uint256]

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

ध्यान दें कि यह एल्गोरिथम केवल उपयोगकर्ता इंटरफेस और बाहरी सर्वर के लिए काम करता है। ब्लॉकचेन पर चल रहा कोड स्वयं पिछले इवेंट्स को नहीं पढ़ सकता है।

1# @dev मालिक के पते से ऑपरेटर पतों की मैपिंग तक मैपिंग।
2ownerToOperators: HashMap[address, HashMap[address, bool]]

एक खाते में एक से अधिक ऑपरेटर हो सकते हैं। एक साधारण HashMap उनका ट्रैक रखने के लिए अपर्याप्त है, क्योंकि प्रत्येक कुंजी एक ही मान की ओर ले जाती है। इसके बजाय, आप मान के रूप में HashMap[address, bool] का उपयोग कर सकते हैं। डिफ़ॉल्ट रूप से प्रत्येक पते के लिए मान False है, जिसका अर्थ है कि यह एक ऑपरेटर नहीं है। आप आवश्यकतानुसार मान True पर सेट कर सकते हैं।

1# @dev मिंटर का पता, जो एक टोकन मिंट कर सकता है
2minter: address

नए टोकन किसी तरह बनाने होंगे। इस अनुबंध में एक ही इकाई है जिसे ऐसा करने की अनुमति है, minter। उदाहरण के लिए, यह एक खेल के लिए पर्याप्त होने की संभावना है। अन्य उद्देश्यों के लिए, एक अधिक जटिल व्यावसायिक तर्क बनाना आवश्यक हो सकता है।

1# @dev इंटरफ़ेस आईडी से बूल तक मैपिंग कि यह समर्थित है या नहीं
2supportedInterfaces: HashMap[bytes32, bool]
3
4# @dev ERC165 का ERC165 इंटरफ़ेस आईडी
5ERC165_INTERFACE_ID: constant(bytes32) = 0x0000000000000000000000000000000000000000000000000000000001ffc9a7
6
7# @dev ERC721 का ERC165 इंटरफ़ेस आईडी
8ERC721_INTERFACE_ID: constant(bytes32) = 0x0000000000000000000000000000000000000000000000000000000080ac58cd

ERC-165 (opens in a new tab) एक अनुबंध के लिए यह खुलासा करने के लिए एक तंत्र निर्दिष्ट करता है कि एप्लिकेशन इसके साथ कैसे संवाद कर सकते हैं, यह किन ERCs के अनुरूप है। इस मामले में, अनुबंध ERC-165 और ERC-721 के अनुरूप है।

फ़ंक्शन

ये वे फ़ंक्शन हैं जो वास्तव में ERC-721 को लागू करते हैं।

कंस्ट्रक्टर

1@external
2def __init__():

वाइपर में, पायथन की तरह, कंस्ट्रक्टर फ़ंक्शन को __init__ कहा जाता है।

1 """
2 @dev अनुबंध कंस्ट्रक्टर।
3 """

पायथन में, और वाइपर में, आप एक बहु-पंक्ति स्ट्रिंग (""" से शुरू और समाप्त होती है) निर्दिष्ट करके और इसे किसी भी तरह से उपयोग न करके भी एक टिप्पणी बना सकते हैं। इन टिप्पणियों में नैटस्पेक (opens in a new tab) भी शामिल हो सकता है।

1 self.supportedInterfaces[ERC165_INTERFACE_ID] = True
2 self.supportedInterfaces[ERC721_INTERFACE_ID] = True
3 self.minter = msg.sender

स्टेट चर तक पहुँचने के लिए आप self.<variable name> (फिर से, पायथन की तरह ही) का उपयोग करते हैं।

फ़ंक्शन देखें

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

1@view
2@external

एक फ़ंक्शन परिभाषा से पहले ये कीवर्ड जो एक एट साइन (@) से शुरू होते हैं, उन्हें डेकोरेशन कहा जाता है। वे उन परिस्थितियों को निर्दिष्ट करते हैं जिनमें एक फ़ंक्शन को बुलाया जा सकता है।

  • @view निर्दिष्ट करता है कि यह फ़ंक्शन एक व्यू है।
  • @external निर्दिष्ट करता है कि इस विशेष फ़ंक्शन को लेनदेन और अन्य अनुबंधों द्वारा बुलाया जा सकता है।
1def supportsInterface(_interfaceID: bytes32) -> bool:

पायथन के विपरीत, वाइपर एक स्टेटिक टाइप्ड भाषा (opens in a new tab) है। आप डेटा प्रकार (opens in a new tab) की पहचान किए बिना किसी चर, या किसी फ़ंक्शन पैरामीटर की घोषणा नहीं कर सकते। इस मामले में इनपुट पैरामीटर bytes32 है, जो 256-बिट मान है (एथेरियम Virtual Machine का मूल शब्द आकार 256 बिट्स है)। आउटपुट एक बूलियन मान है। परंपरा के अनुसार, फ़ंक्शन पैरामीटर के नाम एक अंडरस्कोर (_) से शुरू होते हैं।

1 """
2 @dev इंटरफ़ेस पहचान ERC-165 में निर्दिष्ट है।
3 @param _interfaceID इंटरफ़ेस का आईडी
4 """
5 return self.supportedInterfaces[_interfaceID]

self.supportedInterfaces HashMap से मान लौटाएं, जो कंस्ट्रक्टर (__init__) में सेट है।

1### VIEW FUNCTIONS ###
2

ये व्यू फ़ंक्शंस हैं जो उपयोगकर्ताओं और अन्य अनुबंधों के लिए टोकन के बारे में जानकारी उपलब्ध कराते हैं।

1@view
2@external
3def balanceOf(_owner: address) -> uint256:
4 """
5 @dev `_owner` के स्वामित्व वाले NFTs की संख्या लौटाता है।
6 यदि `_owner` शून्य पता है तो फेंकता है। शून्य पते को सौंपे गए NFTs को अमान्य माना जाता है।
7 @param _owner पता जिसके लिए शेष राशि की क्वेरी करनी है।
8 """

यह लाइन जोर देती है (opens in a new tab) कि _owner शून्य नहीं है। यदि ऐसा है, तो एक त्रुटि है और ऑपरेशन वापस कर दिया जाता है।

1 return self.ownerToNFTokenCount[_owner]
2
3@view
4@external
5def ownerOf(_tokenId: uint256) -> address:
6 """
7 @dev NFT के मालिक का पता लौटाता है।
8 यदि `_tokenId` एक वैध NFT नहीं है तो फेंकता है।
9 @param _tokenId एक NFT के लिए पहचानकर्ता।
10 """
11 owner: address = self.idToOwner[_tokenId]
12 # Throws if `_tokenId` is not a valid NFT
13 assert owner != ZERO_ADDRESS
14 return owner

एथेरियम वर्चुअल मशीन (evm) में कोई भी भंडारण जिसमें कोई मान संग्रहीत नहीं है, शून्य है। यदि _tokenId पर कोई टोकन नहीं है तो self.idToOwner[_tokenId] का मान शून्य है। उस स्थिति में फ़ंक्शन वापस आ जाता है।

1@view
2@external
3def getApproved(_tokenId: uint256) -> address:
4 """
5 @dev एक एकल NFT के लिए स्वीकृत पता प्राप्त करें।
6 यदि `_tokenId` एक वैध NFT नहीं है तो फेंकता है।
7 @param _tokenId NFT की आईडी जिसकी स्वीकृति की क्वेरी करनी है।
8 """
9 # Throws if `_tokenId` is not a valid NFT
10 assert self.idToOwner[_tokenId] != ZERO_ADDRESS
11 return self.idToApprovals[_tokenId]

ध्यान दें कि getApproved शून्य वापस कर सकता है। यदि टोकन वैध है तो यह self.idToApprovals[_tokenId] लौटाता है। यदि कोई अनुमोदक नहीं है तो वह मान शून्य है।

1@view
2@external
3def isApprovedForAll(_owner: address, _operator: address) -> bool:
4 """
5 @dev जांचता है कि `_operator` `_owner` के लिए एक स्वीकृत ऑपरेटर है या नहीं।
6 @param _owner वह पता जो NFTs का मालिक है।
7 @param _operator वह पता जो मालिक की ओर से कार्य करता है।
8 """
9 return (self.ownerToOperators[_owner])[_operator]

यह फ़ंक्शन जांचता है कि क्या _operator को इस अनुबंध में _owner के सभी टोकन प्रबंधित करने की अनुमति है। क्योंकि कई ऑपरेटर हो सकते हैं, यह एक दो-स्तरीय HashMap है।

सहायक फ़ंक्शन स्थानांतरित करें

ये फ़ंक्शन उन परिचालनों को लागू करते हैं जो टोकन को स्थानांतरित करने या प्रबंधित करने का हिस्सा हैं।

1
2### TRANSFER FUNCTION HELPERS ###
3
4@view
5@internal

यह सजावट, @internal, का अर्थ है कि फ़ंक्शन केवल उसी अनुबंध के भीतर अन्य फ़ंक्शन से ही सुलभ है। परंपरा के अनुसार, इन फ़ंक्शन नामों की शुरुआत भी एक अंडरस्कोर (_) से होती है।

1def _isApprovedOrOwner(_spender: address, _tokenId: uint256) -> bool:
2 """
3 @dev लौटाता है कि दिया गया खर्च करने वाला किसी दिए गए टोकन आईडी को स्थानांतरित कर सकता है या नहीं
4 @param spender क्वेरी करने के लिए खर्च करने वाले का पता
5 @param tokenId स्थानांतरित किए जाने वाले टोकन की uint256 आईडी
6 @return bool कि msg.sender दिए गए टोकन आईडी के लिए स्वीकृत है या नहीं,
7 मालिक का एक ऑपरेटर है, या टोकन का मालिक है
8 """
9 owner: address = self.idToOwner[_tokenId]
10 spenderIsOwner: bool = owner == _spender
11 spenderIsApproved: bool = _spender == self.idToApprovals[_tokenId]
12 spenderIsApprovedForAll: bool = (self.ownerToOperators[owner])[_spender]
13 return (spenderIsOwner or spenderIsApproved) or spenderIsApprovedForAll

किसी पते को टोकन स्थानांतरित करने की अनुमति देने के तीन तरीके हैं:

  1. पता टोकन का मालिक है
  2. पता उस टोकन को खर्च करने के लिए स्वीकृत है
  3. पता टोकन के मालिक के लिए एक ऑपरेटर है

ऊपर दिया गया फ़ंक्शन एक व्यू हो सकता है क्योंकि यह स्थिति को नहीं बदलता है। परिचालन लागत को कम करने के लिए, कोई भी फ़ंक्शन जो एक व्यू हो सकता है, उसे एक व्यू होना चाहिए।

1@internal
2def _addTokenTo(_to: address, _tokenId: uint256):
3 """
4 @dev दिए गए पते पर एक NFT जोड़ें
5 यदि `_tokenId` किसी के स्वामित्व में है तो फेंकता है।
6 """
7 # Throws if `_tokenId` is owned by someone
8 assert self.idToOwner[_tokenId] == ZERO_ADDRESS
9 # Change the owner
10 self.idToOwner[_tokenId] = _to
11 # Change count tracking
12 self.ownerToNFTokenCount[_to] += 1
13
14
15@internal
16def _removeTokenFrom(_from: address, _tokenId: uint256):
17 """
18 @dev दिए गए पते से एक NFT हटाएं
19 यदि `_from` वर्तमान स्वामी नहीं है तो फेंकता है।
20 """
21 # Throws if `_from` is not the current owner
22 assert self.idToOwner[_tokenId] == _from
23 # Change the owner
24 self.idToOwner[_tokenId] = ZERO_ADDRESS
25 # Change count tracking
26 self.ownerToNFTokenCount[_from] -= 1

जब स्थानांतरण में कोई समस्या होती है तो हम कॉल को वापस कर देते हैं।

1@internal
2def _clearApproval(_owner: address, _tokenId: uint256):
3 """
4 @dev दिए गए पते की स्वीकृति साफ़ करें
5 यदि `_owner` वर्तमान स्वामी नहीं है तो फेंकता है।
6 """
7 # Throws if `_owner` is not the current owner
8 assert self.idToOwner[_tokenId] == _owner
9 if self.idToApprovals[_tokenId] != ZERO_ADDRESS:
10 # Reset approvals
11 self.idToApprovals[_tokenId] = ZERO_ADDRESS

केवल आवश्यक होने पर मान बदलें। स्टेट चर भंडारण में रहते हैं। भंडारण में लिखना EVM (एथेरियम Virtual Machine) द्वारा किए जाने वाले सबसे महंगे परिचालनों में से एक है (गैस के संदर्भ में)। इसलिए, इसे कम से कम करना एक अच्छा विचार है, यहां तक कि मौजूदा मूल्य लिखने की भी उच्च लागत होती है।

1@internal
2def _transferFrom(_from: address, _to: address, _tokenId: uint256, _sender: address):
3 """
4 @dev NFT का स्थानांतरण निष्पादित करें।
5 जब तक `msg.sender` वर्तमान स्वामी, एक अधिकृत ऑपरेटर, या इस NFT के लिए स्वीकृत पता न हो, तब तक फेंकता है। (नोट: निजी फ़ंक्शन में `msg.sender` की अनुमति नहीं है इसलिए `_sender` पास करें।)
6 यदि `_to` शून्य पता है तो फेंकता है।
7 यदि `_from` वर्तमान स्वामी नहीं है तो फेंकता है।
8 यदि `_tokenId` एक वैध NFT नहीं है तो फेंकता है।
9 """

हमारे पास यह आंतरिक फ़ंक्शन है क्योंकि टोकन स्थानांतरित करने के दो तरीके हैं (नियमित और सुरक्षित), लेकिन हम चाहते हैं कि कोड में केवल एक ही स्थान हो जहां हम इसे ऑडिटिंग को आसान बनाने के लिए करते हैं।

1 # Check requirements
2 assert self._isApprovedOrOwner(_sender, _tokenId)
3 # Throws if `_to` is the zero address
4 assert _to != ZERO_ADDRESS
5 # Clear approval. Throws if `_from` is not the current owner
6 self._clearApproval(_from, _tokenId)
7 # Remove NFT. Throws if `_tokenId` is not a valid NFT
8 self._removeTokenFrom(_from, _tokenId)
9 # Add NFT
10 self._addTokenTo(_to, _tokenId)
11 # Log the transfer
12 log Transfer(_from, _to, _tokenId)

वाइपर में एक इवेंट उत्सर्जित करने के लिए आप एक log स्टेटमेंट का उपयोग करते हैं (अधिक जानकारी के लिए यहां देखें (opens in a new tab))।

स्थानांतरण फ़ंक्शन

1
2### TRANSFER FUNCTIONS ###
3
4@external
5def transferFrom(_from: address, _to: address, _tokenId: uint256):
6 """
7 @dev जब तक `msg.sender` वर्तमान स्वामी, एक अधिकृत ऑपरेटर, या इस NFT के लिए स्वीकृत पता न हो, तब तक फेंकता है।
8 यदि `_from` वर्तमान स्वामी नहीं है तो फेंकता है।
9 यदि `_to` शून्य पता है तो फेंकता है।
10 यदि `_tokenId` एक वैध NFT नहीं है तो फेंकता है।
11 @notice कॉलर यह पुष्टि करने के लिए ज़िम्मेदार है कि `_to` NFTs प्राप्त करने में सक्षम है अन्यथा वे स्थायी रूप से खो सकते हैं।
12 @param _from NFT का वर्तमान स्वामी।
13 @param _to नया स्वामी।
14 @param _tokenId स्थानांतरित करने के लिए NFT।
15 """
16 self._transferFrom(_from, _to, _tokenId, msg.sender)

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

1@external
2def safeTransferFrom(
3 _from: address,
4 _to: address,
5 _tokenId: uint256,
6 _data: Bytes[1024]=b""
7 ):
8 """
9 @dev एक NFT के स्वामित्व को एक पते से दूसरे पते पर स्थानांतरित करता है।
10 जब तक `msg.sender` वर्तमान स्वामी, एक अधिकृत ऑपरेटर, या इस NFT के लिए स्वीकृत पता न हो, तब तक फेंकता है।
11 यदि `_from` वर्तमान स्वामी नहीं है तो फेंकता है।
12 यदि `_to` शून्य पता है तो फेंकता है।
13 यदि `_tokenId` एक वैध NFT नहीं है तो फेंकता है।
14 यदि `_to` एक स्मार्ट अनुबंध है, तो यह `_to` पर `onERC721Received` को कॉल करता है और यदि वापसी मान `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` नहीं है तो फेंकता है।
15 नोट: bytes4 को पैडिंग के साथ bytes32 द्वारा दर्शाया गया है
16 @param _from NFT का वर्तमान स्वामी।
17 @param _to नया स्वामी।
18 @param _tokenId स्थानांतरित करने के लिए NFT।
19 @param _data बिना किसी निर्दिष्ट प्रारूप के अतिरिक्त डेटा, `_to` पर कॉल में भेजा गया।
20 """
21 self._transferFrom(_from, _to, _tokenId, msg.sender)

पहले स्थानांतरण करना ठीक है क्योंकि यदि कोई समस्या होती है तो हम वैसे भी वापस आ जाएंगे, इसलिए कॉल में किया गया सब कुछ रद्द कर दिया जाएगा।

1 if _to.is_contract: # check if `_to` is a contract address

पहले जांच लें कि पता एक अनुबंध है या नहीं (यदि इसमें कोड है)। यदि नहीं, तो मान लें कि यह एक उपयोगकर्ता पता है और उपयोगकर्ता टोकन का उपयोग करने या इसे स्थानांतरित करने में सक्षम होगा। लेकिन इसे आपको सुरक्षा की झूठी भावना में नहीं आने देना चाहिए। आप safeTransferFrom के साथ भी टोकन खो सकते हैं, यदि आप उन्हें ऐसे पते पर स्थानांतरित करते हैं जिसके लिए किसी को निजी कुंजी नहीं पता है।

1 returnValue: bytes32 = ERC721Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data)

यह देखने के लिए लक्ष्य अनुबंध को कॉल करें कि क्या यह ERC-721 टोकन प्राप्त कर सकता है।

1 # Throws if transfer destination is a contract which does not implement 'onERC721Received'
2 assert returnValue == method_id("onERC721Received(address,address,uint256,bytes)", output_type=bytes32)

यदि गंतव्य एक अनुबंध है, लेकिन एक ऐसा है जो ERC-721 टोकन स्वीकार नहीं करता है (या जिसने इस विशेष स्थानांतरण को स्वीकार नहीं करने का निर्णय लिया है), तो वापस आ जाएं।

1@external
2def approve(_approved: address, _tokenId: uint256):
3 """
4 @dev किसी NFT के लिए स्वीकृत पता सेट करें या उसकी पुष्टि करें। शून्य पता इंगित करता है कि कोई स्वीकृत पता नहीं है।
5 जब तक `msg.sender` वर्तमान NFT स्वामी, या वर्तमान स्वामी का अधिकृत ऑपरेटर न हो, तब तक फेंकता है।
6 यदि `_tokenId` एक वैध NFT नहीं है तो फेंकता है। (नोट: यह EIP में नहीं लिखा गया है)
7 यदि `_approved` वर्तमान स्वामी है तो फेंकता है। (नोट: यह EIP में नहीं लिखा गया है)
8 @param _approved दिए गए NFT आईडी के लिए स्वीकृत किए जाने वाला पता।
9 @param _tokenId स्वीकृत किए जाने वाले टोकन की आईडी।
10 """
11 owner: address = self.idToOwner[_tokenId]
12 # Throws if `_tokenId` is not a valid NFT
13 assert owner != ZERO_ADDRESS
14 # Throws if `_approved` is the current owner
15 assert _approved != owner

परंपरा के अनुसार यदि आप एक अनुमोदक नहीं चाहते हैं तो आप शून्य पते को नियुक्त करते हैं, न कि स्वयं को।

1 # Check requirements
2 senderIsOwner: bool = self.idToOwner[_tokenId] == msg.sender
3 senderIsApprovedForAll: bool = (self.ownerToOperators[owner])[msg.sender]
4 assert (senderIsOwner or senderIsApprovedForAll)

अनुमोदन सेट करने के लिए आप या तो मालिक हो सकते हैं, या मालिक द्वारा अधिकृत ऑपरेटर हो सकते हैं।

1 # Set the approval
2 self.idToApprovals[_tokenId] = _approved
3 log Approval(owner, _approved, _tokenId)
4
5
6@external
7def setApprovalForAll(_operator: address, _approved: bool):
8 """
9 @dev किसी तीसरे पक्ष ("ऑपरेटर") के लिए `msg.sender` की सभी संपत्तियों का प्रबंधन करने के लिए अनुमोदन को सक्षम या अक्षम करता है। यह ApprovalForAll इवेंट भी उत्सर्जित करता है।
10 यदि `_operator` `msg.sender` है तो फेंकता है। (नोट: यह EIP में नहीं लिखा गया है)
11 @notice यह तब भी काम करता है जब प्रेषक के पास उस समय कोई टोकन न हो।
12 @param _operator अधिकृत ऑपरेटरों के सेट में जोड़ने के लिए पता।
13 @param _approved यदि ऑपरेटर स्वीकृत है तो सही, अनुमोदन रद्द करने के लिए गलत।
14 """
15 # Throws if `_operator` is the `msg.sender`
16 assert _operator != msg.sender
17 self.ownerToOperators[msg.sender][_operator] = _approved
18 log ApprovalForAll(msg.sender, _operator, _approved)

नए टोकन मिंट करें और मौजूदा को नष्ट करें

जिस खाते ने अनुबंध बनाया है, वह minter है, जो नए एनएफटीज़ को मिंट करने के लिए अधिकृत सुपर उपयोगकर्ता है। हालांकि, इसे मौजूदा टोकन को बर्न करने की भी अनुमति नहीं है। केवल मालिक, या मालिक द्वारा अधिकृत इकाई ही ऐसा कर सकती है।

1### MINT & BURN FUNCTIONS ###
2
3@external
4def mint(_to: address, _tokenId: uint256) -> bool:

यह फ़ंक्शन हमेशा True लौटाता है, क्योंकि यदि ऑपरेशन विफल हो जाता है तो इसे वापस कर दिया जाता है।

1 """
2 @dev टोकन मिंट करने के लिए फ़ंक्शन
3 यदि `msg.sender` मिंटर नहीं है तो फेंकता है।
4 यदि `_to` शून्य पता है तो फेंकता है।
5 यदि `_tokenId` किसी के स्वामित्व में है तो फेंकता है।
6 @param _to वह पता जो मिंट किए गए टोकन प्राप्त करेगा।
7 @param _tokenId मिंट करने के लिए टोकन आईडी।
8 @return एक बूलियन जो इंगित करता है कि ऑपरेशन सफल था या नहीं।
9 """
10 # Throws if `msg.sender` is not the minter
11 assert msg.sender == self.minter

केवल मिंटर (वह खाता जिसने ERC-721 अनुबंध बनाया है) ही नए टोकन मिंट कर सकता है। यह भविष्य में एक समस्या हो सकती है यदि हम मिंटर की पहचान बदलना चाहते हैं। एक उत्पादन अनुबंध में आप शायद एक ऐसा फ़ंक्शन चाहेंगे जो मिंटर को मिंटर विशेषाधिकार किसी और को स्थानांतरित करने की अनुमति दे।

1 # Throws if `_to` is zero address
2 assert _to != ZERO_ADDRESS
3 # Add NFT. Throws if `_tokenId` is owned by someone
4 self._addTokenTo(_to, _tokenId)
5 log Transfer(ZERO_ADDRESS, _to, _tokenId)
6 return True

परंपरा के अनुसार, नए टोकन का मिंटिंग शून्य पते से स्थानांतरण के रूप में गिना जाता है।

1
2@external
3def burn(_tokenId: uint256):
4 """
5 @dev एक विशिष्ट ERC721 टोकन को बर्न करता है।
6 जब तक `msg.sender` वर्तमान स्वामी, एक अधिकृत ऑपरेटर, या इस NFT के लिए स्वीकृत पता न हो, तब तक फेंकता है।
7 यदि `_tokenId` एक वैध NFT नहीं है तो फेंकता है।
8 @param _tokenId uint256 बर्न किए जाने वाले ERC721 टोकन की आईडी।
9 """
10 # Check requirements
11 assert self._isApprovedOrOwner(msg.sender, _tokenId)
12 owner: address = self.idToOwner[_tokenId]
13 # Throws if `_tokenId` is not a valid NFT
14 assert owner != ZERO_ADDRESS
15 self._clearApproval(owner, _tokenId)
16 self._removeTokenFrom(owner, _tokenId)
17 log Transfer(owner, ZERO_ADDRESS, _tokenId)

कोई भी जिसे टोकन स्थानांतरित करने की अनुमति है, उसे इसे बर्न करने की अनुमति है। जबकि एक बर्न शून्य पते पर स्थानांतरण के बराबर दिखाई देता है, शून्य पता वास्तव में टोकन प्राप्त नहीं करता है। यह हमें टोकन के लिए उपयोग किए गए सभी भंडारण को मुक्त करने की अनुमति देता है, जो लेनदेन की गैस लागत को कम कर सकता है।

इस अनुबंध का उपयोग करना

सॉलिडिटी के विपरीत, वाइपर में वंशानुक्रम नहीं है। यह कोड को स्पष्ट बनाने और इसलिए सुरक्षित करने के लिए एक जानबूझकर डिजाइन विकल्प है। तो अपना खुद का वाइपर ERC-721 अनुबंध बनाने के लिए आप यह अनुबंध (opens in a new tab) लेते हैं और इसे उस व्यावसायिक तर्क को लागू करने के लिए संशोधित करते हैं जो आप चाहते हैं।

निष्कर्ष

समीक्षा के लिए, इस अनुबंध के कुछ सबसे महत्वपूर्ण विचार यहां दिए गए हैं:

  • एक सुरक्षित स्थानांतरण के साथ ERC-721 टोकन प्राप्त करने के लिए, अनुबंधों को ERC721Receiver इंटरफ़ेस लागू करना होगा।
  • भले ही आप सुरक्षित स्थानांतरण का उपयोग करें, टोकन अभी भी फंस सकते हैं यदि आप उन्हें ऐसे पते पर भेजते हैं जिसकी निजी कुंजी अज्ञात है।
  • जब किसी ऑपरेशन में कोई समस्या होती है तो केवल एक विफलता मान वापस करने के बजाय कॉल को revert करना एक अच्छा विचार है।
  • ERC-721 टोकन तब मौजूद होते हैं जब उनका कोई मालिक होता है।
  • एक एनएफटी स्थानांतरित करने के लिए अधिकृत होने के तीन तरीके हैं। आप मालिक हो सकते हैं, एक विशिष्ट टोकन के लिए अनुमोदित हो सकते हैं, या मालिक के सभी टोकन के लिए एक ऑपरेटर हो सकते हैं।
  • पिछले इवेंट्स केवल ब्लॉकचेन के बाहर दिखाई देते हैं। ब्लॉकचेन के अंदर चलने वाला कोड उन्हें देख नहीं सकता है।

अब जाओ और सुरक्षित वाइपर अनुबंध लागू करो।

मेरे और काम के लिए यहाँ देखें (opens in a new tab)

पेज का अंतिम अपडेट: 3 मार्च 2026

क्या यह ट्यूटोरियल सहायक था?