تقنيات مذهلة في تطوير العقود: الدروس المستفادة من كود Uniswap
مؤخراً أثناء كتابة دليل تطوير بورصة لامركزية، استندت إلى تنفيذ الشفرة لبعض DEX المعروف، وتعلمت الكثير من المعرفة الجديدة. كوني مطوراً سبق له أن قام بتطوير عقد NFT بسيط، هذه هي المرة الأولى التي أحاول فيها تطوير عقود Defi، وأعتقد أن هذه النصائح الصغيرة ستكون مفيدة جداً للمبتدئين الذين يرغبون في تعلم تطوير العقود.
دعونا نلقي نظرة على هذه الحيل المثيرة للاهتمام، وبعضها يمكن أن يُطلق عليه حتى الحيل الغريبة.
عنوان نشر العقد القابل للتنبؤ
عادةً ما تكون العناوين التي يتم الحصول عليها عند نشر العقد عشوائية إلى حد ما، وذلك بسبب ارتباطها بالـ nonce، مما يجعل من الصعب التنبؤ بعنوان العقد. ومع ذلك، في بعض السيناريوهات، نحتاج إلى استنتاج عنوان العقد من خلال أزواج التداول والمعلومات ذات الصلة. هذا مفيد في العديد من الحالات، مثل تحديد صلاحيات التداول أو الحصول على عنوان تجمع السيولة.
يمكن إنشاء العقد باستخدام طريقة CREATE2 من خلال إضافة معامل salt، وعنوان العقد الذي تم إنشاؤه بهذه الطريقة يكون قابلاً للتنبؤ. منطق توليد العنوان هو: العنوان الجديد = hash("0xFF"، عنوان المنشئ، salt، initcode).
استخدام دوال الاسترجاع بشكل جيد
في Solidity، يمكن للعقود استدعاء بعضها البعض. هناك سيناريو حيث تستدعي A طريقة معينة B، ثم تقوم B باستدعاء A في الطريقة التي تم استدعاؤها، وهذا مفيد في بعض السيناريوهات.
على سبيل المثال، عندما تستدعي طريقة swap لعقد DEX معين للتداول، ستقوم باستدعاء swapCallback، مع تمرير الرمز المميز المطلوب فعليًا لهذه الصفقة. يحتاج المستدعي إلى تحويل الرموز المميزة المطلوبة للتداول إلى عقد DEX في الاستدعاء، بدلاً من تقسيم طريقة swap إلى جزئين ليقوم المستدعي باستدعائه. وهذا يضمن أمان طريقة swap، ويضمن تنفيذ المنطق بالكامل، دون الحاجة إلى تسجيل متغيرات معقدة لضمان الأمان.
استخدم الاستثناءات لنقل المعلومات، استخدم try catch لتنفيذ تقدير المعاملات
في كود بعض DEX، وجدنا أنه يقوم بتغليف طريقة swap باستخدام try catch. لماذا؟ لأننا بحاجة لمحاكاة طريقة swap لتقدير الرموز المطلوبة للتداول، ولكن أثناء التقدير، لن يتم إجراء تبادل الرموز فعليًا، لذلك سيظهر خطأ. يقوم بإلقاء خطأ خاص في دالة رد الاتصال الخاصة بالتداول، ثم يلتقط هذا الخطأ، ويحلل المعلومات المطلوبة من رسالة الخطأ.
يبدو أن هذا نوع من التحايل، لكنه عملي للغاية. بهذه الطريقة، لا حاجة لتعديل طريقة السواب لتقدير طلبات التداول، كما أن المنطق يصبح أبسط.
استخدام الأعداد الكبيرة لحل مشاكل الدقة
في كود DEX، هناك الكثير من المنطق الحسابي، مثل حساب الرموز المتبادلة بناءً على السعر الحالي والسيولة. خلال هذه العملية، يجب علينا تجنب فقدان الدقة عند إجراء عمليات القسمة. في بعض التنفيذات، يتم استخدام "<< FixedPoint96.RESOLUTION" بشكل متكرر خلال عملية الحساب، وهو ما يمثل الإزاحة لليسار بمقدار 96 بت، مما يعادل الضرب في 2^96. بعد الإزاحة لليسار، يتم إجراء عملية القسمة، مما يضمن عدم تجاوز ( أثناء المعاملات العادية، وعادةً ما يتم حسابها باستخدام uint256، مما يكفي لضمان الدقة في حالة ).
حساب العائد بطريقة Share
في DEX، نحتاج إلى تسجيل عوائد رسوم المعاملات لمزودي السيولة LP(. من الواضح أنه لا يمكن تسجيل رسوم كل LP في كل معاملة، لأن ذلك سيستهلك الكثير من الغاز. فما هو الحل؟
يمكن تعريف هيكل يتضمن feeGrowthInside0LastX128 و feeGrowthInside1LastX128 في Position، حيث تسجل هذه القيم رسوم المعاملات التي ينبغي أن يحصل عليها كل سيولة في آخر مرة تم فيها سحب الرسوم من كل مركز.
ببساطة، يكفي تسجيل إجمالي الرسوم و الرسوم التي يجب تخصيصها لكل سيولة. عند سحب الرسوم، يمكن حساب الرسوم القابلة للسحب بناءً على السيولة المحتفظ بها. هذا مشابه لامتلاك أسهم في شركة، حيث تحتاج فقط إلى معرفة الأرباح التاريخية لكل سهم، بالإضافة إلى الأرباح التي حصلت عليها في آخر سحب.
![Web3 سلسلة المبتدئين: الحيل الصغيرة التي تعلمتها من كود Uniswap لتطوير العقود])https://img-cdn.gateio.im/webp-social/moments-45e66af69435e6d4412ae506e77ab893.webp(
ليس من الضروري الحصول على جميع المعلومات من السلسلة
التخزين على السلسلة مكلف نسبيًا، لذا ليس من الضروري أن تكون جميع المعلومات على السلسلة أو الحصول عليها من السلسلة. على سبيل المثال، العديد من واجهات برمجة التطبيقات التي تستدعيها المواقع الأمامية لبعض DEX هي واجهات برمجة التطبيقات التقليدية Web2.
يمكن تخزين قائمة أحواض التداول ومعلومات أحواض التداول في قاعدة بيانات عادية، وقد يحتاج البعض إلى المزامنة بشكل دوري من السلسلة، ولكن لا يلزم استدعاء واجهة RPC المقدمة من السلسلة أو خدمات العقد للحصول على البيانات ذات الصلة في الوقت الحقيقي.
بالطبع، المعاملات الرئيسية تتم بالتأكيد على السلسلة.
تعلم تقسيم العقود، واستخدام العقود القياسية الموجودة
قد يتضمن المشروع عدة عقود تم نشرها فعليًا. حتى لو تم نشر عقد واحد فقط فعليًا، يمكننا أيضًا تقسيم العقد إلى عدة عقود للحفاظ عليها من خلال طريقة الوراثة.
بالإضافة إلى ذلك، يمكن استخدام عقود معيارية مثل @openzeppelin/contracts/token/ERC721/ERC721.sol مباشرة. بهذه الطريقة، يمكن إدارة المراكز بطريقة NFT من جهة، ومن جهة أخرى، يمكن تحسين كفاءة التطوير باستخدام عقود معيارية موجودة.
ملخص
تجربة عملية لتطوير نسخة بسيطة من بورصة لامركزية، ستساعدك على فهم أعمق لتنفيذ رموز DEX، وستتعلم أيضًا المزيد من النقاط المعرفية في المشاريع العملية. سواء كنت مهتمًا بتطوير مشاريع Web3 أو DeFi، فإن الخبرة العملية ستكون مفيدة لك كثيرًا.
![Web3 سلسلة للمبتدئين: النصائح الصغيرة لتطوير العقود التي تعلمتها من كود Uniswap])https://img-cdn.gateio.im/webp-social/moments-f95ddc9d89809cf11dbe65b9bafda157.webp(
قد تحتوي هذه الصفحة على محتوى من جهات خارجية، يتم تقديمه لأغراض إعلامية فقط (وليس كإقرارات/ضمانات)، ولا ينبغي اعتباره موافقة على آرائه من قبل Gate، ولا بمثابة نصيحة مالية أو مهنية. انظر إلى إخلاء المسؤولية للحصول على التفاصيل.
7 تقنيات لتطوير العقود: تعلم أفضل ممارسات DeFi من كود DEX
تقنيات مذهلة في تطوير العقود: الدروس المستفادة من كود Uniswap
مؤخراً أثناء كتابة دليل تطوير بورصة لامركزية، استندت إلى تنفيذ الشفرة لبعض DEX المعروف، وتعلمت الكثير من المعرفة الجديدة. كوني مطوراً سبق له أن قام بتطوير عقد NFT بسيط، هذه هي المرة الأولى التي أحاول فيها تطوير عقود Defi، وأعتقد أن هذه النصائح الصغيرة ستكون مفيدة جداً للمبتدئين الذين يرغبون في تعلم تطوير العقود.
دعونا نلقي نظرة على هذه الحيل المثيرة للاهتمام، وبعضها يمكن أن يُطلق عليه حتى الحيل الغريبة.
عنوان نشر العقد القابل للتنبؤ
عادةً ما تكون العناوين التي يتم الحصول عليها عند نشر العقد عشوائية إلى حد ما، وذلك بسبب ارتباطها بالـ nonce، مما يجعل من الصعب التنبؤ بعنوان العقد. ومع ذلك، في بعض السيناريوهات، نحتاج إلى استنتاج عنوان العقد من خلال أزواج التداول والمعلومات ذات الصلة. هذا مفيد في العديد من الحالات، مثل تحديد صلاحيات التداول أو الحصول على عنوان تجمع السيولة.
يمكن إنشاء العقد باستخدام طريقة CREATE2 من خلال إضافة معامل salt، وعنوان العقد الذي تم إنشاؤه بهذه الطريقة يكون قابلاً للتنبؤ. منطق توليد العنوان هو: العنوان الجديد = hash("0xFF"، عنوان المنشئ، salt، initcode).
استخدام دوال الاسترجاع بشكل جيد
في Solidity، يمكن للعقود استدعاء بعضها البعض. هناك سيناريو حيث تستدعي A طريقة معينة B، ثم تقوم B باستدعاء A في الطريقة التي تم استدعاؤها، وهذا مفيد في بعض السيناريوهات.
على سبيل المثال، عندما تستدعي طريقة swap لعقد DEX معين للتداول، ستقوم باستدعاء swapCallback، مع تمرير الرمز المميز المطلوب فعليًا لهذه الصفقة. يحتاج المستدعي إلى تحويل الرموز المميزة المطلوبة للتداول إلى عقد DEX في الاستدعاء، بدلاً من تقسيم طريقة swap إلى جزئين ليقوم المستدعي باستدعائه. وهذا يضمن أمان طريقة swap، ويضمن تنفيذ المنطق بالكامل، دون الحاجة إلى تسجيل متغيرات معقدة لضمان الأمان.
استخدم الاستثناءات لنقل المعلومات، استخدم try catch لتنفيذ تقدير المعاملات
في كود بعض DEX، وجدنا أنه يقوم بتغليف طريقة swap باستخدام try catch. لماذا؟ لأننا بحاجة لمحاكاة طريقة swap لتقدير الرموز المطلوبة للتداول، ولكن أثناء التقدير، لن يتم إجراء تبادل الرموز فعليًا، لذلك سيظهر خطأ. يقوم بإلقاء خطأ خاص في دالة رد الاتصال الخاصة بالتداول، ثم يلتقط هذا الخطأ، ويحلل المعلومات المطلوبة من رسالة الخطأ.
يبدو أن هذا نوع من التحايل، لكنه عملي للغاية. بهذه الطريقة، لا حاجة لتعديل طريقة السواب لتقدير طلبات التداول، كما أن المنطق يصبح أبسط.
استخدام الأعداد الكبيرة لحل مشاكل الدقة
في كود DEX، هناك الكثير من المنطق الحسابي، مثل حساب الرموز المتبادلة بناءً على السعر الحالي والسيولة. خلال هذه العملية، يجب علينا تجنب فقدان الدقة عند إجراء عمليات القسمة. في بعض التنفيذات، يتم استخدام "<< FixedPoint96.RESOLUTION" بشكل متكرر خلال عملية الحساب، وهو ما يمثل الإزاحة لليسار بمقدار 96 بت، مما يعادل الضرب في 2^96. بعد الإزاحة لليسار، يتم إجراء عملية القسمة، مما يضمن عدم تجاوز ( أثناء المعاملات العادية، وعادةً ما يتم حسابها باستخدام uint256، مما يكفي لضمان الدقة في حالة ).
حساب العائد بطريقة Share
في DEX، نحتاج إلى تسجيل عوائد رسوم المعاملات لمزودي السيولة LP(. من الواضح أنه لا يمكن تسجيل رسوم كل LP في كل معاملة، لأن ذلك سيستهلك الكثير من الغاز. فما هو الحل؟
يمكن تعريف هيكل يتضمن feeGrowthInside0LastX128 و feeGrowthInside1LastX128 في Position، حيث تسجل هذه القيم رسوم المعاملات التي ينبغي أن يحصل عليها كل سيولة في آخر مرة تم فيها سحب الرسوم من كل مركز.
ببساطة، يكفي تسجيل إجمالي الرسوم و الرسوم التي يجب تخصيصها لكل سيولة. عند سحب الرسوم، يمكن حساب الرسوم القابلة للسحب بناءً على السيولة المحتفظ بها. هذا مشابه لامتلاك أسهم في شركة، حيث تحتاج فقط إلى معرفة الأرباح التاريخية لكل سهم، بالإضافة إلى الأرباح التي حصلت عليها في آخر سحب.
![Web3 سلسلة المبتدئين: الحيل الصغيرة التي تعلمتها من كود Uniswap لتطوير العقود])https://img-cdn.gateio.im/webp-social/moments-45e66af69435e6d4412ae506e77ab893.webp(
ليس من الضروري الحصول على جميع المعلومات من السلسلة
التخزين على السلسلة مكلف نسبيًا، لذا ليس من الضروري أن تكون جميع المعلومات على السلسلة أو الحصول عليها من السلسلة. على سبيل المثال، العديد من واجهات برمجة التطبيقات التي تستدعيها المواقع الأمامية لبعض DEX هي واجهات برمجة التطبيقات التقليدية Web2.
يمكن تخزين قائمة أحواض التداول ومعلومات أحواض التداول في قاعدة بيانات عادية، وقد يحتاج البعض إلى المزامنة بشكل دوري من السلسلة، ولكن لا يلزم استدعاء واجهة RPC المقدمة من السلسلة أو خدمات العقد للحصول على البيانات ذات الصلة في الوقت الحقيقي.
بالطبع، المعاملات الرئيسية تتم بالتأكيد على السلسلة.
تعلم تقسيم العقود، واستخدام العقود القياسية الموجودة
قد يتضمن المشروع عدة عقود تم نشرها فعليًا. حتى لو تم نشر عقد واحد فقط فعليًا، يمكننا أيضًا تقسيم العقد إلى عدة عقود للحفاظ عليها من خلال طريقة الوراثة.
بالإضافة إلى ذلك، يمكن استخدام عقود معيارية مثل @openzeppelin/contracts/token/ERC721/ERC721.sol مباشرة. بهذه الطريقة، يمكن إدارة المراكز بطريقة NFT من جهة، ومن جهة أخرى، يمكن تحسين كفاءة التطوير باستخدام عقود معيارية موجودة.
ملخص
تجربة عملية لتطوير نسخة بسيطة من بورصة لامركزية، ستساعدك على فهم أعمق لتنفيذ رموز DEX، وستتعلم أيضًا المزيد من النقاط المعرفية في المشاريع العملية. سواء كنت مهتمًا بتطوير مشاريع Web3 أو DeFi، فإن الخبرة العملية ستكون مفيدة لك كثيرًا.
![Web3 سلسلة للمبتدئين: النصائح الصغيرة لتطوير العقود التي تعلمتها من كود Uniswap])https://img-cdn.gateio.im/webp-social/moments-f95ddc9d89809cf11dbe65b9bafda157.webp(