بررسی معماری قرارداد هوشمند Compound V3

پروتکل Compound یکی از مهم‌ترین سیستم‌های وام‌دهی در دنیای دیفای (DeFi) است. این پروتکل الهام‌بخش طراحی بسیاری از پروژه‌های مشابه در بلاکچین‌های مختلف بوده است. در این مقاله، ساختار قرارداد هوشمند نسخه سوم Compound را بررسی می‌کنیم.

با توجه به ماهیت Compound به‌عنوان یک پلتفرم وام‌دهی، فرض می‌کنیم خواننده با مفاهیمی مانند نرخ بهره در دیفای، لیکوئید شدن (liquidation) و نقش وثیقه (collateral) در وام‌های غیرمتمرکز آشنا است.

در نسخه سوم، برخلاف نسخه دوم Compound، هر بازار فقط یک دارایی را برای وام‌دهی ارائه می‌دهد. به‌عبارت دیگر، در بازار USDC فقط می‌توان USDC وام گرفت. در بازار ETH نیز فقط ETH قابل دریافت است. امکان وام‌گیری دارایی‌های دیگر در همان بازار وجود ندارد. برای دریافت وام، کاربر باید به‌تناسب نسبت وثیقه‌گذاری (collateralization ratio) که توسط حاکمیت (governance) تعیین می‌شود، وثیقه تأمین کند.

به دارایی قابل وام‌گیری در Compound V3، «دارایی پایه» (base asset) گفته می‌شود. چون USDC یکی از محبوب‌ترین گزینه‌ها برای وام‌دهی و وام‌گیری است، در مثال‌های این مقاله از آن استفاده خواهیم کرد.

قرارداد هوشمندی که منطق اصلی وام‌دهی و وام‌گیری را اجرا می‌کند، با نام «Comet» شناخته می‌شود. مستندات رسمی و کدهای پروژه نیز از همین نام استفاده می‌کنند. نسخه سوم Compound هم‌اکنون روی شبکه اصلی اتریوم و برخی راهکارهای لایه دوم (L2) مثل Polygon، Base و Arbitrum فعال است. فهرست کامل بازارهای فعال Compound V3 از طریق منابع رسمی قابل مشاهده است.

این مقاله یک مرور کلی از نحوه استفاده از این قرارداد هوشمند و ساختار فایل‌های سالیدیتی ارائه می‌دهد.

بخش اول: استفاده از Compound

در نسخه سوم Compound، کاربران می‌توانند سه اقدام اصلی انجام دهند:

  1. وام‌دهی دارایی پایه

  2. تأمین وثیقه و وام‌گیری دارایی پایه

  3. لیکویید کردن وام‌های کم‌وثیقه

این سه قابلیت، ستون‌های اصلی عملکرد نسخه سوم Compound را تشکیل می‌دهند.پ

وام‌دهی USDC

ویدئوی زیر نحوه وام دهی توکن USDC در شبکه Polygon را نمایش می‌دهد. (برای مشاهده بازار USDC روی Polygon می‌توانید از این لینک استفاده کنید.)

افرادی که در این پروتکل مشارکت می‌کنند، توکن پاداشی به نام COMP دریافت می‌کنند. در تصویر مربوطه، فلش صورتی نشان می‌دهد که حساب موردنظر تاکنون ۰.۰۰۰۴ توکن COMP به‌عنوان پاداش کسب کرده است، اما این پاداش هنوز دریافت (claim) نشده است. علاوه بر این، این حساب تاکنون بیش از ۰.۰۶ دلار سود حاصل از وام‌دهی دریافت کرده است. این سود از تفاوت بین مقدار فعلی دارایی (۴۶۰۲.۰۶۴۹) و مقدار اولیه آن (۴۶۰۲.۰۰) به دست می‌آید که برابر با ۰.۰۶۴۹ دلار است.

تصویری از داشبورد وام‌دهی USDC

