آموزش استاندارد ERC-1363 در سالیدیتی

استاندارد ERC-1363 در سالیدیتی این امکان را فراهم می‌کند که یک قرارداد هوشمند بلافاصله پس از دریافت توکن، از آن انتقال مطلع شود و به آن واکنش نشان دهد.

مشکل اصلی که استاندارد ERC-1363 در سالیدیتی حل میکند چیست؟

فرض کنید یک کاربر، تعدادی توکن مبتنی بر استاندارد ERC-20 را برای یک قرارداد هوشمند ارسال می‌کند. در این حالت، قرارداد هوشمند نمی‌داند چه کسی این توکن ها را فرستاده و نمی‌تواند براساس آن عملیات خاصی مثل ثبت واریز برای کاربر انجام دهد؛ چون هیچ مکانیزمی برای شناسایی فرستنده هنگام دریافت مستقیم توکن در برنامه نویسی این قرارداد در نظر گرفته نشده است.

هرچند لاگ های رویداد (eventها) این اطلاعات را ثبت می‌کنند، اما فقط سیستم های خارج از بلاکچین (off-chain) می‌توانند به آن ها دسترسی داشته باشند. قراردادهای هوشمند به تنهایی نمی‌توانند این داده ها را بخوانند، مگر اینکه از یک اوراکل (Oracle) استفاده کنند.

راهکار مرسوم در استاندارد ERC-20: استفاده از transferFrom

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

در این روش، کاربر ابتدا با استفاده از تابع approve، اجازه می‌دهد قرارداد دریافت‌کننده مقدار مشخصی از توکن های او را برداشت کند. سپس با فراخوانی تابع deposit، قرارداد این توکن ها را از حساب کاربر به حساب خودش منتقل می‌کند. از آنجا که قرارداد مستقیماً این انتقال را انجام داده، به‌درستی حساب کاربر را شارژ می‌کند.

این راهکار هرچند جواب‌گوست، اما دو مشکل دارد:

  1. هزینه بیشتر گس: نیاز به دو تراکنش دارد — یکی برای approve و دیگری برای transferFrom — که هزینه کل گس را افزایش می‌دهد.

  2. ریسک امنیتی: اگر کاربر پس از انجام عملیات، مقدار مجاز approve را مجدد به صفر تغییر ندهد، در صورت هک یا سواستفاده از قرارداد، ممکن است تمام توکن های قابل برداشت از حساب کاربر خارج شود.

استاندارد ERC-1363 در سالیدیتی با هدف ساده سازی این فرایند و حذف نیاز به تأیید مجزا (approve) ارائه شده است. در ادامه، این استاندارد و نحوه استفاده از آن را بررسی خواهیم کرد.

هوک انتقال در سالیدیتی

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

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

کسانی که با تابع onERC721Received در استاندارد ERC-721 در سالیدیتی آشنا هستند، به خوبی با مفهوم هوک انتقال آشنایی دارند.

استاندارد ERC-1363 و افزودن هوک انتقال به ERC-20

استاندارد ERC-1363 نسخه توسعه یافته‌ای از ERC-20 محسوب می‌شود که امکان فراخوانی هوک انتقال را به قابلیت‌های آن اضافه می‌کند.

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

اینترفیس IERC1363Receiver در سالیدیتی

هر قراردادی که می‌خواهد از دریافت توکن های ERC-1363 مطلع شود، باید اینترفیس IERC1363Receiver را پیاده‌سازی کند (می‌توانید پیاده‌سازی آن را در OpenZeppelin ببینید). اینترفیس شامل تنها یک تابع به نام onTransferReceived است:

توضیح پارامترها:

  • operator: آدرسی است که انتقال را آغاز کرده است.

  • from: حسابی است که توکن های ERC-1363 از آن کسر شده‌اند.

  • value: تعداد توکن های منتقل شده را نشان می‌دهد.

  • data: داده‌ای است که توسط operator مشخص می‌شود و به گیرنده منتقل می‌گردد.

هنگام پیاده‌سازی این تابع، همیشه بررسی کنید که msg.sender همان قرارداد توکن ERC-1363 باشد که انتظار دریافت آن را دارید؛ زیرا هر کسی می‌تواند این تابع را با مقادیر دلخواه فراخوانی کند.

در ادامه یک نمونه قرارداد ساده و حداقلی برای دریافت توکن های ERC-1363 ارائه خواهد شد.

