Fase 3: despliegue en varias cadenas EVM y redundancia de keepers
20 de abril de 2026: la Fase 3 toma la superficie de contratos de la Fase 1 y la Fase 2 y la lleva a todas las cadenas EVM que admitimos. Además añade un segundo keeper, para que una caída de NestJS no pueda saltarse un cobro de suscripción.
En resumen
- Desplegar
PaymentLinkFactory, la implementación dePaymentLinkReceiver,FeeSplitterySubscriptionHuben Ethereum mainnet, Arbitrum, Optimism y Polygon. - El mismo esquema de salt de CREATE2 en todas partes: la dirección de la factoría es la misma en todas las cadenas (limpio para la documentación, para las integraciones y para
computeAddressdesde el cliente). - Registrar Chainlink Automation (preferido) y/o Gelato Web3 Functions como segundo keeper que llama al mismo
charge(ids[]). - Publicar SLO: 99,5 % de los cobros en los 10 minutos siguientes al vencimiento, medido.
Qué cambia en esta fase
Varios keepers llamando al mismo charge() público es la garantía de disponibilidad. Ninguno tiene custodia; cualquiera de ellos puede salvar un cobro vencido.
Plan de despliegue
Orden de despliegue (una cadena por semana, con canario por cadena):
- Ethereum mainnet (chainId
1) - Arbitrum One (
42161) - Optimism (
10) - Polygon PoS (
137)
Las direcciones de cada cadena se publican en /docs/non-custodial/contract-reference. La clave de despliegue es la misma multisig Safe 3 de 5 definida en la Fase 0, redesplegada en cada cadena desde la misma ceremonia.
Las cuatro cadenas comparten el mismo feature flag useOnChainReceiver, definido por chainId dentro de api/src/payments/wallet.service.ts. Los comercios lo activan cadena por cadena; el valor por defecto pasa a activado cuando la semana canaria sale limpia.
Estrategia de gas para charge()
Las transacciones charge() del keeper necesitan gas. Reutilizamos la infraestructura de paymaster existente en api/src/withdrawals/services/gas-strategy:
- Con paymaster de Alchemy (Base, Arbitrum, Optimism, Polygon): el keeper llama a
SubscriptionHub.charge()como UserOperation con patrocinio de la política. Coste de gas cero para la EOA del keeper. - Ethereum mainnet (sin paymaster): el keeper paga con su saldo de gas en caliente. Lo recarga a diario la wallet de la plataforma y se monitoriza con una alerta de Datadog por saldo bajo.
- Gas subvencionado por el comercio (opcional): los comercios pueden definir una
gas_refund_addressy el keeper cobra el reembolso de ahí, siguiendo el patrón actual de soporte/comisión. Fuera del alcance del despliegue inicial.
Segundo keeper: Chainlink y Gelato
El segundo keeper es una apuesta por la redundancia, no un sustituto. Funciona junto al programador de NestJS.
Chainlink Automation (preferido en EVM)
- Registrar un Upkeep por cada
SubscriptionHub. checkUpkeep()devuelveperformData = abi.encode(ids[])para todos losidconblock.timestamp >= nextChargeAt(leídos de una función view).performUpkeep(performData)llama acharge(ids)en lote.- Financiado con LINK desde la tesorería de la plataforma; saldo monitorizado.
Gelato Web3 Functions (alternativa)
- Una Web3 Function en JS consulta el hub, encuentra los ID vencidos y envía una transacción
charge(ids[]). - El precio se paga a posteriori desde
1Balancede Gelato.
Cualquiera de los dos basta por sí solo; elegiremos según la experiencia operativa durante la Fase 3. Ejecutar ambos no es problema: charge() es idempotente dentro de un periodo gracias a lastChargedAt.
SLO y monitorización
Objetivos de SLO publicados:
| Métrica | Objetivo |
|---|---|
charge() en los 10 minutos siguientes a nextChargeAt | 99,5 % |
charge() en la hora siguiente a nextChargeAt | 99,9 % |
| Saldo de gas en caliente de la EOA del keeper sobre el umbral de alerta | 99,99 % |
| Eventos indexados en los 2 minutos siguientes a la finalidad del bloque | 99,5 % |
La monitorización se conecta a la configuración de Sentry existente documentada en la skill de flujo de trabajo de Sentry del repositorio. Alertas:
- Reverts de
charge()por hora > umbral → PagerDuty - Saldo nativo de la EOA del keeper por debajo de N gwei × gasLimit × 100 → PagerDuty
- Upkeep de Chainlink/Gelato en mal estado → aviso
- Retraso del indexador de eventos
Paid> 5 min → aviso
Obsolescencias
Igual que en las Fases 1 y 2, pero en más cadenas. Todavía no se elimina nada; la eliminación espera a la Fase 7.
Plan de migración
- Enlaces de pago nuevos: usan receptores en contrato en cualquier cadena con el flag activado.
- Suscripciones nuevas: usan
SubscriptionHuben cualquier cadena con el flag activado. - Clientes existentes: migración voluntaria en la renovación, igual que en la Fase 2.
- Liquidación entre cadenas (Relay): superficie sin cambios; el keeper sigue llamando a los ejecutores de Relay en api/src/withdrawals/services/bridge, solo que desde una EOA sin custodia.
Riesgos y mitigaciones
- Direcciones distintas entre cadenas. Mitigación: desplegador CREATE2 determinista (por ejemplo,
0x4e59b44847b379578588920cA78FbF26c0B4956C) con un hash de init-code fijo; las factorías comparten dirección en las cuatro cadenas. - Límites de la política de paymaster por cadena. Mitigación: monitorización por cadena y alertas de cuota de la política al 70 % de uso.
- Cambios frecuentes en el registro de upkeeps de Chainlink. Mitigación: un upkeep por cadena; la lista de ID se lee on-chain, así que dar de alta comercios no requiere cambios en la configuración de Chainlink.
- Cobro doble entre keepers. Mitigación:
lastChargedAtmonótono másChargeSkippedpara duplicados; ambos keepers son idempotentes por diseño. - Picos de gas en mainnet. Mitigación: ajuste del tamaño de lote por cadena; un techo de precio de gas por encima del cual
charge()se aplaza un bloque.
Lista de estado
- Despliegues completados en Ethereum, Arbitrum, Optimism y Polygon
- Direcciones de factoría + hub publicadas en la referencia de contratos
- Políticas de paymaster validadas por cadena
- Upkeep de Chainlink Automation activo en al menos 2 cadenas
- Panel de SLO en Datadog
- Runbook para caídas del keeper (
charge()manual desde la CLI del comercio) - Comercios canarios desplegados por cadena
Qué sigue
Solana es la otra gran cadena que debemos hacer no custodial: Fase 4.
Documentación de referencia: Estado de la Fase 3 · Estrategia de keepers · Referencia de contratos