تفاوت قیمتی بین مقدار نمایش داده‌شده در باکس سبز و باکس زرد به این دلیل است که قیمت USDC همیشه دقیقاً برابر با ۱ دلار نیست. نمودار زیر قیمت‌های اخیر USDC در برابر دلار آمریکا (USDC/USD) را نشان می‌دهد که از طریق اوراکل چین لینک (Chainlink) روی شبکه پالیگان ثبت شده‌اند. همان‌طور که مشاهده می‌کنید، قیمت USDC در تمام لحظات دقیقاً برابر با ۱ دلار نیست و گاهی نوسانات جزئی دارد.

تصویری از نمودارهای USDC/USD

وام‌گیری USDC

ویدئوی زیر مراحل وام‌گیری را نمایش می‌دهد. در این مثال، حساب موردنظر ۰.۰۶ اتریوم (ETH) معادل تقریباً ۱۱۰ دلار را به‌عنوان وثیقه به پروتکل سپرده کرده و در ازای آن، ۱۰۰ دلار USDC وام گرفته است. این تراکنش در بازار وام‌دهی شبکه لایه دوم BASE صورت گرفته است. با استفاده از این روش، کاربر می‌تواند دارایی خود را بدون نیاز به فروش، نقد کند و از آن در کاربردهای دیگر استفاده نماید.

با بررسی کیف پول مرورگر، مشاهده می‌شود که اکنون حساب موردنظر دارای ۱۰۰ USDC روی شبکه Base است. در اینجا، USDCbC به‌عنوان نماد توکن شناخته می‌شود. این نماد بیانگر USDC بریج شده به شبکه Base است (Bridged USDC).

تصویری از کیف پول مرورگر

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

درک نرخ خالص وام گیری و وام دهی

تصویری از نرخ‌های خالص وام گیری و وام دهی

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

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

به‌طور دقیق‌تر:

  • وام گیرنده ها در حال حاضر ۶.۷۱٪ سود سالانه (APR) پرداخت می‌کنند (دایره قرمز بالا)

  • اما در ازای آن، ۲.۵۸٪ پاداش سالانه به‌صورت توکن COMP دریافت می‌کنند (دایره آبی بالا)

  • بنابراین نرخ خالص وام‌گیری برابر است با:
    ۶.۷۱٪ – ۲.۵۸٪ = ۴.۱۳٪

در سمت دیگر:

  • وام دهنده ها از وام دادن USDC به‌صورت مستقیم ۶.۴۷٪ سود سالانه کسب می‌کنند (دایره قرمز پایین)

  • و علاوه بر آن، ۴.۶۳٪ دیگر نیز از طریق پاداش توکن COMP به آن‌ها تعلق می‌گیرد (دایره آبی پایین)

  • بنابراین نرخ خالص سود وام دهی برابر می‌شود با:
    ۶.۴۷٪ + ۴.۶۳٪ = ۱۱.۱۰٪

در مجموع، چون وام گیرنده ها ۶.۷۱٪ بهره پرداخت می‌کنند و وام دهنده ها ۶.۴۷٪ از این مبلغ را دریافت می‌کنند، حدود ۰.۲۴٪ از بهره پرداختی مستقیماً به پروتکل اختصاص می‌یابد.

لازم به ذکر است که نرخ پاداش های توکن COMP به‌صورت دوره‌ای و از طریق رأی گیری حاکمیتی تغییر می‌کند.

بخش دوم: پیمایش در کدهای پروژه

نسخه سوم پروتکل Compound شامل ۴۳۰۴ خط کد سالیدیتی است؛ این عدد بدون احتساب کامنت‌ها و خطوط خالی محاسبه شده است.

تصویری برای پیمایش در کدبیس

معماری Compound V3 از نمای بالا (نمای 10,000 فوتی)

