प्रमुख मजकुराकडे जा

Vyper ERC-721 कॉन्ट्रॅक्ट वॉकथ्रू

Vyper
erc-721
Python
नवशिक्या
Ori Pomerantz
१ एप्रिल, २०२१
18 मिनिट वाचन

प्रस्तावना

ERC-721 मानक हे नॉन-फंजिबल टोकन्स (NFT) ची मालकी ठेवण्यासाठी वापरले जाते. ERC-20 टोकन्स एका वस्तू (कमोडिटी) सारखे वागतात, कारण वैयक्तिक टोकन्समध्ये काहीही फरक नसतो. याउलट, ERC-721 टोकन्स अशा मालमत्तेसाठी डिझाइन केलेले आहेत जे समान आहेत परंतु एकसारखे नाहीत, जसे की भिन्न मांजर कार्टून किंवा रिअल इस्टेटच्या वेगवेगळ्या तुकड्यांची मालकी हक्क.

या लेखात आपण Ryuya Nakamura च्या ERC-721 कॉन्ट्रॅक्टचे (opens in a new tab) विश्लेषण करू. हे कॉन्ट्रॅक्ट Vyper (opens in a new tab) मध्ये लिहिलेले आहे, जी एक Python-सारखी कॉन्ट्रॅक्ट भाषा आहे, जी Solidity पेक्षा असुरक्षित कोड लिहिणे अधिक कठीण करण्यासाठी डिझाइन केलेली आहे.

कॉन्ट्रॅक्ट

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

