تخطَّ إلى المحتوى

مقالات

قائمة التحقق من الجاهزية لتدقيق العقود الذكية

30 فحصاً قبل تدقيق العقود الذكية: النطاق والوثائق، والاختبارات، واختبارات Fuzz والثوابت في Foundry، وتصنيف نتائج Slither، والتحكم في الوصول، والتكاملات، والنشر.

فريق هندسة sigmacode.io8 دقائق قراءة

في هذه الصفحة (9)
  1. 1. النطاق والتوثيق
  2. 2. نظافة الكود والتحليل الساكن
  3. 3. الاختبارات
  4. 4. اختبارات Fuzz والثوابت
  5. 5. التحكم في الوصول وقابلية الترقية
  6. 6. التكاملات الخارجية
  7. 7. النشر والعمليات
  8. 8. لوجستيات التدقيق
  9. كيف يمكننا المساعدة

تدقيق العقود الذكية مكلف ومحدد زمنياً بدقة. يحصل المدققون على عدد ثابت من الأيام، وكل ساعة يقضونها في فهم ما يُفترض بالكود فعله، أو ملاحقة commit متحرك، أو كتابة الاختبارات التي لم تكتبها أنت، هي ساعة لا تُنفَق على المنطق الذي قد يفقد الأموال فعلاً. ثم يمتلئ تقرير النتائج بـNatSpec الناقص والـpragma العائمة ومسارات revert غير المختبرة بدلاً من المشكلات التي تدفع لاكتشافها.

تحصل قاعدة الكود المُعدّة جيداً على تدقيق أعمق بالميزانية نفسها. تجمع قائمة التحقق هذه ما نضعه قبل تسليم الكود إلى مدقق خارجي: 30 فحصاً ملموساً تغطي التوثيق ونظافة الكود والاختبار والتحكم في الوصول والتكاملات والنشر واللوجستيات. وهي لا تحل محل التدقيق؛ بل تضمن أن يذهب وقت التدقيق إلى حيث يهمّ.

1. النطاق والتوثيق#

لا يستطيع المدققون التحقق من السلوك إلا مقابل قصد يفهمونه، لذا يجب أن يُكتَب القصد.

  • جمّد بصمة commit. أعطِ المدققين commit موسوماً واحداً ولا تغيّر الكود قيد المراجعة أثناء فترة العمل. تذهب الإصلاحات إلى فرع منفصل وتُراجَع في جولة مراجعة الإصلاحات.
  • انشر قائمة ملفات النطاق مع nSLOC. عدّد كل عقد في النطاق بمساره وعدد أسطر الكود المصدري المطبَّعة، واذكر صراحةً ما هو خارج النطاق (المكتبات، والمحاكاة، والسكربتات، والملفات المدققة سابقاً). يقدّم المدققون عروض الأسعار ويخططون على أساس nSLOC، فالعد الدقيق يجنّب المفاجآت على الطرفين.
  • اكتب نظرة عامة على المعمارية. صفحة أو اثنتان تصفان العقود وكيف تستدعي بعضها البعض وأيها يحتفظ بالأموال وتدفقات المستخدم الرئيسية. رسم بسيط للاستدعاءات وتدفقات التوكنات يوفّر على المدققين ساعات من الهندسة العكسية.
  • حدّد السلوك والثوابت نثراً. صِف ما يجب أن تفعله كل دالة خارجية والخصائص التي يجب أن تصحّ دائماً، مثل «مجموع أرصدة المستخدمين يساوي totalAssets» أو «القفل الزمني وحده يمكنه تغيير الرسوم». تصبح هذه العبارات أساساً لمراجعة المدققين ولاختبارات الثوابت لديك معاً.
  • وثّق المشكلات المعروفة والمخاطر المقبولة. عدّد القيود التي تعرفها مسبقاً والقرارات التصميمية التي تقبلها، مثل مفاضلات المركزية أو أنواع التوكنات غير المدعومة. فهذا يُبقيها خارج تقرير النتائج ويري المدققين أين فكّرت مسبقاً.