در تصویر زیر، نمایی از مخزن گیت‌هاب (GitHub) پروژه Compound V3 را مشاهده می‌کنید.

  • فایل‌هایی که با رنگ سبز مشخص شده‌اند، شامل منطق اصلی وام دهی و وام گیری هستند. این فایل‌ها هسته عملکرد پروتکل را تشکیل می‌دهند. در ادامه مقاله، رابطه وراثتی (inheritance) بین این فایل‌ها به‌صورت دقیق توضیح داده خواهد شد. در میان این فایل‌ها، قرارداد هوشمند اصلی به نام Comet، مسئولیت اجرای منطق وام دهی و وام گیری را بر عهده دارد.

  • فایل‌هایی که با رنگ آبی هایلایت شده‌اند، مربوط به قراردادهایی هستند که در زمان ارتقاء، نسخه های جدیدی از Comet را مستقر (deploy) می‌کنند. این بخش نیز ساختاری سلسله مراتبی دارد که در ادامه بررسی خواهد شد.

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

تصویری از مخزن گیت‌هاب Compound V3

نمودار زیر نمایی کلی از قراردادهای هوشمندی را نشان می‌دهد که در نسخه سوم Compound مستقر شده‌اند. این نمودار تنها یک نمای سطح بالا (High-Level Overview) ارائه می‌دهد؛ جزئیات فنی دقیق‌تر در بخش‌های بعدی توضیح داده خواهد شد.

نکته مهم این است که کدگذاری رنگ‌ها در این نمودار با هایلایت‌های توضیح‌داده‌شده در بخش قبل مطابقت دارد:

  • رنگ سبز نشان‌دهنده قرارداد اصلی وام دهی و وام گیری (Comet) است که هسته عملکرد پروتکل محسوب می‌شود.

  • رنگ آبی مربوط به قراردادهایی است که وظیفه استقرار (Deploy) نسخه‌های جدید Comet را در هنگام ارتقاء بر عهده دارند.

  • رنگ صورتی بیانگر قرارداد توزیع پاداش‌ها است که مسئول ارسال توکن های COMP به کاربران است.

این نمودار به درک ساختار کلی سیستم کمک می‌کند و نشان می‌دهد که چگونه اجزای مختلف با هم در ارتباط هستند و چه وظایفی دارند.

تصویری از نمای کلی سطح بالا Compound V3

بیشتر کاربران هنگام استفاده از Compound V3 از طریق قرارداد Comet Proxy (که در مخزن گیت‌هاب نمایش داده نشده) یا از طریق قرارداد پاداش‌ها (Rewards) با پروتکل تعامل می‌کنند. تمام منطق مربوط به عملکردی که کاربران با آن سر و کار دارند، در قرارداد Comet قرار دارد. Comet Proxy صرفاً نقش یک واسط را دارد و عملکرد خود را به این قرارداد اصلی واگذار (delegate) می‌کند.

قراردادهای مربوط به پیکربندی و کارخانه (Configuration و Factory) نیز وظیفه دارند تا نسخه‌های جدید Comet را زمانی که رأی گیری حاکمیتی برای ارتقاء انجام می‌شود، مستقر کنند.

قراردادهایی که در نمودار علامت ستاره (*) دارند، دارای چندین قرارداد پایه (ancestor contracts) هستند که از آن‌ها ارث بری کرده‌اند. در بخش بعد، زنجیره وراثت (inheritance chain) مربوط به قرارداد Comet را به‌صورت دقیق بررسی خواهیم کرد.

روش غیرمعمول Compound V3 برای به‌روزرسانی پارامترها از طریق حاکمیت

در Compound V3، تغییر پارامترهایی مانند مدل های نرخ بهره یا ضریب لیکوئید شدن (liquidation factors) از طریق رأی گیری حاکمیتی امکان‌پذیر است، به‌ویژه زمانی که شرایط اقتصاد رمزارزی تغییر می‌کند.

