المرحلة 3: التوسع إلى شبكات EVM متعددة وتكرار الـ keepers
20 أبريل 2026 — تأخذ المرحلة 3 واجهة العقود من المرحلة 1 والمرحلة 2 وتنشرها على كل شبكة EVM ندعمها. كما تضيف keeper ثانيًا، حتى لا يتسبب انقطاع NestJS في تفويت خصم اشتراك.
باختصار
- نشر
PaymentLinkFactoryوتطبيقPaymentLinkReceiverوFeeSplitterوSubscriptionHubعلى Ethereum mainnet وArbitrum وOptimism وPolygon. - مخطط salt نفسه لـ CREATE2 في كل مكان؛ عنوان المصنع واحد على كل الشبكات (أنظف للتوثيق وللتكاملات ولـ
computeAddressمن جهة العميل). - تسجيل Chainlink Automation (المفضّل) و/أو Gelato Web3 Functions كـ keeper ثانٍ يستدعي
charge(ids[])نفسها. - نشر أهداف SLO: 99.5% من الخصومات خلال 10 دقائق من موعد الاستحقاق، بقياس فعلي.
ما الذي تغيّره هذه المرحلة
تعدد الـ keepers التي تستدعي charge() العامة نفسها هو ضمان الاستمرارية. لا يملك أيٌّ منها حفظًا للأموال؛ ويمكن لأيٍّ منها إنقاذ خصم مستحق.
خطة النشر
ترتيب النشر (شبكة واحدة أسبوعيًا، مع canary لكل شبكة):
- Ethereum mainnet (chainId
1) - Arbitrum One (
42161) - Optimism (
10) - Polygon PoS (
137)
تُنشر العناوين على كل شبكة في /docs/non-custodial/contract-reference. مفتاح النشر هو التوقيع المتعدد Safe ثلاثة من خمسة نفسه المحدد في المرحلة 0، ويُعاد نشره لكل شبكة من المراسم نفسها.
تشترك الشبكات الأربع في العلم نفسه useOnChainReceiver المحدد حسب chainId داخل api/src/payments/wallet.service.ts. يفعّله التجار شبكةً بعد شبكة؛ وتصبح القيمة الافتراضية مفعّلة بعد أسبوع canary نظيف.
استراتيجية الغاز لـ charge()
تحتاج معاملات charge() الخاصة بالـ keeper إلى غاز. نعيد استخدام بنية الـ paymaster الحالية في api/src/withdrawals/services/gas-strategy:
- مع paymaster من Alchemy (Base وArbitrum وOptimism وPolygon): يستدعي الـ keeper الدالة
SubscriptionHub.charge()كـ UserOperation برعاية السياسة. تكلفة غاز صفرية لحساب EOA الخاص بالـ keeper. - Ethereum mainnet (دون paymaster): يدفع الـ keeper من رصيد الغاز الساخن الخاص به. تموّله محفظة المنصة يوميًا، ويُراقب بتنبيه Datadog عند انخفاض الرصيد.
- غاز مدعوم من التاجر (اختياري): يمكن للتجار تعيين
gas_refund_addressويسحب الـ keeper التعويض منه، بما يطابق نمط الدعم/العمولة الحالي. خارج نطاق الإطلاق الأولي.
الـ keeper الثاني: Chainlink وGelato
الـ keeper الثاني للتكرار، لا للاستبدال. يعمل إلى جانب مُجدوِل NestJS.
Chainlink Automation (المفضّل على EVM)
- تسجيل Upkeep لكل
SubscriptionHub. - تعيد
checkUpkeep()القيمةperformData = abi.encode(ids[])لكلidيحققblock.timestamp >= nextChargeAt(مقروءة من دالة عرض). - تستدعي
performUpkeep(performData)الدالةcharge(ids)دفعة واحدة. - يُموَّل بـ LINK من خزينة المنصة؛ ويُراقب الرصيد.
Gelato Web3 Functions (بديل)
- تستطلع Web3 Function مكتوبة بـ JS المركز، وتجد المعرّفات المستحقة، وترسل معاملة
charge(ids[]). - يُدفع السعر لاحقًا من
1Balanceفي Gelato.
أيٌّ منهما كافٍ وحده؛ وسنختار بناءً على الخبرة التشغيلية خلال المرحلة 3. تشغيل الاثنين معًا لا بأس به؛ فـ charge() idempotent داخل الفترة بفضل lastChargedAt.
أهداف SLO والمراقبة
أهداف SLO المنشورة:
| المقياس | الهدف |
|---|---|
charge() خلال 10 دقائق من nextChargeAt | 99.5% |
charge() خلال ساعة من nextChargeAt | 99.9% |
| رصيد الغاز الساخن لحساب الـ keeper أعلى من عتبة التنبيه | 99.99% |
| فهرسة الأحداث خلال دقيقتين من نهائية الكتلة | 99.5% |
تتصل المراقبة بإعداد Sentry الحالي الموثق في مهارة سير عمل Sentry في المستودع. التنبيهات:
- عدد revert لـ
charge()في الساعة > العتبة ← PagerDuty - الرصيد الأصلي لحساب الـ keeper أقل من N gwei × gasLimit × 100 ← PagerDuty
- upkeep في Chainlink/Gelato غير سليم ← تحذير
- تأخر مفهرس أحداث
Paidأكثر من 5 دقائق ← تحذير
الإيقافات
كما في المرحلتين 1 و2، لكن على شبكات أكثر. لا يُحذف شيء بعد؛ فالحذف ينتظر المرحلة 7.
خطة الترحيل
- روابط الدفع الجديدة: تستخدم المستقبِلات القائمة على العقود على أي شبكة مفعّل لها العلم.
- الاشتراكات الجديدة: تستخدم
SubscriptionHubعلى أي شبكة مفعّل لها العلم. - العملاء الحاليون: ترحيل اختياري عند التجديد، كما في المرحلة 2.
- التسوية عبر الشبكات (Relay): الواجهة دون تغيير؛ يواصل الـ keeper استدعاء منفّذي Relay في api/src/withdrawals/services/bridge، لكن من EOA لا يملك أي حفظ.
المخاطر ووسائل الحد منها
- اختلاف العناوين بين الشبكات. الحل: ناشر CREATE2 حتمي (مثل
0x4e59b44847b379578588920cA78FbF26c0B4956C) مع تجزئة init-code مقفلة؛ تتشارك المصانع العنوان نفسه على الشبكات الأربع. - حدود سياسة الـ paymaster لكل شبكة. الحل: مراقبة لكل شبكة وتنبيهات حصة السياسة عند 70% من الاستخدام.
- كثرة تغييرات تسجيل upkeep في Chainlink. الحل: upkeep واحد لكل شبكة؛ تُقرأ قائمة المعرّفات على السلسلة، فلا يتطلب تسجيل التجار تغيير إعدادات Chainlink.
- خصم مزدوج بين الـ keepers. الحل:
lastChargedAtرتيب إضافةً إلىChargeSkippedللتكرارات؛ وكلا الـ keepers idempotent بالتصميم. - ارتفاعات مفاجئة في غاز الشبكة الرئيسية. الحل: ضبط حجم الدفعة لكل شبكة؛ وسقف لسعر الغاز يؤجَّل فوقه
charge()كتلة واحدة.
قائمة الحالة
- إتمام النشر على Ethereum وArbitrum وOptimism وPolygon
- نشر عناوين المصنع + المركز في مرجع العقود
- التحقق من سياسات الـ paymaster لكل شبكة
- تفعيل upkeep من Chainlink Automation على شبكتين على الأقل
- لوحة SLO في Datadog
- دليل تشغيل لانقطاع الـ keeper (
charge()يدوي من CLI التاجر) - إطلاق تجار canary لكل شبكة
ما التالي
سولانا هي الشبكة الكبيرة الأخرى التي يجب أن نجعلها غير احتجازية: المرحلة 4.
التوثيق المرجعي: حالة المرحلة 3 · استراتيجية الـ keepers · مرجع العقود
