برنامه نویسی سالیدیتی : استاندارد ERC721 (بخش چهارم)

در مقاله قبلی از این مجموعه آموزشی که توسط Andrew Parker از medium.com تهیه شده، ما نوشتن درباره قرارداد ERC721 را آغاز کردیم. توضیحات متعددی در سه مقاله اول وجود داشت (بخش 1 تا 3) و به همین خاطر فرض می‌‌کنیم همه کدها را مطالعه کرده‌‌اید! در این مقاله، با افزودن تاییدیه‌‌ها، اپراتورها و متغیرهای متعدد عملکرد انتقال، قراردادمان را به پایان خواهیم رساند.

0 106

برای مطالعه بخش قبل اینجا را کلیک کنید

پیش به سوی کد!

.در پایان مقاله آخر و در بخش عملکرد burnToken، ممکن است توجه کرده باشید که من دو mapping را مشخص کردم که عناوین قانونی و مجوزی داشتند. این دو عنوان برای برای مدیریت تاییدیه‌‌ها به کار می‌‌روند که اساسا سیستمی برای کنترل توکن‌‌های شما توسط فرد دیگر و حفظ مالکیت آن‌‌ها توسط خودتان است.

دو نوع تاییدیه وجود دارد، یکی به فرد اجازه کنترل یک توکن مشخص (مقرری) و دیگری اجازه کنترل تمام توکن‌‌ها (مجوز) را می‌‌دهد. هر دو نوع تاییدیه عملکردهای خاص خود و روش کار متفاوت نسبت به یکدیگر دارند و به همین خاطر هر دو را به صورت مجزا از هم بررسی خواهیم کرد.

مجاز (Authorised)

مجوز با دو تابع استاندارد ERC721 تعریف می‌‌شود.

 

که به یک فرد دارای مجوز، کنترل تمام توکن‌‌های شما را می‌‌دهد (بگذارید به این افراد، اپراتور بگوییم) و

 

که این داده‌‌ها را می‌‌خواند. اینجا است که mapping دارای مجوزی که از شروع قراردادمان اعلام کرده بودیم وارد ماجرا می‌‌شود. اگر این موضوع را فراموش کرده‌‌اید، mapping که معرفی کرده بودیم چنین است:

 

اگر تا به حال یک نگاشت (mapping) ندیده‌‌اید، نگران نباشید زیرا پیچیدگی چندان بالایی ندارد. در این مورد، هر آدرس مالک به نگاشت شخصی خود می‌‌رود که آدرس‌‌های اپراتور را به یک bool هدایت می‌‌کند که ممکن است یک اپراتور باشد یا خیر.

بنابراین خواندن از این نگاشت فقط ساختار زیر را می‌‌طلبد:

 

که اگر اپراتور برای مالک صحیح باشد، آن را صحیح یا مثبت و در غیر این صورت، غلط یا کاذب ارزیابی خواهد کرد.

در حقیقت، تمام عملکردهای isApprovedForAll ما دقیقا به همین شکل عمل می‌‌کنند و مقداری از این نگاشت را باز می‌‌گردانند.

 

به طور مشابه عملکرد setApprovalForAll ما، فقط یک مقدار را در این نگاشت تنظیم می‌‌کند. تنها نیاز دیگر این است که عملکرد ما، رویداد ApprovalForAll را منتشر کند که در واسطه استاندارد به این شکل تعریف می‌‌شود:

 

پس عملکرد setApprovalForAll ما چنین خواهد بود:

 

مقرری

مقرری هم با دو عملکرد توصیف می‌‌شود.

 

که مشخص می‌‌کند چه کسی برای توکن مشخص، تایید می‌‌شود و

 

که این داده را می‌‌خواند. مهمترین نکته این است که برای هر توکن مشخص، فقط یک آدرس دارای مجوز در هر زمان وجود خواهد داشت. اگر فردی را برای یک توکن تایید کنید و سپس فرد دیگری را تایید کنید، فرد اول دیگر برای آن توکن، مجوز نخواهد داشت.

شبیه به نگاشت مجوز برای رابطه با اپراتورها ما مقرری برای رابطه با تاییدیه تک‌‌توکنی خواهیم داشت. برای یادآوری:

 