اما نکته مهم اینجاست:
تمام این اطلاعات به‌جای ذخیره در متغیرهای ذخیره سازی (storage)، در متغیرهای غیرقابل‌تغییر (immutable) نگهداری می‌شوند. به همین دلیل، برای اعمال تغییرات، نمی‌توان مستقیماً مقادیر را به‌روزرسانی کرد؛ بلکه باید یک نسخه جدید از قرارداد Comet مستقر (deploy) شود و سپس پراکسی (proxy) به این نسخه جدید اشاره کند.

در نگاه اول، این طراحی ممکن است غیرعادی به نظر برسد، اما مزایای مهمی دارد:

  1. متغیرهای immutable بسیار کارآمدتر از متغیرهای ذخیره سازی هستند و هزینه گس را به‌طور چشمگیری کاهش می‌دهند.

  2. قراردادهای اصلی نیازی به تعریف توابع تنظیم‌کننده (setter) ندارند، بنابراین ساختار کد ساده‌تر و ایمن‌تر باقی می‌ماند.

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

وراثت در قرارداد Comet

در نمودار زیر، سلسله مراتب وراثت (inheritance hierarchy) قرارداد Comet نمایش داده شده است. در این بخش، یک مرور سطح بالا بر هرکدام از قراردادهای پدر (ancestor contracts) خواهیم داشت تا ساختار کلی و نقش آن‌ها در شکل‌گیری Comet را بهتر درک کنیم.

تصویری از میراث Comet

CometMath.sol (بیضی خاکستری بالا-چپ)

فایل CometMath.sol مجموعه‌ای از توابع کمکی را شامل می‌شود که هدف اصلی آن‌ها تبدیل انواع عددی unsigned (بدون علامت) با بیت بالاتر به انواع با بیت پایین‌تر است.

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

برای مثال، اگر بخواهیم یک uint256 را به uint104 تبدیل کنیم اما مقدار آن بزرگ‌تر از حداکثر مقدار قابل ذخیره در uint104 باشد، این عملیات باعث بازگرداندن تراکنش خواهد شد.

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

از آنجایی که فایل CometMath.sol نسبتاً کوچک است، در ادامه کل آن را نشان می دهیم:

تصویری از ComethMath.sol

CometStorage.sol (بیضی قرمز)

تمام متغیرهای ذخیره سازی (storage) مورد استفاده در قرارداد Comet، فقط و فقط در فایل CometStorage.sol تعریف شده‌اند و در هیچ جای دیگری از زنجیره وراثت دیده نمی‌شوند.

به بیان دقیق‌تر:
هیچ‌یک از قراردادهای پدر یا فرزند در ساختار وراثتی Comet، به‌جز CometStorage، هیچ متغیر ذخیره‌ای ندارند.

این طراحی هدفمند انجام شده و مزایای مشخصی دارد:

  • کنترل کامل ساختار حافظه را فراهم می‌کند، که برای قراردادهای قابل ارتقاء (upgradeable) بسیار حیاتی است.

  • از بروز خطاهای احتمالی ناشی از ترتیب نادرست متغیرهای storage در وراثت جلوگیری می‌شود.

  • کدهای منطقی و کدهای مربوط به حافظه از هم جدا باقی می‌مانند که موجب افزایش خوانایی و امنیت می‌شود.

در نتیجه، CometStorage.sol به‌عنوان لایه مرکزی مدیریت داده ها در قرارداد Comet عمل می‌کند و تمام وضعیت ها (state) از جمله اطلاعات وام ها، وثیقه ها، نرخ ها، آدرس ها و غیره در این فایل تعریف می‌شوند.

CometCore.sol (بیضی خاکستری ردیف دوم)

فایل CometCore.sol مسئول تعریف منطق اصلی محاسبه و پیگیری بهره (interest) برای وام دهندگان و وام گیرندگان در پروتکل Compound V3 است.