2. نظافة الكود والتحليل الساكن#

الضجيج في قاعدة الكود يكلّف وقتاً من التدقيق وينتج نتائج قليلة القيمة، فأزله قبل أن يراه المدققون.

  • ثبّت المترجم وصِل إلى صفر تحذيرات. استخدم pragma solidity 0.8.x; دقيقاً بدلاً من ^0.8.0 عائم، واجعل الإصدار ودورات المُحسِّن وvia_ir وevm_version في foundry.toml تطابق ما ستنشره. كل تحذير مترجم يجب إصلاحه أو تبريره بوعي.
  • ثبّت التبعيات وعدّدها. اقفل OpenZeppelin Contracts وكل مكتبة أخرى على إصدار دقيق، مثل وحدة فرعية موسومة v5.x أو إصدار دقيق في package.json. عدّد كل التبعيات في وثائق التدقيق وعلّم أي ملفات نسختها أو عدّلتها.
  • أزل الكود الميت وTODO ومخرجات التصحيح. احذف الدوال غير المستخدمة والكود المعلَّق واستيرادات console.log ومساعدات الاختبار المتروكة من العقود ضمن النطاق. تُشير TODO المفتوحة إلى منطق غير مكتمل وستُبلَّغ كذلك.
  • أكمل NatSpec على الدوال الخارجية والعامة. كل دالة خارجية وعامة يجب أن تحمل @notice و@param و@return، وحيثما يلزم ملاحظة عن التحكم في الوصول وحالات revert. استخدم أخطاء مخصصة وأصدر أحداثاً لكل تغيير حالة يهمّ خارج السلسلة.
  • شغّل Slither وصنّف كل نتيجة. شغّل slither على الـcommit المجمَّد وصنّف كل نتيجة كمُصلَحة أو إيجاب كاذب أو مقبولة، مع تبرير من سطر واحد. أداة ثانية مثل Aderyn تلتقط غالباً أنماطاً مختلفة، ومشاركة المخرجات المصنَّفة تخبر المدققين أي النتائج الآلية تمت معالجتها مسبقاً.

3. الاختبارات#

تُري الاختبارات المدققين كيف يُفترض استخدام الكود وتتيح لهم كتابة إثباتات مفهوم بسرعة.

  • غطِّ كل دالة خارجية وانشر التقرير. كل دالة خارجية وعامة تحتاج اختباراً واحداً على الأقل للمسار السعيد. ولّد تقرير تغطية أسطر وفروع بـforge coverage واشرح أي فروع غير مغطاة بدلاً من إخفائها.
  • اختبر مسارات revert والحالات الحدّية. تحقق عبر vm.expectRevert من أن الاستدعاءات غير المصرَّح بها والمعاملات غير الصالحة والكميات الصفرية والقيم الحدّية تُرجِع الخطأ المخصص المتوقع. مسارات revert غير المختبرة هي حيث تختبئ أخطاء التحقق والتحكم في الوصول.
  • شغّل اختبارات fork على التكاملات الحقيقية. إذا كان البروتوكول يتحدث إلى عقود خارجية مثل DEX أو أسواق إقراض أو أوراكل، فاختبر على نسخة متفرعة من الشبكة الرئيسية أو L2 بأرقام كتل مثبتة. المحاكاة تثبت فقط أن كودك يعمل مع افتراضاتك عن الطرف الآخر.

4. اختبارات Fuzz والثوابت#

