एनएफटी बूम हुआ है, और अभी भी हो रहा है (जुलाई 2022 में इस लेखन के अनुसार)। इथरस्कैन में एक आसान खोज उपयोगिता है, जो इसके आसान सत्यापन और डीकंपलिंग सुविधाओं के साथ, आपको तुलना करने के लिए कई ERC721 के कोड को देखने देती है। कई अच्छी तरह से डिज़ाइन किए गए अनुबंधों के साथ, हम यह भी देख सकते हैं कि कई लोग एक ही गलती को बार-बार करते हैं। इस लेख में मैं एनएफटी के लिए सबसे आम "डिजाइन विफल" में से 4 के बारे में अपनी राय दूंगा, जो कि मैं आमतौर पर ईथरस्कैन पर एनएफटी अनुबंधों को देखते समय नोटिस करता हूं।
ध्यान दें कि यह लेख मुख्य रूप से ईवीएम-संगत ब्लॉकचेन को ध्यान में रखते हुए लिखा गया था, लेकिन कई बिंदु लागू होते हैं या अन्य नेटवर्क पर भी कुछ सादृश्य या समकक्ष होते हैं।
कृपया अपमान न करें यदि आपने कुछ ऐसा किया है जिसे मैं "डिज़ाइन विफल" कहता हूं। ये मेरे विचार हैं, और इसके अलावा एक डेवलपर के रूप में मैं इन गैस-महंगे नेटवर्क-भीड़ वाले समय में गैस की लागत को बचाने की आवश्यकता को पूरी तरह से समझता हूं। एक स्वतंत्र सलाहकार के रूप में मेरे दृष्टिकोण पर विचार करें; एक ग्राहक जो विकास सहायता के लिए हजारों डॉलर खर्च कर सकता है, निश्चित रूप से उत्कृष्टता की खोज में तैनाती के लिए एक अतिरिक्त सौ निर्धारित कर सकता है।
यह निश्चित रूप से एथेरियम श्रृंखला की बात कर रहा है, जो इस लेखन के रूप में सबसे महंगी है; बहुभुज कम है, और सोलाना (एक गैर-ईवीएम) जैसी अन्य श्रृंखलाएं और भी कम हैं। मेरा कहना है कि यदि धन उपलब्ध है, तो उच्च गुणवत्ता वाले कार्यान्वयन के लाभ अतिरिक्त लागत के लायक हो सकते हैं।
यह बेहद सामान्य है, लेकिन जब मैं इसे देखता हूं, तो यह मेरी आंखों के लिए अनुबंध को ध्वजांकित करता है, जैसा कि शौकिया तौर पर किया जाता है। निष्पक्ष होने के लिए, वैध और समझने योग्य प्रेरणाएँ हैं। एक के लिए, कई नेटवर्क पर अनुबंधों को तैनात करना और प्रबंधित करना बहुत महंगा हो गया है, और उन लागतों को बचाने के लिए दर्द उठाया गया है। और, सादगी के लिए, कोई सोच सकता है, क्यों न खनन और बिक्री के तर्क को अनुबंध के साथ ही रखा जाए?
लेकिन यह वास्तव में एक अच्छा विचार नहीं है। अनुबंध स्वयं तर्क के नेटवर्क का अपरिवर्तनीय केंद्र होना चाहिए, लेकिन सीधे पैसे को संभाल कर अपने हाथों को गंदा नहीं करना चाहिए। इसमें ईआरसी721 कार्यान्वयन के समान अनुबंध कोड में सीधे बिक्री, बिक्री समय, श्वेतसूचीकरण आदि शामिल हैं। बिक्री तर्क और मूल तर्क कसकर जुड़े हुए हैं।
जबकि गैस की लागत पर बचत सभी तर्कों को एक अनुबंध में समेटने का सबसे अच्छा और सबसे समझने योग्य कारण हो सकता है, मुझे लगता है कि, सभी बातों पर विचार किया जाता है, इस डिज़ाइन शॉर्टकट को लागू नहीं करने के बहुत बेहतर कारण हैं। आपका मुख्य अनुबंध तर्क पत्थर में स्थापित एकमात्र चीज होना चाहिए, और ज्यादातर मामलों में मानक को बहुत, अच्छी तरह से ... मानक तरीके से लागू किया जाएगा। कई क्लोन एक दूसरे के लगभग क्लोन हैं (या हो सकते हैं)। आपकी खनन रणनीति, मूल्य निर्धारण (यदि आप टकसाल बेच रहे हैं) - इस प्रकार की चीजों को अलग किया जाना चाहिए। यह आपके अनुबंध को इस तरह से लचीला बनाने की अनुमति देता है जो उपयोगकर्ता के विश्वास को नुकसान नहीं पहुंचाता है। डिकूपल्ड डिजाइन और एकल-जिम्मेदारी सिद्धांत। साइड नोट: मुझे लगता है कि यह ERC721 अनुबंध में ही आपूर्ति (यानी अधिकतम आपूर्ति) को प्रतिबंधित करने के लिए समझ में आता है, जब तक कि इसे किसी व्यवस्थापक भूमिका वाले किसी व्यक्ति द्वारा संशोधित किया जा सकता है।
एक टोकन अनुबंध को किसी प्रकार के अभिगम नियंत्रण की आवश्यकता होती है, क्योंकि ऐसे कार्य होते हैं (जैसे आपूर्ति मापदंडों के लिए कुछ भी करना या करना) जो केवल अनुमत पते पर उपलब्ध होना चाहिए। इसे पूरा करने का सबसे आसान तरीका एक स्वामित्व मॉडल का उपयोग करना है (आमतौर पर ओपनजेपेलिन के स्वामित्व योग्य अनुबंध का उपयोग करना क्योंकि इस तरह की मूलभूत आवश्यकता के लिए पहिया का पुन: आविष्कार क्यों करें)। लेकिन मैं निम्नलिखित कारणों से इसके बजाय भूमिका-आधारित अभिगम नियंत्रण का उपयोग करने का दृढ़ता से सुझाव दूंगा। ओनेबल (या कुछ इसी तरह) का उपयोग करने के पीछे प्रेरणा शायद सादगी (और गैस की लागत पर बचत) है, जो सतह पर ठीक है। आप यह भी "जान" सकते हैं कि आप (या आपका ग्राहक) अनुबंध का प्रबंधन करने वाले "हमेशा" अकेले रहेंगे। फ्यूचर-प्रूफिंग बेहतर है, जब लागत कम हो; और ओनेबल मॉडल की तुलना में भूमिका-आधारित सुरक्षा की जटिलता (जैसे ओपनजेपेलिन का IAccessControl) ईमानदारी से थोड़ा अधिक जटिल (और महंगा) है। यदि गैस की लागत अभी भी एक मुद्दा है, तो आप हमेशा भूमिका-आधारित सुरक्षा कोड (चाहे वह OpenZeppelin, या अपना हो) को केवल वही कर सकते हैं जिसकी आपको आवश्यकता है। लेकिन भूमिका-आधारित का उपयोग करने का अधिक महत्वपूर्ण कारण यह है कि यह आपको ERC721 अनुबंध से ही कार्यक्षमता (जैसा कि पिछले बिंदु, बिक्री और मूल्य निर्धारण की जानकारी में) को अलग करने में सक्षम बनाता है। यह आपको पूर्ण व्यवस्थापक अनुमतियों की अनुमति के बिना, इसे "मिन्टर" भूमिका सौंपकर एक अलग अनुबंध को मिन्टर के रूप में नामित करने की अनुमति देता है। जबकि व्यवस्थापक (या व्यवस्थापक, जो शायद इंसान हैं और अनुबंध नहीं हैं) के पास अभी भी उच्च-स्तरीय अनुमतियां हैं (जैसे अनुमतियां निकालना और जोड़ना)। जब मिन्टर (उदाहरण के लिए) अब आपकी ज़रूरतों को पूरा नहीं करता है, तो कोई बस अपने खनन अधिकारों को रद्द करके, और एक नई खनन रणनीति को लागू करने वाले एक नए अनुबंध के लिए खनन अधिकार प्रदान करके इसे सेवानिवृत्त कर देता है; यह मॉड्यूलर, सुविधाजनक और सुरक्षित है। परियोजनाओं के विशेष उपयोग के मामलों के आधार पर, खनन के अलावा अन्य गतिविधियों को उसी तरह से संभाला जा सकता है।
कई टोकन (या सामान्य रूप से अनुबंध) या तो ERC-165 को लागू नहीं करते हैं, या इसे बेहतर तरीके से लागू नहीं करते हैं। ईआरसी-165, मेरे विचार में, अंतरसंचालनीयता के बारे में है। यह आपके अनुबंध को भविष्य के अनुकूल बनाता है, और एक्सचेंज आपके एनएफटी की रॉयल्टी संरचना के बारे में (उदाहरण के लिए) पता लगाने के लिए इसे कॉल कर सकते हैं। मैं देखता हूं कि इसे अक्सर लागू नहीं किया जाता है, या उप-इष्टतम रूप से कार्यान्वित किया जाता है।
इसे सही तरीके से लागू करने के लिए यहां एक नियम दिया गया है:
|| type(ISomeInterface).interfaceId == _interfaceId
उदाहरण:
function supportsInterface(bytes4 _interfaceId) public view override(ERC721, ERC721Enumerable) returns (bool) { return super.supportsInterface(_interfaceId) || _interfaceId == type(IERC2981).interfaceId; }
यदि आपके कोड में कोई मूल वर्ग नहीं है जो ERC-165 को लागू करता है, तो केवल दूसरे प्रकार का प्रतिनिधित्व किया जाना चाहिए, जैसे कि
function supportsInterface(bytes4 _interfaceId) public view override returns (bool) { return _interfaceId == type(IERC721).interfaceId || _interfaceId == type(IERC2981).interfaceId || _interfaceId == type(IAccessControl).interfaceId; }
यदि आपका कोड ईआरसी-165 के मूल वर्ग के कार्यान्वयन द्वारा नियंत्रित किए गए इंटरफेस के अलावा कोई अन्य इंटरफेस लागू नहीं करता है, तो दूसरे प्रकार की आवश्यकता नहीं है। जैसे कि:
function supportsInterface(bytes4 _interfaceId) public view override(ERC721, ERC721Enumerable) //just make sure this list is complete returns (bool) { return super.supportsInterface(_interfaceId); }
ERC-165 को सही ढंग से लागू करना वैकल्पिक है, लेकिन महत्वपूर्ण है। आप चाहते हैं कि आपके टोकन अधिक से अधिक अन्य प्रणालियों (जैसे एक्सचेंजों) के साथ संगत हों, जिनमें भविष्य वाले भी शामिल हैं जिन्हें अभी तक लागू नहीं किया गया है। जैसे-जैसे समय बीतता जाएगा और स्थान परिपक्व होता जाएगा, ERC-165 मानक अधिक उपयोग और महत्वपूर्ण हो जाएगा।
आपका ERC721 टोकन बहुत मानक हो सकता है, और बहुत कम अनुकूलन के साथ सभी तृतीय पक्ष अभिभावक वर्गों और पुस्तकालयों का उपयोग कर सकता है, और आप जान सकते हैं कि तृतीय पक्ष कोड प्रसिद्ध रूप से अच्छी तरह से परीक्षण और सुरक्षित है। लेकिन आपको अभी भी अपने कोड का पूरी तरह से परीक्षण करने की आवश्यकता है, क्योंकि आपको इसे मेननेट पर तैनात करने से ठीक पहले इसे प्राप्त करने का केवल एक मौका मिलता है, जिससे आपको हमेशा के लिए महिमा या शर्म आती है।
सबसे पहले, निश्चित रूप से, इकाई परीक्षण । मेरी राय में, आप किस परीक्षण ढांचे का उपयोग करते हैं, यह महत्वपूर्ण नहीं है; मैं ईथर और मोचा के साथ हार्डहैट का उपयोग करता हूं। मेरे लिए एकमात्र महत्वपूर्ण हिस्सा यह है कि परीक्षण कवरेज और हैप्पी-पाथ मामलों, असाधारण मामलों और किनारे के मामलों की कवरेज व्यापक और गहरी है। भले ही आप परीक्षण कोड (जैसे OpenZeppelin) हो सकते हैं जो पहले से ही प्रसिद्ध रूप से अच्छी तरह से परीक्षण किया गया है, (ए) आपके कस्टम कोड ने उन मामलों में से कुछ को तोड़ दिया हो सकता है, इसलिए उन्हें फिर से जांचना चाहिए, और (बी) ओपनजेपेलिन में पहले बग थे, और वे भविष्य में फिर से हो सकते हैं। आपका कुछ समय बचाने के लिए, आपके पास सभी ERC721 टोकन, सभी ERC20 टोकन, सभी ERC1155 टोकन आदि के लिए परीक्षण का एक मानक सूट हो सकता है, जिसे आप परियोजना से परियोजना में पुन: उपयोग कर सकते हैं। यह अच्छा है। फिर आप किसी भी अनुकूलन को मानक में शामिल करने के लिए प्रत्येक प्रोजेक्ट के लिए मामले जोड़ सकते हैं; इससे समय की बचत होगी। यूनिट परीक्षणों में एक्सेस कंट्रोल, बुनियादी कार्यक्षमता (जैसे खनन और स्थानांतरण), पॉज़ेबिलिटी (यदि आपका अनुबंध रुकने योग्य है), ERC165 मानक का कार्यान्वयन, और बहुत कुछ शामिल होना चाहिए। आप सॉलिडिटी-कवरेज (एक नोडज पैकेज) का उपयोग करके अपने कवरेज का परीक्षण कर सकते हैं।
अंत में, स्वचालित उपकरण आपको परीक्षण में भारी मात्रा में सहायता दे सकते हैं। Slither , Manticore , और Mythril उद्योग मानक हैं, जिन्हें आमतौर पर Consensys और Certik जैसे सुरक्षा ऑडिटिंग में प्रमुख नामों द्वारा उपयोग किया जाता है। सॉलिडिटी -कवरेज (एक नोडज पैकेज) आपको आपके यूनिट परीक्षणों द्वारा प्रदान किए जा रहे कवरेज का अनुमानित प्रतिशत बताएगा (अंगूठे के नियम के रूप में बहुत आसान)। सोलग्राफ एक उपकरण है जो अनुबंध कोड में संबंधों और कनेक्शनों को देखने में आपकी सहायता कर सकता है; परीक्षण योजना में उपयोगी। इकिडना भी उपयोगी है; यह एक फ़ज़िंग परीक्षण उपकरण है। व्यक्तिगत रूप से मैं एक परीक्षण-प्रथम पद्धति का उपयोग करता हूं जहां लागू हो। यह अच्छा परीक्षण कवरेज सुनिश्चित करता है, और परीक्षण सूट एक परियोजना युक्ति के समान हो जाता है। मुझे कुछ अच्छे परीक्षण कवरेज पसंद हैं।
> pip3 install slither-analyzer > pip3 install mythril > npm install solidity-coverage
तो, संक्षेप में:
इथरस्कैन पर अनुबंध कोड का सत्यापन एक बड़ी विशेषता है। अनुबंध टैब पर हरे रंग का चेक मार्क देखना, और "सटीक मिलान" टैग के साथ कोड को स्वयं देखने में सक्षम होना, विश्वास और जवाबदेही उत्पन्न करता है। जब कोई आपके अनुबंध को पहली बार देख रहा हो, उपयोग या निवेश के सापेक्ष जोखिमों का आकलन करने की कोशिश कर रहा हो, तो यह केवल मदद कर सकता है। और यह सामान्य तौर पर, सभी प्रकार के सभी अनुबंधों के लिए है, न कि केवल एनएफटी के लिए।