این فایل مشخص می‌کند که چگونه پروتکل:

  • بهره‌ تجمع‌یافته را محاسبه می‌کند

  • تفاوت بین مقادیر اصلی (Principal Value) و فعلی (Present Value) را تشخیص می‌دهد

علاوه بر این، در CometCore.sol تعدادی ثابت سراسری (global constants) نیز تعریف شده‌اند که در بخش‌های مختلف سیستم مورد استفاده قرار می‌گیرند.

در ادامه مقاله، زمانی که درباره مفهوم “مقدار اصلی” و “مقدار فعلی” صحبت می‌کنیم، به‌صورت دقیق‌تر وارد جزئیات این فایل خواهیم شد تا نحوه عملکرد آن را به‌خوبی درک کنیم.

CometMainInterface.sol (بیضی آبی سمت چپ)

همان‌طور که از نام آن پیداست، CometMainInterface.sol در واقع فایل اینترفیس (interface) قرارداد Comet است.

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

از آنجا که ساختار و نقش اینترفیس ها در برنامه نویسی سالیدیتی کاملاً واضح و شناخته‌شده است، نیازی به توضیح بیشتر درباره این فایل وجود ندارد و از بحث پیرامون آن صرف‌نظر می‌کنیم.

Comet.sol (بیضی سبز)

فایل Comet.sol هسته اصلی و مهم‌ترین بخش کل پروژه Compound V3 است — ستاره اصلی این معماری.

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

  • وام دهی (Lend): واریز دارایی پایه به پروتکل برای کسب سود

  • وام‌گیری (Borrow): دریافت دارایی پایه در ازای تأمین وثیقه

  • بازپرداخت (Repay): بازگرداندن وام گرفته شده

  • لیکویید کردن (Liquidate): تسویه وام هایی که وثیقه آن‌ها کمتر از حد مجاز شده است

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

به‌طور خلاصه، اگر بخواهیم تنها یک فایل را به‌عنوان درگاه اصلی کاربران معرفی کنیم، بدون شک Comet.sol همان فایل کلیدی خواهد بود.

CometExt: یک افزونه برای Comet از طریق delegatecall

برای عبور از محدودیت ۲۴ کیلوبایتی در استقرار قراردادهای سالیدیتی، پروتکل Compound از یک الگوی هوشمندانه به نام الگوی افزونه با fallback (fallback-extension pattern) استفاده کرده است.

در این روش، قرارداد اصلی یعنی Comet.sol، بخشی از توابع فرعی و غیرحیاتی را به فایل CometExt واگذار می‌کند. این کار با استفاده از دستور delegatecall انجام می‌شود که به قرارداد افزونه اجازه می‌دهد توابع اضافی را اجرا کند، اما در زمینه (context) حافظه قرارداد اصلی.

برای مثال:

  • تابع name() در فایل Comet.sol تعریف نشده و بنابراین روی سایت‌هایی مانند Etherscan قابل مشاهده نیست.

  • با این حال، اگر همین تابع را با ابزارهایی مانند Foundry cast فراخوانی کنیم، قرارداد رفتاری کاملاً طبیعی از خود نشان می‌دهد، انگار که این تابع وجود دارد.

تصویری که CometExt را به عنوان افزونه‌ای برای Comet از طریق delegatecall نشان می‌دهد

آنچه اتفاق می‌افتد این است که فراخوانی تابع، به تابع fallback برخورد می‌کند و سپس این فراخوانی با استفاده از delegatecall به قرارداد CometExt منتقل می‌شود. در CometExt، تابعی به نام name() وجود دارد که پاسخ درخواست را ارائه می‌دهد.

نکته مهم اینجاست که CometExt باید ساختار حافظه (storage layout) قرارداد Comet را رعایت کرده و آن را بدون ایجاد تداخل، گسترش دهد. این هماهنگی از طریق تقلید ساختار وراثتی Comet در CometExt به‌دست می‌آید.

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