در روش سنتی، برای اینکه یک قرارداد هوشمند متوجه شود توکن ERC-20 دریافت کرده، باید کاربر ابتدا با استفاده از تابع approve، قرارداد را مجاز به برداشت توکن کند. سپس قرارداد با استفاده از تابع transferFrom توکن را از حساب کاربر برداشت می‌کند.

اما با استاندارد ERC-1363 دیگر نیازی به مرحله تأیید (approve) نیست. تابع transferAndCall توکن را مستقیماً به قرارداد منتقل می‌کند و به‌طور همزمان، تابع onTransferReceived را در قرارداد گیرنده فراخوانی می‌کند. این قابلیت، شناسایی دریافت توکن را برای قرارداد ساده‌تر می‌کند و نیاز به دو تراکنش جداگانه را از بین می‌برد.

سازگاری حداکثری با استاندارد ERC-20

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

برای حل این مشکل، طراحان ERC-1363 این استاندارد را بر پایه ERC-20 توسعه داده‌اند و تمام توابع اصلی آن را دقیقاً مطابق با مشخصات ERC-20 پیاده‌سازی کرده‌اند. این توابع شامل موارد زیر هستند:

  • name

  • symbol

  • decimals

  • totalSupply

  • balanceOf

  • transfer

  • transferFrom

  • approve

  • allowance

به این ترتیب، تمام پروتکل های قدیمی که با ERC-20 کار می‌کنند، می‌توانند بدون هیچ تغییری با توکن های ERC-1363 نیز تعامل داشته باشند.

اما برای بهره‌برداری از قابلیت های جدید، استاندارد ERC-1363 توابع اضافه‌ای را معرفی کرده است که فقط در صورت نیاز مورد استفاده قرار می‌گیرند.

توابع اضافی استاندارد ERC-1363 در سالیدیتی

برای اینکه یک توکن با استاندارد ERC-1363 در سالیدیتی سازگار باشد، باید ۶ تابع اضافی را پیاده‌سازی کند:

  • دو نسخه از transferAndCall

  • دو نسخه از transferFromAndCall

  • دو نسخه از approveAndCall

همان طور که از نام این توابع پیداست، ابتدا عملیات استاندارد ERC-20 (مثل انتقال یا تأیید) را انجام می‌دهند و سپس تابع هوک مربوط به گیرنده را فراخوانی می‌کنند.

هر کدام از این توابع در دو نسخه ارائه می‌شوند:

  1. نسخه‌ای بدون پارامتر data

  2. نسخه‌ای با پارامتر data برای ارسال اطلاعات اضافی به قرارداد گیرنده

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

به جز پارامتر data، ساختار سایر پارامترهای این توابع کاملاً مشابه توابع ERC-20 است و ترتیب آن ها نیز تغییر نکرده است.

الهام‌گیری از ERC-721: مقایسه transferFrom و transferFromAndCall

استاندارد ERC-1363 از مفاهیمی مشابه استاندارد ERC-721 الهام گرفته است. همان‌طور که در ERC-721 تفاوت بین توابع transferFrom و safeTransferFrom وجود دارد، در ERC-1363 نیز تفاوتی مشابه بین transferFrom و transferFromAndCall دیده می‌شود.

با این حال، استفاده از واژه “safe” (ایمن) در نام تابع می‌تواند گمراه‌کننده باشد. دلیلش این است که استفاده از هوک های انتقال (transfer hooks) در ERC-1363 ممکن است مسیرهایی برای حمله بازگشتی (reentrancy attack) ایجاد کند. بنابراین این عملیات واقعاً “ایمن” نیست.

در عوض، استفاده از واژه call در نام تابع (همان‌طور که در transferFromAndCall دیده می‌شود)، به وضوح نشان می‌دهد که این تابع، پس از انجام انتقال، یک فراخوانی (call) به گیرنده انجام می‌دهد تا او را از دریافت توکن مطلع کند.

نحوه ذخیره‌سازی در ERC-1363

استاندارد ERC-1363 برای ذخیره مقادیر مربوط به موجودی حساب‌ها (balances) و مجوزهای برداشت (approvals) دقیقاً از همان متغیرهایی استفاده می‌کند که در استاندارد ERC-20 به کار رفته‌اند. این استاندارد هیچ نوع اطلاعات اضافه‌ای در قرارداد ذخیره نمی‌کند و ساختار داده‌های آن کاملاً با ERC-20 سازگار است.

مروری بر کد ERC-1363 در سالیدیتی

ارث‌بری از ERC-20

