آموزش نحوه محاسبه mintFee در Uniswap V2

پروتکل یونی سواپ V2 طوری طراحی شده که یک‌ششم از کارمزد هر مبادله (swap) را به خودش اختصاص دهد. این سهم که به آن mintFee در Uniswap V2 گفته می‌شود، هنگام فراخوانی توابع mint یا burn به پروتکل تعلق می‌گیرد. با توجه به این‌که کارمزد هر تراکنش برابر با ۰.۳ درصد است، یک‌ششم آن می‌شود ۰.۰۵ درصد. در نتیجه، ۰.۰۵ درصد از حجم هر معامله به‌صورت غیرمستقیم برای پروتکل در نظر گرفته می‌شود.

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

پیش نیازها

برای دنبال کردن این بخش، باید با همه فصل‌های قبلی کتاب Uniswap V2 آشنا باشید.

دلیل ناکارآمد بودن دریافت کارمزد در هر مبادله

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

یونی سواپ برای جلوگیری از این هزینه اضافی، کارمزد پروتکل را هنگام اجرای توابع burn یا mint دریافت می‌کند. چون این توابع نسبت به مبادله توکن ها (swap) کمتر فراخوانی می‌شوند، اجرای آن‌ها باعث صرفه‌جویی در مصرف گس می‌شود.

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

اصطلاح‌شناسی مربوط به fee و mintFee

برای جلوگیری از سردرگمی در واژه‌ها، در این مقاله از عبارت “fee” برای اشاره به ۰.۳ درصد کارمزدی که از معامله‌گران در زمان مبادله (swap) دریافت می‌شود استفاده می‌کنیم، و عبارت “mintFee” را برای سهم یک‌ششمی از این ۰.۳ درصد به کار می‌بریم. بله، استفاده از واژه “fee” در هر دو اصطلاح شاید انتخاب دقیقی نباشد، اما در متون مرتبط با یونی سواپ، معمولاً همین واژه‌گذاری رایج است و باید با آن کنار بیاییم.

مقدار نقدینگی (Liquidity) برابر است با ریشه دوم حاصل‌ضرب موجودی دو توکن داخل استخر. توضیح منطقی این فرمول در مقاله مربوط به تابع swap در یونی سواپ V2 ارائه شده است. در برخی منابع علمی از نماد
برای نمایش آن استفاده می‌شود که در آن k = xy بوده و x و y به ترتیب بیانگر موجودی دو توکن در استخر هستند (یعنی ذخایر توکن x و توکن y).

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

فرضیات محاسبه mintFee در Uniswap V2

برای اینکه محاسبه mintFee به‌درستی انجام شود، یونی سواپ V2 بر پایه دو اصل تغییرناپذیر (invariant) مهم عمل می‌کند:

  1. اگر توابع mint() و burn() فراخوانی نشوند، نقدینگی استخر فقط می‌تواند افزایش یابد.

  2. افزایش نقدینگی تنها به دلیل دریافت کارمزد یا دریافت اهدا (donation) اتفاق می‌افتد. بنابراین، با اندازه‌گیری میزان افزایش نقدینگی از زمان آخرین تراکنش mint() یا burn()، استخر می‌تواند بفهمد چه مقدار کارمزد دریافت شده است.

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

محاسبه مثالی از mintFee در Uniswap V2

فرض کنید در زمان t1، موجودی استخر برابر با ۱۰ عدد توکن0 و ۱۰ عدد توکن1 باشد.

بعد از انجام تعداد زیادی معامله و جمع‌آوری کارمزد، در زمان t2، موجودی استخر به ۴۰ توکن0 و ۴۰ توکن1 می‌رسد.

مقدار نقدینگی برابر با ریشه دوم حاصل‌ضرب موجودی دو توکن است، یعنی:

در این مثال:

  • در زمان t1، نقدینگی برابر با  بوده است.

  • در زمان t2، نقدینگی به افزایش یافته است.

به عبارت دیگر، نقدینگی از ۱۰ به ۴۰ رسیده، یعنی ۳۰ واحد از این رشد ناشی از کارمزد معاملات بوده است.

حالا هدف این است که به آدرس دریافت‌کننده کارمزد پروتکل، به‌اندازه‌ای توکن نقدینگی (LP token) صادر کنیم که یک‌ششم از این بخش سودآور را دریافت کند. چون ۳۰ واحد نقدینگی ناشی از کارمزد است، سهم پروتکل باید برابر باشد با:
واحد نقدینگی.

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

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

استخراج فرمول ریاضی mintFee در Uniswap V2