در ادامه، نموداری دقیق‌تر نمایش داده شده که رابطه میان Comet و CometExt را به‌صورت کامل نشان می‌دهد.

یک نمودار واضح که رابطه بین Comet و CometExt را نشان می‌دهد

صدور پاداش ها (Rewards Issuance)

برای صدور پاداش‌های غیرمرتبط با سود و بهره، فقط یک قرارداد اختصاصی وجود دارد که در تصویر با باکس صورتی مشخص شده است.

تصویری برای صدور پاداش

در اکوسیستم Compound، وام دهندگان و وام گیرندگان به‌ازای مشارکت خود توکن های COMP دریافت می‌کنند. قرارداد Comet وظیفه دارد میزان مشارکت کاربران را ردیابی کند، اما وظیفه صدور و توزیع پاداش‌ها بر عهده قرارداد Rewards است.

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

چرخه عمر یک بروزرسانی پارامتر

همان‌طور که پیش‌تر توضیح داده شد، قرارداد Comet بر پایه متغیرهای غیرقابل‌تغییر (immutable) تنظیم شده است. بنابراین، برای اعمال تغییر در این پارامترها، کافی نیست مقدار جدیدی بروزرسانی شود؛ بلکه باید قرارداد جدیدی مستقر شود و سپس پراکسی به پیاده سازی جدید اشاره کند. این فرآیند توسط قراردادهای پیکربندی (Configuration) مدیریت می‌شود.

در عمل، تغییر منحنی نرخ بهره بسیار نادر است. برای مثال، قرارداد مستقر روی شبکه اصلی (mainnet) تاکنون تنها سه بار دستخوش تغییر در منحنی نرخ بهره شده است:

البته نرخ بهره تنها پارامتری نیست که قابلیت تغییر دارد. نسبت لیکوئید شدن (liquidation ratios) و حتی نوع دارایی‌های مجاز برای وثیقه گذاری نیز می‌توانند با رأی گیری تغییر کنند.

افرادی که به جزئیات بیشتر علاقه دارند می‌توانند به صفحه پیشنهادهای حاکمیتی (governance proposals) مراجعه کنند.

در GIF زیر، ساختار قرارداد پیکربندی نشان داده شده و مشخص می‌شود که چگونه حاکمیت، نسخه‌های جدیدی از Comet را با پارامترهای به‌روزشده مستقر می‌کند.

تصویری از پیکربندی ساختار قرارداد هوشمند

CometConfiguration.sol و ConfiguratorStorage.sol

فایل CometConfiguration.sol ساختاری (struct) را تعریف می‌کند که تمام رفتارهای قرارداد Comet را با پارامترهای مشخص تنظیم می‌کند. این ساختار شامل متغیرهایی است که نحوه عملکرد سیستم را تعیین می‌کنند.

در مقابل، فایل ConfiguratorStorage.sol صرفاً وظیفه دارد این ساختارها را ذخیره کند.

فایل ConfiguratorStorage این ساختارها را به ارث می‌برد و آن‌ها را در قالب mapping در حافظه ذخیره می‌کند.

نکته مهم: این متغیرهای ذخیره سازی، بخشی از قرارداد Comet نیستند. بلکه قرارداد Configurator با استفاده از این تنظیمات ذخیره‌شده، نسخه‌های جدید Comet را مستقر می‌کند.

در ادامه، تصویری از بخشی از کدهای مربوط به CometConfiguration و ConfiguratorStorage نمایش داده شده است.

تصویری از کد مربوط به CometConfiguration و ConfiguratorStorage

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

زمانی که یک نسخه جدید از Comet با پارامترهای به‌روزشده مستقر می‌شود، تنها کافی است یک متغیر خاص در حافظه (storage) به‌روزرسانی شود و سایر متغیرها بدون تغییر باقی می‌مانند. برای مثال، اگر فقط بخواهیم آستانه لیکوئید شدن (liquidation threshold) مربوط به وثیقه wBTC را تغییر دهیم، فقط همان متغیر مرتبط در قرارداد configurator تغییر می‌کند و نیازی به بازنویسی یا ارسال مجدد کل ساختار نیست.