اینجا هیچ حقه خاصی وجود ندارد، فقط نگاشت برای هر tokenId و آدرس مورد تایید آن به چشم می‌‌خورد. اگر هیچ تغییری نکرده بود، آن را 0x0 ارزیابی می‌‌کند.

دو نیاز عملکرد getApproved ما این است که اگر throws if _tokenId یک NFT معتبر نبود و این آدرس تایید شده برای این NFT یا آدرس صفر بازگشت و هیچ چیز وجود نداشت، چنین خواهیم داشت:

 

و برای بخش تاییدیه‌‌ها، ما عملکرد تایید را داریم. در ذهن داشته باشید که من تغییرپذیری را از قابل‌‌پرداخت به غیرقابل‌‌پرداخت تغییر داده‌‌ام و در نسخه واسطه خودم هم تغییر مشابهی ایجاد کرده‌‌ام. ما برای پرداخت به چنین عملکردی نیاز نداریم.

 

استاندارد شرایط زیر برای عملکرد تایید را دارد.

“Throws unless msg.sender is the current NFT owner, or an authorised operator of the current owner.”

ما با گرفتن نتایج ownerOf و ذخیره آن در متغیر موقت شروع می‌‌کنیم. اگر از قبل به خاطر دارید، ownerOf کمی پیچیده‌‌تر از مطالعه یک متغیر است و به همین خاطر، روشی ارزان‌‌تر برای فراخوانی مجدد ownerOf هر بار که نیاز به آدرس مالک داریم خواهد بود.

 

سپس بررسی می‌‌کنیم که آیا msg.sender مالک یا اپراتور مورد نیاز ما هست یا خیر. توجه کنید که من بخش دارای مجوز را به صورت مستقیم و نه با فراخوانی isApprovedForAll می‌‌خوانم، این یک ابزار ذخیره‌‌سازی دیگر Gas‌‌ می‌‌باشد.

 

در پایان ما یک رویداد برای انتشار داریم و باید نگاشت مقرری را بروز کنیم.

 

عملکردهای انتقال

آخرین و مهم‌‌ترین بخش قرارداد ما، عملکرد انتقال است. از نظر فنی سه عملکرد وجود دارد اما همه آن‌‌ها اساسا یک عمل را انجام می‌‌دهند. فقط دوتای آن‌‌ها ویژگی‌‌های بیشتری هم دارند. بیایید با ساده‌‌ترین عملکرد آغاز کنیم.

transferFrom

همانطور که از نام آن پیدا است، عملکرد transferFrom برای انتقال یک توکن از یک آدرس به آدرس دیگر به کار می‌‌رود. پیش از این که ادامه دهیم، توجه کنید که من قابلیت‌‌تغییر را از قابل‌‌پرداخت به غیرقابل‌‌پرداخت تغییر داده‌‌ام (زیرا نیازی به پرداخت با این نداریم) و همچنین قابلیت‌‌مشاهده را از خارجی به عمومی تغییر داده‌‌ام (زیرا transferFrom باز هم توسط عملکردهای انتقال دیگر مورد استفاده قرار می‌‌گیرد و عمومی کردن آن، کمی Gas‌‌ ذخیره خواهد کرد).

 

سپس نیازهای متعددی برای این عملکرد وجود دارد که عدم تحقق آن‌‌ها، سبب رد آن می‌‌شود. بیایید با مالکیت توکن آغاز کنیم، زیرا از آن در بسیاری از بررسی‌‌های خود استفاده می‌‌کنیم و عملکرد ownerOf شامل بررسی برای اعتبار tokenId می‌‌شود و بخشی از نیازهای transferFrom می‌‌باشد:

 

در ادامه ما

“Throws unless msg.sender is the current owner, an authorised operator, or the approved address for this NFT.”

را داریم که چنین مفهومی دارد:

 

بار دیگر من به طور مستقیم به نگاشت دسترسی دارم و از عملکرد تاییدیه که قبلا نوشتیم استفاده نمی‌‌کنم، زیرا ارزان‌‌تر تمام می‌‌شود.

