إنتقل إلى المحتوى الرئيسي

المرحلة 3: التوسع إلى شبكات EVM متعددة وتكرار الـ keepers

· 5 دقائق قراءة
OrcaRail
Crypto payment rails for web2 apps

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 لكل شبكة):

  1. Ethereum mainnet (chainId 1)
  2. Arbitrum One (42161)
  3. Optimism (10)
  4. 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 الثاني للتكرار، لا للاستبدال. يعمل إلى جانب مُجدوِل NestJS.

  • تسجيل 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 دقائق من nextChargeAt99.5%
charge() خلال ساعة من nextChargeAt99.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 · مرجع العقود