قرارداد Configurator.sol در سالیدیتی

قرارداد Configurator.sol از ConfigurationStorage ارث بری می‌کند و مجموعه‌ای از توابع تنظیم‌کننده (setter) را فراهم می‌سازد که فقط توسط حاکمیت (governance) قابل فراخوانی هستند.

فایل Configurator.sol نسبتاً بزرگ است، بنابراین در اینجا کل کد آن نمایش داده نمی‌شود. با این حال، تنها با مشاهده رویدادهایی (events) که در این قرارداد تعریف شده‌اند، می‌توان به‌راحتی متوجه شد که این قرارداد چه کاری انجام می‌دهد: این قرارداد فیلدهای خاصی از ساختار تنظیمات (struct) را به‌روزرسانی می‌کند — همان ساختاری که برای استقرار نسخه جدیدی از Comet استفاده می‌شود.

به‌عبارت دیگر، Configurator.sol به حاکمیت این امکان را می‌دهد که هر پارامتر از ساختار پیکربندی را به‌صورت جداگانه و هدفمند تغییر دهد، بدون نیاز به بازنویسی کل ساختار یا استقرار کامل همه چیز از ابتدا.

تصویری از Configurator.sol که عملکرد قرارداد را نشان می‌دهد

قرارداد Configurator.sol همچنین شامل تابعی به نام deploy() است که وظیفه استقرار نسخه‌های جدیدی از قرارداد Comet را بر عهده دارد.

تصویری از Configurator.sol که deploy() را نشان می‌دهد

در کدی که در بالا نمایش داده شده، CometFactory در فایل CometFactory.sol تعریف شده است. این فایل بسیار کوچک است، به همین دلیل می‌توان آن را به‌طور کامل نمایش داد.

نکته‌ای که باید به آن توجه کرد این است که نام تابع clone کمی گمراه‌کننده است. با وجود اینکه ممکن است تصور شود این تابع یک کلون پراکسی (proxy clone) ایجاد می‌کند، اما در واقع اینگونه نیست. تابع clone در اینجا یک نمونه جدید (new instance) از قرارداد Comet را به‌صورت کامل مستقر می‌کند، نه یک پراکسی یا کپی از قرارداد موجود. بنابراین، علی‌رغم نام آن، عملکرد واقعی تابع clone در این فایل، استقرار مستقل یک پیاده سازی جدید از Comet است.

تصویری که عملکرد کلون را نشان می‌دهد

در اینجا دوباره به همان انیمیشنی که پیش‌تر اشاره شد ارجاع می‌دهیم تا تمام مباحث قبلی را به‌صورت یکپارچه مرور کنیم.

تصویری از پیکربندی ساختار قرارداد هوشمند

نمونه واقعی از تغییر پارامتر

برای درک بهتر این فرآیند، به پیشنهاد حاکمیتی شماره ۱۶۲ مراجعه می‌کنیم. در این مثال، مشاهده می‌کنیم که این پیشنهاد در ابتدا چندین تابع setter را روی قرارداد Configurator فراخوانی کرده تا مقادیر پارامترهای مشخصی را به‌روزرسانی کند. سپس در گام نهایی (مرحله ۸)، یک نمونه جدید از قرارداد Comet مستقر شده است.

تصویری از مثال واقعی تغییر پارامتر

همه چیز در کنار هم

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

تصویری که رابطه بین همه فایل‌ها و نحوه تعامل آنها با یکدیگر را نشان می‌دهد

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

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

دوره صفر تا صد آموزش بین المللی لینوکس
  • انتشار: ۲۵ تیر ۱۴۰۴

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

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

مشاهده همه

نظرات

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