با 4 ضدالگوی رایج در قراردادهای NFT آشنا شوید
به گزارش واحد ترجمه گذارنیوز، طی یک سال گذشته، شاهد شکوفایی عجیب بازار توکنهای غیرمثلی (NFT) بودیم و این روند رو به رشد همچنان ادامه دارد. در پلتفرم اتراسکن (Etherscan) یک ابزار جستجوی کاربردی وجود دارد که علاوه بر ویژگیهای تایید و دیکامپایل (Decompile)، میتوان به کمک آن کدهای بسیاری از قراردادهای ایآرسی 721 ( ERC721 ) را با یکدیگر مقایسه نمود.
هنگام مقایسه این قراردادها، به وضوح میبینیم که علیرغم وجود یک طراحی خوب، اشتباهات خاصی در بسیاری از آنها به دفعات تکرار شده است. به همین سبب، بر آن شدیم تا با بررسی ۴ مورد از این اشتباهات رایج در قراردادهای NFT ، به کاهش این بهاصطلاح ضدالگوها (Anti-Pattern) کمک کنیم.
با توجه به شرایط فعلی و کارمزدهای گاهاً نجومی شبکهها، اهمیت صرفه جویی در هزینههای گس (Gas) و کارمزدهای شبکه از هیچکس پوشیده نیست. همانطور که حتماً میدانید، در حال حاضر شبکه اتریوم بالاترین کارمزد تراکنشها را داراست و ما در این مقاله، به طور کلی درباره بلاکچینهای سازگار با سرویس نام اتریوم (EVM) صحبت خواهیم کرد، اما نکات ذکرشده را میتوانید به راحتی به سایر شبکههای بلاکچین تعمیم دهید.
پس از اتریوم، پالیگان (Polygon) و بلاکچینهایی مثل سولانا که از قابلیت سرویس نام اتریوم پشتیبانی نمیکنند، خدمات ارزانتری را ارائه مینمایند. نکتهای که باید در نظر بگیرید این است که درصورت داشتن سرمایه کافی، پیادهسازی پروژههای دارای کیفیت بالا، ارزش صرف هزینههای اضافی را دارد.
ضدالگوی شماره 1: گنجاندن اطلاعات مربوط به قیمت، فروش و منطق در قرارداد
این اشتباه که احتمالاً رایجترین ضدالگوی مشاهده شده در یک قرارداد NFT است، انگیزههای منطقی و قابلدرکی دارد که افراد را بدون درنظر گرفتن اثرات سوء آن، مجاب میکند. به دلیل بالا بودن هزینه استقرار و مدیریت قرارداد در اکثر شبکهها، افراد عموماً برای کاهش این هزینهها از هیچ تلاشی فروگذار نمیکنند.
ولی شاید شما هم بپرسید که چرا نباید منطق ضرب و فروش یک دارایی را در قرارداد آن گنجاند؟ در پاسخ این پرسش باید بگوییم: با وجود این که قرارداد باید مرکز غیر قابل تغییر شبکهای از منطقها باشد، نباید بهطور مستقیم خود را درگیر مدیریت پول کند. به بیان دقیقتر، دادههایی مثل اطلاعات فروش، زمان فروش، وایت لیست و امثال آن نباید مستقیماً در کد استقرار ایآرسی 721 ( ERC721 ) قرار بگیرد. منطق فروش و منطق هسته بسیار بهیکدیگر شبیه هستند.
درحالیکه صرفهجویی در هزینههای گس، بهترین و منطقیترین دلیل جمعآوری تمام منطقها در یک قرارداد است، دلایل مهمتری هست که شما را از این روش منع خواهد کرد. منطق اصلی قرارداد شما باید بدون تغییر باشد و در اکثر مواقع، استانداردها را به بهترین شکل اجرا کند.
اکثر کلونها (Clones) تقریبا یکی هستند. استراتژی صدور، قیمتگذاری و اطلاعاتی از این دست، باید از منطق اصلی قرارداد جدا شوند. این کار علاوه بر حفظ اعتماد کاربر، باعث انعطافپذیری بیشتر در قرارداد شما شده و یک طراحی تفکیکشده با قاعده تک-وظیفهای (Single-responsibility) را برای شما به ارمغان میآورد.
پیشنهاد میشود برای نتیجهگیری بهتر، عرضه (MaxSupply) در خود قرارداد “ERC721” محدود شود و فقط ادمین امکان تغییر آن را داشته باشد.
ضدالگوی شماره 2: عدم استفاده از امنیت مبتنیبر نقش
به دلیل وجود عملیاتهایی مثل ضرب توکن یا تغییراتی در پارامترهای عرضه که فقط باید در دسترس آدرسهای مجاز باشند، هر قرارداد توکن به نوعی کنترل دسترسی (access control) نیاز دارد. سادهترین روش برای اجرای این نوع کنترل دسترسی، بهرهگیری از یک مدل (Ownable) مثل قرارداد OpenZeppelin است. اما معمولاً توصیه میشود که از کنترل دسترسی مبتنی بر نقش (Role-Based Security) برای این کار استفاده شود.
دلیل اصلی این توصیه، سادگی استفاده از مدل Ownable است. شاید شما یا مشتری شما تنها کسانی باشید که برای همیشه قدرت مدیریت قرارداد را در اختیار خواهید داشت. وقتی هزینهها کم باشد، پیشبینی و مقابله با حوادث آینده (Future-proofing) به اولویت افراد تبدیل میشوند. ولی حقیقتاً امنیت نقشمحور (OpenZeppelin) کمی پیچیدهتر و گرانتر از مدل Ownable است.
ولی در شرایطی که هزینه گس زیاد است، میتوانید از کد امنیتی نقشمحور (چه OpenZeppelin باشد چه مدل خاص شما) فقط در راستای رفع نیاز موجود استفاده کنید.
امنیت نقشمحور به شما اجازه میدهد تا مولفههای کاربرد ازجمله اطلاعات قیمتگذاری و فروش را از خود قرارداد ERC721 جدا کنید، و این دلیل مهم دیگری است که استفاده از این مدل را به گزینهای مطلوب برای شما تبدیل میکند. با استفاده از این مدل، شما میتوانید یک قرارداد مجزا را بهعنوان ضربکننده انتخاب کرده و بدون نیاز به اعطای مجوز کامل مدیریت به آن، نقش «صادرکننده» را برای آن تعریف کنید.
این درحالی است که ادمین اصلی شما، که احتمالاً به جای یک قرارداد هوشمند، یک انسان است، بالاترین سطح مجوزها مثل ایجاد تغییرات را در اختیار خواهد داشت. وقتی برای مثال، دیگر نیازی به وجود صادرکننده نباشد، میتوانید بهسادگی آن را لغو کرده و نقش صادرکننده را بههمراه استراتژی جدید به یک قرارداد ماژولار، مناسبتر و امنتر واگذار کنید.
علاوه بر ضرب توکن، فعالیتهای دیگری را نیز میتوانید با همین روش و بر اساس کاربردهای پروژه مدیریت کنید.
ضدالگوی شماره 3: عدم استفاده صحیح از ERC-165 (Introspection)
در اکثر توکنها یا بهطور کلی، اکثر قراردادها میبینیم که یا از ERC-165 استفاده نشده یا آن را بهطور مناسب اجرا نکردهاند. این ضدالگو میتواند تاثیرات مخربی بر بازده توکن شما داشته باشد. اهمیت اصلی کد ERC-165 در نقش آن در ایجاد قابلیت همکاری (Interoperability) نهفته است. به نظر میرسد ERC- 165 سازگاری قرارداد شما را افزایش داده و احتمالاً صرافیها برای آگاهی از ساختار حق امتیاز NFT شما آنرا فراخوانی میکنند. برای اجرای درست این استاندارد باید قوانین زیر با دقت رعایت شوند:
- هر کلاس والدی که ERC-165 را اجرا میکند، باید در لیست لغو (Override) قرار بگیرد. در این صورت هر زمان که فرمان supportsInterface اجرا شود، آنها نیز بهطور خودکار فعال خواهند شد.
- هر رابط دیگری که پیادهسازی شده و در کلاس والد نیست، میتوانید با کلمه an یا یک جمله به شکل زیر اضافه کنید:
|| type(ISomeInterface).interfaceId == _interfaceId
مثال:
در صورت نبود یک کلاس والد در کد شما، برای اجرای ERC-165، باید به نوع دوم اشاره کنید. مثلا:
درصورتی که کد شما بهجز ERC-165 اجرا شده توسط کلاس والد، هیچ رابط دیگری را اجرا نمیکند، به نوع دوم نیاز ندارید:
هرچند اجرای صحیح ERC-165 امری اختیاری است، درصورتی که مایل هستید توکن شما با سیستمهای مختلف مانند صرافیها و حتی سیستمهایی که هنوز پیادهسازی نشدهاند سازگاری داشته باشد، به اهمیت این کار پی خواهید برد.
ضدالگوی شماره 4: عدم تست و بررسی کامل قبل از استقرار
تست نکردن کامل قرارداد، چهارمین مورد از رایجترین اشتباهات و ضدالگوهای مشاهده شده در قراردادهای NFT است. حتی اگر اطمینان دارید که توکن ERC721 شما کاملاً استاندارد بوده و بدون نیاز به تغییرات خاصی میتواند از تمام کتابخانهها و کلاسهای والد شخص ثالث استفاده کند و این کد شخص ثالث تست شده و ایمن است، باز هم لازم است کد خود را بهطور کامل تست کنید، چراکه پیش از استقرار توکن بر شبکه اصلی، تنها یکبار فرصت بررسی و رفع اشکالات احتمالی دراختیار شما قرار میگیرد.
اولین مرحله از پروسه بازبینی، تست یونیت (Unit Testing) است. نوع چهارچوب مورد استفاده برای این تست اهمیت زیادی ندارد ولی، در میان گزینههای موجود، Hardhat، Ethers و Mocha بیشتر توصیه میشود. آنچه که در این مرحله اهمیت دارد، رعایت نکات مهمی مثل پوشش تست، پوشش کلیه موارد Happy-path ، موارد استثنایی و عمق و گستردگی موارد Edge میباشد.
حتی اگر از کدی مثل OpenZeppelin استفاده میکنید که پیش از این به طور کامل تست شده است، باز باید توجه داشته باشید که این احتمال وجود دارد که کد شما در یکی از موارد فوق دچار مشکل شده باشد و یا کد OpenZeppelin مورد استفاده شما قبلاً باگهایی داشته که ممکن است در آینده دوباره ظاهر شوند.
به منظور کاهش زمان انجام این اقدامات، توصیه میشود یک سری تست واحد برای تمام توکنهای ERC721، توکنهای ERC20 و توکنهای ERC1155 آماده و در هر پروژه از همان مجموعه استفاده کنید. با این کار، ضمن صرفه جویی در وقت، میتوانید در صورت لزوم موارد بیشتری را به پروژهها اضافه و استاندارد مورد نظر خود را سفارشیسازی کنید.
تستهای یونیت به طور معمول باید مواردی چون کنترل دسترسی، عملیات پایه مانند ضرب و انتقال توکن، مکثپذیری درصورت وجود قابلیت مکث در قرارداد شما، پیادهسازی استاندارد ERC165 و غیره را پوشش دهد. این گستره پوشش را نیز میتوانید به کمک یکی از پکیجهای پلتفرم Nodejs با نام Solidity-Coverage تست کنید.
نهایتاً، استفاده از ابزارهای خودکار نیز میتواند در انجام تستهای نهایی بسیار کمک کننده باشد. ازجمله استانداردهای صنعتی که معمولاً شرکتهای بزرگ امنیتی مثل Consensys و Certik از آنها استفاده میکنند، میتوان به Slither، Manticore و Mythril اشاره کرد.
گفتنی است که پکیج Solidity-coverage برآوردی از پوشش تستهای یونیت شما را به صورت درصدی نشان میدهد. Solgraph نیز ابزاری است که علاوهبر برنامهریزی تستها، میتوانید به کمک آن ارتباطات موجود در کد قرارداد خود را مشاهده کنید. ابزار مفید ولی تاحدودی پیچیده بعدی نیز Echidna نام دارد.
در صورتی که به طور مرتب از روشهای تستمحور (Test-first) استفاده کنید، حتماً تست موفقی خواهید داشت که شما را به مشخصات اصلی پروژه نزدیک میکند.
مراحل فوق را میتوان به طور خلاصه در سه مرحله مجزا تفکیک کرد:
- انجام یونیت تست جامع و عمیق حتی الامکان در کلیه مواردی که به آنها اشاره شد.
- تست و آزمایش دستی
- استفاده از ابزارهای خودکار مثل Slither، Manticore، Mythril، Echidna و Solidity-coverage
بهتر است قرارداد خود را در اتراسکن تایید کنید
تایید کد قرارداد در اتراسکن یک ویژگی مفید و بسیار کارآمد است چرا که تایید و اعطای تیک سبز به قرارداد شما، میتواند تا حد زیادی منجر به افزایش اعتماد و مسئولیتپذیری شود. در این صورت، وقتی کسی قرارداد شما را برای اولین بار میبیند و تصمیم میگیرد ریسکهای سرمایه گذاری در آن را ارزیابی کند، این امتیاز برای شما بسیار کمککننده خواهد بود.
مترجم: مرضیه مظاهری
منبع: hackernoon