برای محاسبه دقیق میزان توکن‌های LP که باید به پروتکل داده شود، از نمادگذاری زیر استفاده می‌کنیم:

  • s: عرضه فعلی توکن‌های LP پیش از اینکه توکن‌های کارمزد پروتکل صادر شوند.

  • η: تعداد توکن‌های LP که باید به پروتکل صادر شوند (mint شوند). این مقدار باید به‌اندازه‌ای باشد که پروتکل بتواند یک‌ششم از نقدینگی حاصل از سود (profit liquidity) را بازخرید کند.

  • : نقدینگی اولیه یعنی همان مقدار نقدینگی که تأمین‌کنندگان وارد استخر کرده‌اند.

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

  • d: مقدار نقدینگی متعلق به تأمین‌کنندگان (LPها) پس از کسر کارمزد پروتکل. این مقدار برابر است با نقدینگی اولیه به‌علاوه پنج‌ششم از سود.

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

برای محاسبه η مشاهده می‌کنیم که رابطه تغییرناپذیر زیر باید برقرار باشد:

به عبارت دیگر، عرضه قبلی توکن‌های LP یعنی s، می‌تواند نقدینگی متعلق به تأمین‌کنندگان (LPها) را بازخرید کند، و تعداد η توکن LP می‌تواند مقدار نقدینگی متعلق به پروتکل را بازخرید کند.

نمودار زیر مقدار η را بر اساس تغییرات نقدینگی محاسبه می‌کند.

استخراج جبری کارمزد پروتکل

کد تابع _mintFee() در Uniswap V2

با در نظر گرفتن استخراج جبری قبلی، قسمت اصلی تابع _mintFee در یونی سواپ V2 باید تا حد زیادی قابل درک باشد. در این بخش، برخی از تغییرات در نمادگذاری را مرور می‌کنیم:

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

  • نقدینگی قبلی، یعنی ، در کد با نام kLast ثبت می‌شود.

  • عرضه توکن‌های LP پیش از رقیق شدن، یعنی s، با متغیر totalSupply نمایش داده می‌شود.

  • این تابع تغییردهنده وضعیت قرارداد است، به این معنا که درون خود تابع، mintFee را محاسبه و صادر می‌کند، نه اینکه فقط مقدار آن را برگرداند. (این مورد در کد معمولاً با رنگ آبی مشخص می‌شود.)

  • فعال یا غیرفعال بودن کارمزد پروتکل با استفاده از یک پرچم به نام feeOn کنترل می‌شود، که هنوز درباره آن صحبت نکرده‌ایم.

کد سالیدیتی تابع _mintFee()

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

محل به‌روزرسانی kLast

در کدی که پیش‌تر بررسی شد، متغیر kLast تنها زمانی مقداردهی می‌شود که feeOn به مقدار false تغییر پیدا کند. این مقدار در پایان توابع mint و burn تنظیم می‌شود، اما در تابع swap این اتفاق نمی‌افتد؛ دلیل آن هم این است که ما فقط می‌خواهیم رشد نقدینگی ناشی از کارمزدها را بین دو نقطه‌ی واریز (mint) و برداشت (burn) بسنجیم. در مستندات تصویری یونی سواپ، محل مقداردهی kLast با کادر زرد رنگ مشخص شده است.

مقداردهی kLast در تابع Mint

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

مقداردهی kLast در تابع Burn

تابع Burn از Uniswap با سوئیچ کارمزد برجسته شده

شرایط عملکرد تابع _mintFee

حالا که فهمیدیم kLast چگونه و کجا به‌روزرسانی می‌شود، می‌توانیم عملکرد تابع _mintFee را به‌طور کامل توضیح دهیم.

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

  1. feeOn برابر false است → هیچ توکنی صادر نمی‌شود (هایلایت سبز)

  2. feeOn برابر false است و kLast صفر است (هایلایت زرد)

  3. feeOn برابر false است ولی kLast صفر نیست (هایلایت زرد)

  4. feeOn برابر true است اما افزایش نقدینگی رخ نداده است (هایلایت نارنجی)

  5. feeOn برابر true است و افزایش نقدینگی اتفاق افتاده → mintFee باید صادر شود (هایلایت آبی)

برای درک بهتر منطق پشت این شاخه‌ها، نمودار درخت تصمیم‌گیری (decision tree) ارائه شده که در آن، هر شاخه با رنگی مشابه شرایط گفته‌شده در کد علامت‌گذاری شده است.

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

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

پکیج آموزش سی شارپ | مختص ورود به بازار کار + آموزش ساخت بازی Quiz of King
  • انتشار: ۲۱ خرداد ۱۴۰۴

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

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

مشاهده همه

نظرات

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