يجد الـfuzzing تركيبات المدخلات التي لم يفكر فيها أحد، وتتحقق اختبارات الثوابت من بقاء النظام متسقاً عبر تسلسلات الاستدعاءات.

  • طبّق fuzz على كل دالة تقبل مدخلاً رقمياً. اكتب اختبارات fuzz في Foundry للكميات والطوابع الزمنية وحسابات الحصص ورياضيات الرسوم، وقيّد المدخلات بـbound() بدلاً من الإفراط في vm.assume. اتجاه التقريب والتجاوز عند القيم القصوى هما الهدفان النموذجيان.
  • اكتب اختبارات ثوابت ذات حالة بمعالِجات. استخدم اختبار الثوابت في Foundry مع عقود معالِجة (handlers) تستدعي النظام بتسلسلات واقعية من عدة جهات فاعلة. تحقق من الملاءة وحفظ القيمة وخصائص التحكم في الوصول بعد كل تسلسل استدعاء.
  • أبقِ الثوابت المكتوبة ومجموعة الاختبارات متزامنة. كل ثابت في مواصفتك يجب أن يقابل اختبار ثابت، وكل اختبار ثابت يجب أن يُرجَع إلى المواصفة. شغّل المجموعة بعدد ذي معنى من الدورات والعمق في CI، لا محلياً بالإعدادات الافتراضية فقط.

5. التحكم في الوصول وقابلية الترقية#

يمكن للدوال ذات الصلاحيات والترقيات أن تنقل أو تقفل كل أصل في النظام، لذا يجب أن يكون نموذج الثقة صريحاً.

  • عدّد كل دور ودالة ذات صلاحيات. وثّق كل دور، وأي الدوال يمكنه استدعاؤها، ومن يحمله، وما أسوأ سيناريو إذا اختُرق مفتاحه. هذا هو قسم افتراضات الثقة الذي سيطلبه المدققون أولاً.
  • ضع قوة الإدارة خلف multisig وقفل زمني. يجب أن تُدار المعاملات الحرجة والترقيات بمحفظة متعددة التوقيع مثل Safe، مع TimelockController أو تأخير مكافئ للتغييرات التي تمسّ أموال المستخدمين. وثّق عتبة الموقِّعين والتأخير.
  • افحص تخطيط التخزين للعقود القابلة للترقية. بالنسبة للوكلاء (proxies)، استخدم عقود OpenZeppelin v5 القابلة للترقية مع تخزين بمساحات أسماء ERC-7201 وتحقق من الترقيات بأدوات OpenZeppelin upgrades. ضمّن فرق تخطيط التخزين بين الإصدارات إذا كانت الترقية ضمن النطاق.
  • احمِ دوال التهيئة والترقية. استدعِ _disableInitializers() في مُنشئ التنفيذ، واستخدم معدِّلات initializer وreinitializer بشكل صحيح، وقيّد _authorizeUpgrade لوكلاء UUPS (ERC-1822). عقد تنفيذ غير محمي هو نتيجة لا يجب أن يضطر المدققون للإبلاغ عنها أبداً.

6. التكاملات الخارجية#

كل استدعاء خارجي هو افتراض عن كود شخص آخر، وكل افتراض يجب أن يُكتَب ويُختبَر.

  • عالج قِدَم الأوراكل وفشله. تحقق من updatedAt مقابل إيقاع الخلاصة (heartbeat)، وارفض الأسعار الصفرية أو السالبة، وعلى شبكات L2 تحقق من خلاصة جاهزية المُسلسِل (sequencer). قرّر ما يفعله البروتوكول عندما يتعذّر الوصول إلى الأوراكل ووثّقه.
  • احتسب غرائب التوكنات. حدّد أنواع التوكنات المدعومة وعالج أو استبعد صراحةً توكنات fee-on-transfer وrebasing وغير ذات 18 خانة عشرية وERC-20 غير القياسية. استخدم SafeERC20 للتحويلات وقِس فروق الأرصدة حيث يهمّ المبلغ المستلَم.
  • ارسم خريطة أسطح إعادة الدخول. عدّد كل استدعاء خارجي وتحويل توكنات، واتبع checks-effects-interactions، واستخدم ReentrancyGuard (أو ReentrancyGuardTransient مع EIP-1153) حيث تُشارَك الحالة. فكّر في إعادة الدخول عبر الدوال وإعادة الدخول للقراءة فقط، وردود الاستدعاء من توكنات ERC-721 وERC-1155 وERC-777.
  • فكّر في MEV والسباق الأمامي (front-running). أضف حدود انزلاق ومواعيد نهائية للمقايضات والإيداعات، واحمِ خزائن ERC-4626 من هجوم تضخيم المُودِع الأول، وراجع أي منطق يعتمد على ترتيب المعاملات. وثّق مخاطر الترتيب التي تقبلها.