همان‌طور که پیش‌تر اشاره شد، استاندارد ERC-1363 در واقع همان ERC-20 است که توابع جدیدی به آن اضافه شده‌اند. بنابراین، اولین قدم برای پیاده‌سازی یک توکن ERC-1363 این است که از قرارداد ERC-20 ارث‌بری کنیم:

تابع transferFromAndCall(address to, uint256 value) external returns (bool)

این تابع زمانی با موفقیت اجرا می‌شود که آدرس گیرنده تابع onTransferReceived() را پیاده‌سازی کرده باشد و مقدار بازگشتی آن دقیقاً برابر با چهار بایت ابتدایی تابع onTransferReceived() باشد:

تابع transferAndCall(address to, uint256 value) external returns (bool)

عملکرد این تابع تقریباً مشابه transferFromAndCall است، با این تفاوت که آدرس فرستنده همان msg.sender است:

تابع _checkOnTransferReceived()

این تابع عملکرد زیر را انجام می‌دهد:

  1. بررسی می‌کند که آیا آدرس گیرنده، یک قرارداد هوشمند است یا نه. اگر نباشد، تراکنش را لغو می‌کند (revert).

  2. تلاش می‌کند تابع onTransferReceived را در قرارداد گیرنده صدا بزند.

  3. اگر خروجی دریافتی برابر با 0x88a7ca5c نباشد، عملیات را لغو می‌کند.

  4. اگر اجرای onTransferReceived با خطا مواجه شود، پیام خطا را دریافت و ریورت می‌کند.

نکته مهم: از آنجا که این تابع برای حساب های معمولی (EOA) اجرا نمی‌شود و باعث خطا می‌شود، برای ارسال توکن ERC-1363 به یک آدرس کیف پول معمولی، باید از توابع استاندارد ERC-20 مانند transfer یا transferFrom استفاده کنید:

تابع approveAndCall

در مثال‌های قبلی، قرارداد گیرنده همان دریافت‌کننده توکن های ERC-1363 بود. اما اگر بخواهیم یک قرارداد واسطه، مانند روتری در صرافی Uniswap، به عنوان فرستنده توکن ها عمل کند چه باید کرد؟

در ساختارهای سنتی، این کار با دو مرحله انجام می‌شود:

  1. ابتدا کاربر با استفاده از approve به قرارداد اجازه می‌دهد تا از طرف او توکن خرج کند.

  2. سپس قرارداد با transferFrom توکن را به مقصد می‌فرستد.

استاندارد ERC-1363 این فرایند را در یک تراکنش با استفاده از approveAndCall ساده‌سازی می‌کند. در این حالت، قراردادی که اجازه برداشت توکن را دریافت کرده، به طور خودکار یک تابع هوک مخصوص را دریافت می‌کند.

همانند توابع transferAndCall، توابع approveAndCall نیز در دو نسخه ارائه شده‌اند: یکی با پارامتر data برای ارسال اطلاعات اضافی و دیگری بدون آن:

اینترفیس IERC1363Spender

مشابه با IERC1363Receiver که در آن تابع onTransferReceived فراخوانی می‌شد، در اینجا نیز با استفاده از اینترفیس IERC1363Spender، هنگام فراخوانی تابع approveAndCall، تابع onApprovalReceived فعال می‌شود.

در ادامه، پیاده‌سازی اینترفیس IERC1363Spender بر اساس نسخه ارائه شده توسط OpenZeppelin نمایش داده شده است (توضیحات درون کد حذف شده‌اند):

  • owner: این آدرس نشان می‌دهد چه کسی مالک توکن هاست و شخصاً اجازه برداشت آن ها را صادر کرده است.

  • value: این مقدار مشخص می‌کند چه تعداد توکن برای برداشت تأیید شده‌اند.

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

از آنجا که فقط صاحب توکن ها می‌تواند مجوز برداشت صادر کند، نیازی به پارامتر operator نیست — در اینجا owner همان کسی است که عمل تأیید را انجام داده است.

در مثال زیر، یک قرارداد به نام Router تعریف شده که از IERC1363Spender ارث‌بری می‌کند. این قرارداد پس از دریافت مجوز با استفاده از approveAndCall، توکن ها را به آدرسی که در داده‌ها (data) مشخص شده ارسال می‌کند:

تابع onApprovalReceived باید بررسی کند که msg.sender همان قرارداد توکن مورد انتظار باشد. اگر این بررسی انجام نشود و هر آدرسی بتواند این تابع را فراخوانی کند، ممکن است رفتارهای غیرمنتظره و حتی خطر امنیتی در قرارداد ایجاد شود.