Vyper मध्ये, Python प्रमाणेच, कमेंट्स हॅश (#) ने सुरू होतात आणि ओळीच्या शेवटपर्यंत चालू राहतात. @<keyword> समाविष्ट असलेल्या कमेंट्स NatSpec (opens in a new tab) द्वारे मानवासाठी वाचनीय डॉक्युमेंटेशन तयार करण्यासाठी वापरल्या जातात.

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

ERC-721 इंटरफेस Vyper भाषेमध्ये अंगभूत आहे. तुम्ही कोडची व्याख्या येथे पाहू शकता (opens in a new tab). इंटरफेसची व्याख्या Vyper ऐवजी Python मध्ये लिहिलेली आहे, कारण इंटरफेस केवळ ब्लॉकचेनमध्येच नव्हे, तर बाह्य क्लायंटकडून ब्लॉकचेनला व्यवहार पाठवताना देखील वापरले जातात, जे Python मध्ये लिहिलेले असू शकतात.

पहिली ओळ इंटरफेस इम्पोर्ट करते आणि दुसरी ओळ नमूद करते की आम्ही येथे त्याची अंमलबजावणी करत आहोत.

ERC721Receiver इंटरफेस

1# safeTransferFrom() द्वारे कॉल केलेल्या कॉन्ट्रॅक्टसाठी इंटरफेस
2interface ERC721Receiver:
3 def onERC721Received(

ERC-721 दोन प्रकारच्या ट्रान्सफरला समर्थन देते:

  • transferFrom, जे प्रेषकाला (sender) कोणतेही डेस्टिनेशन ॲड्रेस निर्दिष्ट करण्याची परवानगी देते आणि हस्तांतरणाची जबाबदारी प्रेषकावर टाकते. याचा अर्थ असा की आपण अवैध ॲड्रेसवर हस्तांतरण करू शकता, अशा परिस्थितीत NFT कायमचा गमावला जातो.
  • safeTransferFrom, जे डेस्टिनेशन ॲड्रेस हे कॉन्ट्रॅक्ट आहे की नाही हे तपासते. तसे असल्यास, ERC-721 कॉन्ट्रॅक्ट प्राप्त करणाऱ्या कॉन्ट्रॅक्टला विचारतो की त्याला NFT प्राप्त करायचा आहे का.

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 आहे, याचा अर्थ ते ब्लॉकचेनची स्थिती (state) वाचू शकते, परंतु त्यात बदल करू शकत नाही.

इव्हेंट्स

इव्हेंट्स (opens in a new tab) हे ब्लॉकचेनच्या बाहेरील वापरकर्त्यांना आणि सर्व्हरना इव्हेंट्सबद्दल माहिती देण्यासाठी उत्सर्जित केले जातात. लक्षात घ्या की इव्हेंट्सची सामग्री ब्लॉकचेनवरील कॉन्ट्रॅक्टसाठी उपलब्ध नसते.

1# @dev कोणत्याही NFT ची मालकी कोणत्याही यंत्रणेद्वारे बदलल्यावर उत्सर्जित होते. हा इव्हेंट NFTs
2# तयार झाल्यावर (`from` == 0) आणि नष्ट झाल्यावर (`to` == 0) उत्सर्जित होतो. अपवाद: कॉन्ट्रॅक्ट निर्मिती दरम्यान, कितीही
3# NFTs ट्रान्सफर उत्सर्जित न करता तयार आणि नियुक्त केले जाऊ शकतात. कोणत्याही
4# हस्तांतरणाच्या वेळी, त्या NFT साठी मंजूर केलेला पत्ता (असल्यास) 'काहीही नाही' वर रीसेट केला जातो.
5# @param _from NFT चा प्रेषक (पत्ता शून्य असल्यास तो टोकन निर्मिती दर्शवतो).
6# @param _to NFT चा प्राप्तकर्ता (पत्ता शून्य असल्यास तो टोकन नष्ट करणे दर्शवतो).
7# @param _tokenId हस्तांतरित झालेला NFT.
8event Transfer:
9 sender: indexed(address)
10 receiver: indexed(address)
11 tokenId: indexed(uint256)
सर्व दाखवा

हे ERC-20 ट्रान्सफर इव्हेंटसारखेच आहे, फक्त आपण रकमेऐवजी tokenId कळवतो. कोणीही शून्य पत्त्याचा मालक नाही, म्हणून प्रथेनुसार आपण त्याचा वापर टोकनची निर्मिती आणि नाश कळवण्यासाठी करतो.

1# @dev NFT साठी मंजूर केलेला पत्ता बदलला किंवा पुन्हा निश्चित केल्यावर हे उत्सर्जित होते. शून्य
2# पत्ता सूचित करतो की कोणताही मंजूर पत्ता नाही. जेव्हा एखादा ट्रान्सफर इव्हेंट उत्सर्जित होतो, तेव्हा हे देखील
3# सूचित करते की त्या NFT साठी मंजूर केलेला पत्ता (असल्यास) 'काहीही नाही' वर रीसेट केला जातो.
4# @param _owner NFT चा मालक.
5# @param _approved आम्ही मंजूर करत असलेला पत्ता.
6# @param _tokenId आम्ही मंजूर करत असलेला NFT.
7event Approval:
8 owner: indexed(address)
9 approved: indexed(address)
10 tokenId: indexed(uint256)
सर्व दाखवा

ERC-721 मंजुरी ERC-20 अलाउन्स सारखीच आहे. एका विशिष्ट पत्त्याला एक विशिष्ट टोकन हस्तांतरित करण्याची परवानगी दिली जाते. यामुळे करारांना टोकन स्वीकारल्यावर प्रतिसाद देण्यासाठी एक यंत्रणा मिळते. कॉन्ट्रॅक्ट इव्हेंट ऐकू शकत नाहीत, म्हणून जर तुम्ही फक्त त्यांना टोकन हस्तांतरित केले तर त्यांना त्याबद्दल 'माहित' होत नाही. या प्रकारे मालक प्रथम एक मंजुरी सादर करतो आणि नंतर कॉन्ट्रॅक्टला विनंती पाठवतो: 'मी तुम्हाला टोकन X हस्तांतरित करण्यासाठी मंजूर केले आहे, कृपया ... करा'.

ERC-721 मानकाला ERC-20 मानकासारखे बनवण्यासाठी ही एक डिझाइन निवड आहे. कारण ERC-721 टोकन फंजिबल नाहीत, एक कॉन्ट्रॅक्ट टोकनच्या मालकीकडे पाहून ओळखू शकतो की त्याला एक विशिष्ट टोकन मिळाले आहे.

1# @dev मालकासाठी ऑपरेटर सक्षम किंवा अक्षम केल्यावर हे उत्सर्जित होते. ऑपरेटर
2# मालकाच्या सर्व NFTs चे व्यवस्थापन करू शकतो.
3# @param _owner NFT चा मालक.
4# @param _operator पत्ता ज्यावर आम्ही ऑपरेटर हक्क सेट करत आहोत.
5# @param _approved ऑपरेटर हक्कांची स्थिती (ऑपरेटर हक्क दिल्यास 'true' आणि
6# रद्द केल्यास 'false').
7event ApprovalForAll:
8 owner: indexed(address)
9 operator: indexed(address)
10 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]

Ethereum मध्ये वापरकर्ता आणि कॉन्ट्रॅक्ट ओळख 160-बिट पत्त्यांद्वारे दर्शविली जाते. हे दोन व्हेरिएबल्स टोकन आयडी वरून त्यांच्या मालकांना आणि त्यांना हस्तांतरित करण्यास मंजूर असलेल्यांना (प्रत्येकासाठी जास्तीत जास्त एक) मॅप करतात. Ethereum मध्ये, अनइनिशियलाइज्ड डेटा नेहमी शून्य असतो, म्हणून जर मालक किंवा मंजूर हस्तांतरणकर्ता नसेल तर त्या टोकनसाठी मूल्य शून्य असते.

1# @dev मालकाच्या पत्त्यावरून त्याच्या टोकनच्या संख्येवर मॅपिंग.
2ownerToNFTokenCount: HashMap[address, uint256]

हे व्हेरिएबल प्रत्येक मालकासाठी टोकनची संख्या ठेवते. मालकांकडून टोकनपर्यंत कोणतेही मॅपिंग नाही, म्हणून विशिष्ट मालकाचे टोकन ओळखण्याचा एकमेव मार्ग म्हणजे ब्लॉकचेनच्या इव्हेंट इतिहासात मागे पाहणे आणि योग्य Transfer इव्हेंट पाहणे. आपल्याकडे सर्व NFTs आहेत आणि आपल्याला वेळेत आणखी मागे पाहण्याची गरज नाही हे जाणून घेण्यासाठी आपण या व्हेरिएबलचा वापर करू शकतो.

लक्षात घ्या की हा अल्गोरिदम फक्त वापरकर्ता इंटरफेस आणि बाह्य सर्व्हरसाठी काम करतो. ब्लॉकचेनवर चालणारा कोड स्वतः मागील इव्हेंट वाचू शकत नाही.

1# @dev मालकाच्या पत्त्यावरून ऑपरेटर पत्त्यांच्या मॅपिंगवर मॅपिंग.
2ownerToOperators: HashMap[address, HashMap[address, bool]]

एका खात्यात एकापेक्षा जास्त ऑपरेटर असू शकतात. त्यांचा मागोवा ठेवण्यासाठी एक साधे HashMap पुरेसे नाही, कारण प्रत्येक की एकाच मूल्याकडे नेते. त्याऐवजी, तुम्ही मूल्य म्हणून HashMap[address, bool] वापरू शकता. डीफॉल्टनुसार प्रत्येक पत्त्यासाठी मूल्य False असते, याचा अर्थ तो ऑपरेटर नाही. तुम्ही आवश्यकतेनुसार मूल्ये True वर सेट करू शकता.

1# @dev मिन्टरचा पत्ता, जो टोकन मिंट करू शकतो
2minter: address

नवीन टोकन कोणत्यातरी प्रकारे तयार करावे लागतात. या कॉन्ट्रॅक्टमध्ये एकच संस्था आहे जिला तसे करण्याची परवानगी आहे, ती म्हणजे minter. उदाहरणार्थ, एका खेळासाठी हे पुरेसे असण्याची शक्यता आहे. इतर उद्देशांसाठी, अधिक क्लिष्ट व्यवसाय तर्क तयार करणे आवश्यक असू शकते.

1# @dev इंटरफेस आयडी वरून ते समर्थित आहे की नाही याबद्दलच्या bool वर मॅपिंग
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__():

Vyper मध्ये, Python प्रमाणेच, कन्स्ट्रक्टर फंक्शनला __init__ म्हणतात.

1 """
2 @dev कॉन्ट्रॅक्ट कन्स्ट्रक्टर.
3 """

Python मध्ये, आणि Vyper मध्ये, तुम्ही एक मल्टी-लाइन स्ट्रिंग (जी """ ने सुरू होते आणि संपते) निर्दिष्ट करून आणि कोणत्याही प्रकारे तिचा वापर न करून देखील एक कमेंट तयार करू शकता. या कमेंट्समध्ये NatSpec (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> वापरता (पुन्हा, Python प्रमाणेच).

व्ह्यू फंक्शन्स

ही अशी फंक्शन्स आहेत जी ब्लॉकचेनची स्थिती बदलत नाहीत, आणि म्हणून जर त्यांना बाह्यरित्या कॉल केले तर ते विनामूल्य कार्यान्वित केले जाऊ शकतात. जर व्ह्यू फंक्शन्सना कॉन्ट्रॅक्टद्वारे कॉल केले गेले तर त्यांना अजूनही प्रत्येक नोडवर कार्यान्वित करावे लागते आणि म्हणून गॅस खर्च येतो.

1@view
2@external

फंक्शनच्या व्याख्येपूर्वी हे कीवर्ड जे ऍट चिन्हासह (@) सुरू होतात, त्यांना डेकोरेशन्स म्हणतात. ते फंक्शन कोणत्या परिस्थितीत कॉल केले जाऊ शकते हे निर्दिष्ट करतात.

  • @view निर्दिष्ट करते की हे फंक्शन एक व्ह्यू आहे.
  • @external निर्दिष्ट करते की हे विशिष्ट फंक्शन व्यवहार आणि इतर कॉन्ट्रॅक्टद्वारे कॉल केले जाऊ शकते.
1def supportsInterface(_interfaceID: bytes32) -> bool:

Python च्या उलट, Vyper ही एक स्टॅटिक टाइप केलेली भाषा (opens in a new tab) आहे. तुम्ही डेटा प्रकार (opens in a new tab) ओळखल्याशिवाय व्हेरिएबल किंवा फंक्शन पॅरामीटर घोषित करू शकत नाही. या प्रकरणात इनपुट पॅरामीटर bytes32 आहे, जे 256-बिट मूल्य आहे (256 बिट्स हे Ethereum व्हर्च्युअल मशीन चा मूळ शब्द आकार आहे). आउटपुट एक बुलियन मूल्य आहे. प्रथेनुसार, फंक्शन पॅरामीटर्सची नावे अंडरस्कोर (_) ने सुरू होतात.

1 """
2 @dev इंटरफेस ओळख ERC-165 मध्ये निर्दिष्ट आहे.
3 @param _interfaceID इंटरफेसचा आयडी
4 """
5 return self.supportedInterfaces[_interfaceID]

self.supportedInterfaces HashMap मधून मूल्य परत करा, जे कन्स्ट्रक्टर (__init__) मध्ये सेट केलेले आहे.

1### व्ह्यू फंक्शन्स ###
2

ही व्ह्यू फंक्शन्स आहेत जी टोकनबद्दलची माहिती वापरकर्त्यांना आणि इतर कॉन्ट्रॅक्टसना उपलब्ध करून देतात.

1@view
2@external
3def balanceOf(_owner: address) -> uint256:
4 """
5 @dev `_owner` च्या मालकीच्या NFTs ची संख्या परत करते.
6 `_owner` शून्य पत्ता असल्यास थ्रो करते. शून्य पत्त्याला नियुक्त केलेले NFTs अवैध मानले जातात.
7 @param _owner ज्या पत्त्यासाठी बॅलन्सची चौकशी करायची आहे.
8 """
9 assert _owner != ZERO_ADDRESS
सर्व दाखवा

ही ओळ asserts (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 # `_tokenId` वैध NFT नसल्यास थ्रो करते
13 assert owner != ZERO_ADDRESS
14 return owner
सर्व दाखवा

Ethereum व्हर्च्युअल मशीनमध्ये (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 # `_tokenId` वैध 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### हस्तांतरण फंक्शन सहाय्यक ###
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 # `_tokenId` कोणाच्यातरी मालकीचा असल्यास थ्रो करते
8 assert self.idToOwner[_tokenId] == ZERO_ADDRESS
9 # मालक बदला
10 self.idToOwner[_tokenId] = _to
11 # गणना ट्रॅकिंग बदला
12 self.ownerToNFTokenCount[_to] += 1
13
14
15@internal
16def _removeTokenFrom(_from: address, _tokenId: uint256):
17 """
18 @dev दिलेल्या पत्त्यावरून NFT काढा
19 `_from` सध्याचा मालक नसल्यास थ्रो करते.
20 """
21 # `_from` सध्याचा मालक नसल्यास थ्रो करते
22 assert self.idToOwner[_tokenId] == _from
23 # मालक बदला
24 self.idToOwner[_tokenId] = ZERO_ADDRESS
25 # गणना ट्रॅकिंग बदला
26 self.ownerToNFTokenCount[_from] -= 1
सर्व दाखवा

जेव्हा हस्तांतरणामध्ये समस्या येते तेव्हा आम्ही कॉल परत घेतो.

1@internal
2def _clearApproval(_owner: address, _tokenId: uint256):
3 """
4 @dev दिलेल्या पत्त्याची मंजुरी साफ करा
5 `_owner` सध्याचा मालक नसल्यास थ्रो करते.
6 """
7 # `_owner` सध्याचा मालक नसल्यास थ्रो करते
8 assert self.idToOwner[_tokenId] == _owner
9 if self.idToApprovals[_tokenId] != ZERO_ADDRESS:
10 # मंजुरी रीसेट करा
11 self.idToApprovals[_tokenId] = ZERO_ADDRESS
सर्व दाखवा

आवश्यक असल्यास फक्त मूल्य बदला. स्टेट व्हेरिएबल्स स्टोरेजमध्ये राहतात. स्टोरेजमध्ये लिहिणे ही EVM (Ethereum व्हर्च्युअल मशीन) च्या सर्वात महागड्या क्रियांपैकी एक आहे (gas च्या बाबतीत). म्हणून, ते कमी करणे ही एक चांगली कल्पना आहे, अगदी विद्यमान मूल्य लिहिण्याचा खर्चही जास्त आहे.

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

आपल्याकडे हे अंतर्गत फंक्शन आहे कारण टोकन हस्तांतरित करण्याचे दोन मार्ग आहेत (नियमित आणि सुरक्षित), परंतु आम्हाला कोडमध्ये फक्त एकच स्थान हवे आहे जेथे आपण ते करतो जेणेकरून ऑडिट करणे सोपे होईल.

1 # आवश्यकता तपासा
2 assert self._isApprovedOrOwner(_sender, _tokenId)
3 # `_to` शून्य पत्ता असल्यास थ्रो करते
4 assert _to != ZERO_ADDRESS
5 # मंजुरी साफ करा. `_from` सध्याचा मालक नसल्यास थ्रो करते
6 self._clearApproval(_from, _tokenId)
7 # NFT काढा. `_tokenId` वैध NFT नसल्यास थ्रो करते
8 self._removeTokenFrom(_from, _tokenId)
9 # NFT जोडा
10 self._addTokenTo(_to, _tokenId)
11 # हस्तांतरण लॉग करा
12 log Transfer(_from, _to, _tokenId)
सर्व दाखवा

Vyper मध्ये इव्हेंट उत्सर्जित करण्यासाठी तुम्ही log स्टेटमेंट वापरता (अधिक तपशिलांसाठी येथे पहा (opens in a new tab)).

हस्तांतरण फंक्शन्स

1
2### हस्तांतरण फंक्शन्स ###
3
4@external
5def transferFrom(_from: address, _to: address, _tokenId: uint256):
6 """
7 @dev `msg.sender` सध्याचा मालक, अधिकृत ऑपरेटर किंवा या NFT साठी मंजूर
8 पत्ता नसल्यास थ्रो करते.
9 `_from` सध्याचा मालक नसल्यास थ्रो करते.
10 `_to` शून्य पत्ता असल्यास थ्रो करते.
11 `_tokenId` वैध NFT नसल्यास थ्रो करते.
12 @notice `_to` NFTs प्राप्त करण्यास सक्षम आहे याची पुष्टी करण्याची जबाबदारी कॉलरची आहे अन्यथा
13 ते कायमचे गमावले जाऊ शकतात.
14 @param _from NFT चा सध्याचा मालक.
15 @param _to नवीन मालक.
16 @param _tokenId हस्तांतरित करायचा NFT.
17 """
18 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 पत्ता नसल्यास थ्रो करते.
12 `_from` सध्याचा मालक नसल्यास थ्रो करते.
13 `_to` शून्य पत्ता असल्यास थ्रो करते.
14 `_tokenId` वैध NFT नसल्यास थ्रो करते.
15 जर `_to` एक स्मार्ट कॉन्ट्रॅक्ट असेल, तर ते `_to` वर `onERC721Received` कॉल करते आणि
16 परत आलेले मूल्य `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` नसल्यास थ्रो करते.
17 टीप: bytes4 पॅडिंगसह bytes32 द्वारे दर्शविले जाते
18 @param _from NFT चा सध्याचा मालक.
19 @param _to नवीन मालक.
20 @param _tokenId हस्तांतरित करायचा NFT.
21 @param _data कोणताही निर्दिष्ट स्वरूप नसलेला अतिरिक्त डेटा, `_to` ला कॉलमध्ये पाठवला जातो.
22 """
23 self._transferFrom(_from, _to, _tokenId, msg.sender)
सर्व दाखवा

प्रथम हस्तांतरण करणे ठीक आहे कारण जर काही समस्या आली तर आपण तरीही परत घेणार आहोत, त्यामुळे कॉलमध्ये केलेले सर्वकाही रद्द होईल.

1 if _to.is_contract: # `_to` हा कॉन्ट्रॅक्ट पत्ता आहे की नाही हे तपासा

प्रथम पत्ता कॉन्ट्रॅक्ट आहे की नाही हे तपासा (त्यात कोड आहे का). नसल्यास, तो वापरकर्त्याचा पत्ता आहे असे समजा आणि वापरकर्ता टोकन वापरू शकेल किंवा हस्तांतरित करू शकेल. पण ते तुम्हाला खोट्या सुरक्षिततेच्या भावनेत अडकू देऊ नका. तुम्ही टोकन गमावू शकता, अगदी safeTransferFrom सह देखील, जर तुम्ही त्यांना अशा पत्त्यावर हस्तांतरित केले ज्याची खाजगी की कोणालाही माहित नाही.

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

लक्ष्य कॉन्ट्रॅक्टला ERC-721 टोकन प्राप्त करू शकतो की नाही हे पाहण्यासाठी कॉल करा.

1# हस्तांतरणाचे गंतव्यस्थान असा कॉन्ट्रॅक्ट असल्यास जो '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 # `_tokenId` वैध NFT नसल्यास थ्रो करते
13 assert owner != ZERO_ADDRESS
14 # `_approved` सध्याचा मालक असल्यास थ्रो करते
15 assert _approved != owner
सर्व दाखवा

प्रथेनुसार, जर तुम्हाला मंजूर करणारा नको असेल तर तुम्ही शून्य पत्ता नियुक्त करता, स्वतःला नाही.

1 # आवश्यकता तपासा
2 senderIsOwner: bool = self.idToOwner[_tokenId] == msg.sender
3 senderIsApprovedForAll: bool = (self.ownerToOperators[owner])[msg.sender]
4 assert (senderIsOwner or senderIsApprovedForAll)

मंजुरी सेट करण्यासाठी तुम्ही एकतर मालक असू शकता किंवा मालकाने अधिकृत केलेला ऑपरेटर असू शकता.

1 # मंजुरी सेट करा
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` च्या सर्व मालमत्तेचे व्यवस्थापन
10 करण्यासाठी मंजुरी सक्षम किंवा अक्षम करते. हे ApprovalForAll इव्हेंट देखील उत्सर्जित करते.
11 `_operator` हा `msg.sender` असल्यास थ्रो करते. (टीप: हे EIP मध्ये लिहिलेले नाही)
12 @notice प्रेषकाकडे त्यावेळी कोणतेही टोकन नसले तरीही हे काम करते.
13 @param _operator अधिकृत ऑपरेटर्सच्या सेटमध्ये जोडायचा पत्ता.
14 @param _approved ऑपरेटर मंजूर असल्यास True, मंजुरी रद्द करण्यासाठी false.
15 """
16 # `_operator` हा `msg.sender` असल्यास थ्रो करते
17 assert _operator != msg.sender
18 self.ownerToOperators[msg.sender][_operator] = _approved
19 log ApprovalForAll(msg.sender, _operator, _approved)
सर्व दाखवा

नवीन टोकन मिंट करणे आणि विद्यमान टोकन नष्ट करणे

ज्या खात्याने कॉन्ट्रॅक्ट तयार केले आहे तो minter आहे, जो नवीन NFTs मिंट करण्यासाठी अधिकृत सुपर वापरकर्ता आहे. तथापि, त्यालाही विद्यमान टोकन बर्न करण्याची परवानगी नाही. फक्त मालक, किंवा मालकाने अधिकृत केलेली संस्था, ते करू शकते.

1### मिंट आणि बर्न फंक्शन्स ###
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 # `msg.sender` मिन्टर नसल्यास थ्रो करते
11 assert msg.sender == self.minter
सर्व दाखवा

फक्त मिन्टर (ज्या खात्याने ERC-721 कॉन्ट्रॅक्ट तयार केले आहे) नवीन टोकन मिंट करू शकतो. भविष्यात जर आपल्याला मिन्टरची ओळख बदलायची असेल तर ही एक समस्या असू शकते. एका प्रोडक्शन कॉन्ट्रॅक्टमध्ये तुम्हाला कदाचित असे फंक्शन हवे असेल जे मिन्टरला मिन्टरचे विशेषाधिकार दुसऱ्या कोणालातरी हस्तांतरित करण्याची परवानगी देईल.

1 # `_to` शून्य पत्ता असल्यास थ्रो करते
2 assert _to != ZERO_ADDRESS
3 # NFT जोडा. `_tokenId` कोणाच्यातरी मालकीचा असल्यास थ्रो करते
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 पत्ता नसल्यास थ्रो करते.
8 `_tokenId` वैध NFT नसल्यास थ्रो करते.
9 @param _tokenId बर्न करायच्या ERC721 टोकनचा uint256 आयडी.
10 """
11 # आवश्यकता तपासा
12 assert self._isApprovedOrOwner(msg.sender, _tokenId)
13 owner: address = self.idToOwner[_tokenId]
14 # `_tokenId` वैध NFT नसल्यास थ्रो करते
15 assert owner != ZERO_ADDRESS
16 self._clearApproval(owner, _tokenId)
17 self._removeTokenFrom(owner, _tokenId)
18 log Transfer(owner, ZERO_ADDRESS, _tokenId)
सर्व दाखवा

ज्यालाही टोकन हस्तांतरित करण्याची परवानगी आहे त्याला ते बर्न करण्याची परवानगी आहे. बर्न हे शून्य पत्त्यावर हस्तांतरणासारखे दिसत असले तरी, शून्य पत्त्याला प्रत्यक्षात टोकन मिळत नाही. हे आपल्याला टोकनसाठी वापरलेले सर्व स्टोरेज मोकळे करण्याची परवानगी देते, ज्यामुळे व्यवहाराचा गॅस खर्च कमी होऊ शकतो.

हे कॉन्ट्रॅक्ट वापरणे

Solidity च्या उलट, Vyper मध्ये इनहेरिटन्स नाही. कोड अधिक स्पष्ट आणि त्यामुळे सुरक्षित करणे सोपे करण्यासाठी ही एक जाणीवपूर्वक केलेली डिझाइन निवड आहे. म्हणून तुमचा स्वतःचा Vyper ERC-721 कॉन्ट्रॅक्ट तयार करण्यासाठी तुम्ही हा कॉन्ट्रॅक्ट (opens in a new tab) घ्या आणि तुम्हाला हव्या असलेल्या व्यवसाय तर्काची अंमलबजावणी करण्यासाठी त्यात बदल करा.

निष्कर्ष

पुनरावलोकनासाठी, या कॉन्ट्रॅक्टमधील काही सर्वात महत्त्वाचे विचार येथे आहेत:

  • सुरक्षित हस्तांतरणासह ERC-721 टोकन प्राप्त करण्यासाठी, कॉन्ट्रॅक्ट्सना ERC721Receiver इंटरफेस लागू करावा लागतो.
  • तुम्ही सुरक्षित हस्तांतरण वापरत असलात तरीही, टोकन अडकू शकतात जर तुम्ही त्यांना अशा पत्त्यावर पाठवले ज्याची खाजगी की अज्ञात आहे.
  • जेव्हा ऑपरेशनमध्ये समस्या येते तेव्हा फक्त अयशस्वी मूल्य परत करण्याऐवजी कॉल revert करणे ही एक चांगली कल्पना आहे.
  • ERC-721 टोकन तेव्हा अस्तित्वात असतात जेव्हा त्यांचा मालक असतो.
  • NFT हस्तांतरित करण्यासाठी अधिकृत होण्याचे तीन मार्ग आहेत. तुम्ही मालक असू शकता, विशिष्ट टोकनसाठी मंजूर असू शकता, किंवा मालकाच्या सर्व टोकनसाठी ऑपरेटर असू शकता.
  • मागील इव्हेंट फक्त ब्लॉकचेनच्या बाहेर दिसतात. ब्लॉकचेनच्या आत चालणारा कोड ते पाहू शकत नाही.

आता जा आणि सुरक्षित Vyper कॉन्ट्रॅक्ट्स लागू करा.

माझ्या कामाबद्दल अधिक माहितीसाठी येथे पहा (opens in a new tab).

पृष्ठ अखेरचे अद्यतन: २२ ऑगस्ट, २०२५

हे मार्गदर्शन उपयुक्त होते का?