سپس

“Throws if _from is not the current owner.”

چنین می‌‌شود:

 

آخرین بررسی ما

 

شخصا دوست دارم تا بعد از بررسی‌‌ها، تمام رویدادها را فورا منتشر کنم اما این موضوع چندان اهمیتی ندارد و می‌‌توانید تا پایان صبر کنید.

 

سپس نگاشت مالکان خود را به‌‌روز می‌‌کنیم تا مالک جدید منعکس شود،

 

و ترازهای آدرس‌‌ها را هم تنظیم می‌‌کنیم.

 

توجه کنید که در این قسمت، نیازی به SafeMath نیست، منطق قراردادی ما تضمین می‌‌کند که هیچکس با تراز 0 نتواند به این نقطه برسد و تراز سرریز نخواهیم داشت.

تنها کاری که باقی می‌‌ماند، ریست‌‌کردن مقرری برای این توکن است. حالا که توکن چند دست عوض کرده، مالک باید تصمیم بگیرد که چه کسی کنترل آن را در اختیار داشته باشد.

 

رویداد انتقال می‌‌گوید که ما مقرری را ریست می‌‌کنیم تا نیازی به انتشار رویداد تاییدیه هم نباشد.

safeTransferFrom

عملکرد safeTransferFrom تقریبا مشابه transferFrom می‌‌باشد، فقط اینکه آن‌‌ها نیازمند بررسی معتبر بودن پذیرنده قرارداد ERC721 هستند و اگر چنین است، به شما اجازه می‌‌دهند تا کمی اطلاعات به آن قرارداد منتقل کنید. یک نسخه سه پارامتری و یک نسخه 4 پارامتری از این عملکرد وجود دارد اما نسخه 3 پارامتری همان نسخه 4 پارامتری است که یک پارامتر خالی دارد و به همین خاطر با نسخه 4 پارامتری آغاز می‌‌کنیم.

بار دیگر توجه کنید که من به دلایل مرتبط با Gas‌‌ و اینکه نیازی به پرداخت نداریم، قابلیت‌‌تغییر و قابلیت‌‌مشاهده را از قابل‌‌پرداخت خارجی به عمومی و غیرقابل‌‌پرداخت تبدیل کرده‌‌ام.

 

اولین کاری که باید انجام دهیم، فراخواندن عملکرد transferFrom است و این مسئله اغلب بررسی‌‌های لازم ما را انجام خواهد داد و در نهایت، توکن را هم منتقل می‌‌کند.

 

سپس باید به شرایط اضافه‌‌شده به safeTransferFrom برسیم.

 

اینجا باید کمی تغییر انجام دهیم، خوشبختانه یک کد وجود دارد که اندازه کد را به یک آدرس مشخص باز می‌‌گرداند. من هم تا به حال از چنین تغییری برای بررسی اندازه کد استفاده نکرده‌‌ام و باید _toand کمک بگیریم. سپس به بخش سالیدیتی باز خواهیم گشت.

 

اگر اندازه 0 باشد، این آدرس متعلق به یک قرارداد نخواهد بود. اما اگر متعلق باشد، باید onERC721Received را فرا بخوانیم و نیاز خواهیم داشت که به ما پاسخ صحیحی بدهد:

 

تنها تفاوت بین transferFrom و safeTransferFrom همین مسئله است. فقط نسخه 3 پارامتری باقی مانده‌‌است که نسخه 4 پارامتری را در بخش آخر فرا می‌‌خواند. توجه کنید که من قابلیت‌‌تغییر را از قابل‌‌پرداخت به غیرقابل‌‌پرداخت تغییر داده‌‌ام:

 

جمع‌‌بندی

بفرمایید! موفق شدید قرارداد ERC721 خودتان را بنویسید، خسته نباشید! یک کپی از این قرارداد در GitHub من موجود است و می‌‌توانید بعد ازا آن کمک بگیرید.

در بخش بعدی به آزمایش قرارداد هوشمندمان خواهیم پرداخت

شاید از این مطالب هم خوشتان بیاید.

ارسال پاسخ

آدرس ایمیل شما منتشر نخواهد شد.