7. النشر والعمليات#

الكود المدقَّق لا يكون آمناً إلا بقدر أمان طريقة نشره وتشغيله.

  • اجعل سكربتات النشر قابلة للتكرار ومعاملاتها موثقة. انشر بسكربتات Foundry من الـcommit المجمَّد، واحتفظ بكل معاملات المُنشئ والتهيئة في إعدادات خاضعة للتحكم في الإصدارات، وضمّن السكربتات في نطاق التدقيق أو على الأقل في التسليم. عقد صحيح منشور بمعاملات خاطئة لا يزال مكسوراً.
  • تدرّب على شبكة اختبار بمصادر محققة. شغّل سكربت النشر نفسه على شبكة اختبار وعلى نسخة متفرعة من الشبكة الرئيسية، وتحقق من المصادر على مستكشف الكتل، وتأكد أن الأدوار انتهت إلى العناوين المقصودة. أعطِ المدققين عناوين شبكة الاختبار حتى يتفاعلوا مع نشر حقيقي.
  • جهّز الإيقاف المؤقت ودليل التشغيل والمراقبة. قرّر من يمكنه إيقاف ماذا، واكتب دليل حوادث موجزاً، وأعدّ تنبيهات لتغييرات الأدوار والترقيات والسحوبات الكبيرة وحالات الإيقاف. سيراجع المدققون مسارات الطوارئ، فيجب أن تكون موجودة قبل التدقيق.

8. لوجستيات التدقيق#

اللوجستيات الجيدة تُبقي التدقيق متحركاً وتضمن استخدام جولة الإصلاح فعلاً.

  • سمِّ نقطة اتصال تقنية وقناة. عيّن مطوراً واحداً يعرف قاعدة الكود ويستطيع الإجابة عن الأسئلة خلال ساعات، واتفق على قناة مشتركة طوال مدة التدقيق. كل سؤال بلا إجابة يوقف المراجعة.
  • احجز وقتاً للإصلاحات وجولة مراجعة إصلاحات. خطّط لطاقة المطورين فور وصول التقرير واتفق مسبقاً على أن يراجع المدققون الإصلاحات. الإصلاحات غير المراجعة قد تُدخِل أخطاءً جديدة بعد توقيع التدقيق.
  • افصح عن التدقيقات والمراجعات السابقة. شارك تقارير التدقيق السابقة وحالة إصلاحاتها وأي مراجعات داخلية. يستطيع المدققون حينها التركيز على ما تغيّر والتحقق من عدم انتكاس النتائج السابقة.

كيف يمكننا المساعدة#

نقدّم برنامج Audit-Readiness Sprint محدد النطاق من أسبوع إلى أسبوعين: نموذج تهديدات، وتحليل فجوات مجموعة الاختبارات، واختبارات fuzz وثوابت في Foundry، وتصنيف Slither، وقائمة إصلاحات مرتبة بالأولوية، وحزمة تسليم للتدقيق تتضمن النطاق والتوثيق والمشكلات المعروفة. نحن لسنا شركة تدقيق والبرنامج لا يحل محل تدقيق خارجي؛ بل يُعدّ كودك حتى يقضي المدققون وقتهم على المنطق. التفاصيل على صفحة الأسعار وفي خدمات البلوكتشين والويب 3.

إذا كنت ترغب في تقدير مجاني لقاعدة كودك، أخبرنا عن مشروعك. ويسعدنا توقيع اتفاقية عدم إفصاح متبادلة قبل مشاركة أي كود.

لديك مشروع في ذهنك؟

أخبرنا بما تبنيه. يرد مهندس senior خلال ساعة في أيام العمل — ثم تحصل على تقييم صادق ونطاق واضح وعرض بسعر ثابت أو مرحلي، عادة خلال أيام عمل قليلة.

تفضّل الكتابة أولًا؟ راسلنا

ستتحدث مباشرة مع Ing. Ismet Mesic، Tech lead.