مثال از یک قرارداد گیرنده با استفاده از ERC-1363

در این مثال، یک قرارداد گیرنده نشان داده می‌شود که از استاندارد ERC-1363 پشتیبانی می‌کند و از پارامتر data استفاده می‌کند تا رفتار قرارداد در زمان دریافت توکن بر اساس داده های دریافتی تغییر کند.

استانداردهای پیشین برای حل مشکل هوک انتقال توکن

استاندارد ERC-1363 اولین تلاشی نبود که سعی کرد قابلیت هوک انتقال (transfer hook) را به توکن های ERC-20 اضافه کند.

استاندارد ERC-223 اولین تلاش رسمی در این زمینه بود. این استاندارد تابع هوک انتقال را به توابع transfer و transferFrom اضافه کرد. اما مشکل اصلی اینجا بود که اگر قرارداد گیرنده این هوک را پیاده‌سازی نکرده بود، نمی‌توانست توکن را دریافت کند.

این ویژگی باعث شد که بسیاری از قراردادهایی که بر اساس استاندارد ERC-20 طراحی شده بودند اما تابع هوک نداشتند، نتوانند با ERC-223 سازگار شوند. به همین دلیل، توسعه‌دهندگان این استاندارد را به‌صورت گسترده نپذیرفتند، چون ERC-223 با زیرساخت‌های قبلی همخوانی نداشت.

در استاندارد ERC-777، فقط قراردادهایی که آدرس آن ها را در رجیستری ERC-1820 ثبت کرده بودند، می‌توانستند هوک انتقال را دریافت کنند. این فرآیند پیچیدگی بیشتری به طراحی قراردادها اضافه کرد.

علاوه بر این، استاندارد ERC-777 مشکلات امنیتی خاصی ایجاد کرد. بسیاری از پروتکل ها هنگام طراحی با ERC-20، این احتمال را در نظر نگرفته بودند که توابع transfer یا transferFrom بتوانند فراخوانی خارجی به قراردادهای دیگر انجام دهند. همین موضوع باعث شد قراردادهایی که برای چنین سناریویی آماده نبودند، در برابر حملات بازگشتی (reentrancy attacks) آسیب‌پذیر شوند. یکی از نمونه‌های شناخته‌شده این آسیب‌پذیری، مربوط به نسخه اول Uniswap بود.

علاوه بر این، چون ERC-777 برای اجرای هوک‌ها باید با قرارداد رجیستری ERC-1820 ارتباط برقرار می‌کرد، مصرف گس در این استاندارد به‌طور قابل توجهی افزایش پیدا می‌کرد.

چگونه ERC-1363 این مشکلات را حل می‌کند؟

استاندارد ERC-1363 تمامی این مشکلات را با یک رویکرد ساده اما مؤثر برطرف می‌کند:

  • توابع اصلی ERC-20 یعنی transfer و transferFrom را بدون هیچ تغییری حفظ می‌کند. در نتیجه با تمامی پروتکل های قدیمی سازگار باقی می‌ماند.

  • هوک های انتقال تنها در توابعی مانند transferAndCall یا approveAndCall فعال می‌شوند — نام این توابع به‌روشنی نشان می‌دهد که قرار است پس از انتقال، تابعی در قرارداد گیرنده فراخوانی شود.

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

چه زمانی باید از استاندارد ERC-1363 استفاده کرد؟

ERC-1363 می‌تواند در هر موقعیتی که قبلاً از ERC-20 استفاده می‌شده، به کار رود. از دید نویسنده مقاله، این استاندارد جایگزین بسیار مناسبی برای ERC-20 است، زیرا نیاز به مرحله approve را حذف می‌کند؛ مرحله‌ای که در گذشته باعث از دست رفتن مقادیر قابل توجهی از دارایی کاربران شده است.

با استفاده از ERC-1363 می‌توان قراردادهایی ساده‌تر، امن‌تر و کارآمدتر طراحی کرد، در حالی که همچنان با اکوسیستم گسترده ERC-20 سازگار باقی ماند.

5/5 - (1 امتیاز)

راستی! برای دریافت مطالب جدید در کانال تلگرام یا پیج اینستاگرام سورس باران عضو شوید.

دوره آموزش طراحی فروشگاه اینترنتی بدون کد نویسی در 8 ساعت
  • انتشار: ۲ خرداد ۱۴۰۴

دسته بندی موضوعات

آخرین محصولات فروشگاه

مشاهده همه

نظرات

بازخوردهای خود را برای ما ارسال کنید