La arquitectura se centra en un patrón de Orquestación de Saga desacoplado por un backbone Impulsado por Eventos. En la entrada, una API Gateway (Kong o Envoy) valida tokens JWT y enruta las solicitudes a un Punto de Aplicación de Políticas (PEP), que consulta un Punto de Decisión de Políticas (PDP) utilizando Open Policy Agent (OPA) para verificaciones en tiempo real de AML y KYC contra listas de sanciones.
El núcleo es el Coordinador de Transacciones Cruzadas, implementado como una máquina de estados utilizando Temporal o un motor Saga personalizado sobre Apache Kafka. Este coordinador gestiona la transacción distribuida a través de dos dominios distintos: el Adaptador de Libro Mayor Fiat (integrándose con SWIFT, ACH o SEPA a través de mensajería ISO 20022) y el Adaptador Blockchain (soportando cadenas EVM a través de Alchemy o Infura, y Stellar a través de Horizon API).
Para la atomicidad sin 2PC (que no está disponible en blockchains públicas), empleamos el patrón Saga con transacciones compensatorias. El coordinador primero ejecuta la transacción local "débito fiat", luego la transacción local "mintear/transferir stablecoin". Si esta última falla, la primera se compensa mediante una transacción de "crédito fiat". La captación de eventos asegura que todos los cambios de estado se persistan en PostgreSQL y se publiquen en Kafka para la audibilidad.
La gestión de liquidez utiliza un Cache Geográficamente Distribuido (Redis Cluster) con respaldo de WAL a Cassandra para la consistencia entre regiones. Las conexiones gRPC entre microservicios aseguran baja latencia, mientras que Prometheus y Grafana proporcionan observabilidad. Todo el stack se ejecuta en Kubernetes con Istio para capacidades de malla de servicios, asegurando mTLS entre componentes.
En CrossBridge Payments, nos enfrentamos a un requisito crítico para habilitar remesas instantáneas de un cliente de EE. UU. utilizando ACH a un destinatario alemán que recibe créditos SEPA, enrutados a través de un puente de stablecoin USDC en Ethereum y Stellar para reducir los retrasos en la banca corresponsal. El desafío principal era garantizar la atomicidad: si la transacción blockchain fallaba después del débito ACH, el cliente perdería fondos, sin embargo, la finalización de la blockchain tarda 12 segundos en Ethereum mientras que la liquidación ACH es T+1, pero los débitos son inmediatos.
Evaluamos tres enfoques arquitectónicos. La primera opción involucraba un Oráculo Centralizado que mantenía custodia tanto de fiat como de cripto, actuando como un intermediario confiable. Si bien esto simplificaba la coordinación y reducía la latencia a milisegundos, introducía un riesgo inaceptable de contraparte y no cumplía con los requisitos regulatorios para la custodia descentralizada en ciertas jurisdicciones.
La segunda opción proponía Contratos de Tiempo Bloqueado por Hash (HTLC) para intercambios atómicos sin confianza entre el banco fiat y la blockchain. Sin embargo, esto resultó inviable porque los sistemas de pago bancarios tradicionales carecen de primitivas criptográficas para verificar hashes en la cadena, y los mecanismos de tiempo de espera creaban una mala experiencia del usuario que requería participación activa del cliente.
Finalmente, seleccionamos Orquestación de Saga con Captación de Eventos utilizando Apache Kafka y Temporal. Este enfoque trató el débito fiat y la acuñación de cripto como transacciones locales separadas dentro de una Saga. El orquestador primero bloqueó fondos en una cuenta de depósito maestro a través del adaptador ACH, luego inició la transferencia de USDC en Stellar (elegido por su finalización de 5 segundos). Si el paso cripto fallaba, el orquestador activaba una transacción compensatoria para revertir el bloqueo de ACH.
El resultado fue una tasa de éxito del 99.95% con un tiempo promedio de confirmación en la interfaz de usuario de 800 ms, auditorías regulatorias completas almacenadas en PostgreSQL y cero pérdidas de fondos de clientes debido a fallas de atomicidad durante el piloto de seis meses.
¿Cómo reconcilia la naturaleza sincrónica de las expectativas del cliente de la API REST con la finalización asíncrona y probabilística de las redes blockchain públicas sin mantener las conexiones HTTP abiertas durante minutos?
Muchos candidatos sugieren la sondeo prolongado o solicitudes HTTP en bloque hasta la confirmación de la blockchain, lo que agota los hilos del servidor y provoca tiempos de espera en la puerta de enlace. El enfoque correcto implica el patrón CQRS combinado con Captación de Eventos. La solicitud inicial de liquidación devuelve inmediatamente un estado de 202 Aceptado y un ID de correlación de transacción único. El cliente se suscribe a un WebSocket o un endpoint de Eventos Enviados por el Servidor (SSE), o sondea un endpoint de estado ligero respaldado por Redis. El backend procesa la confirmación de la blockchain de forma asíncrona a través de consumidores de Kafka. Una vez que la Saga alcanza un estado terminal (completado o compensado), el estado se envía al cliente.
¿Qué estrategia asegura la ejecución exactamente una vez de los débitos fiat cuando la API bancaria descendente (JPMorgan Access o Stripe Treasury) devuelve un tiempo de espera, dejando ambigüedad sobre si los fondos se movieron realmente?
Los candidatos a menudo asumen incorrectamente que los reintentos son seguros o que las claves de idempotencia por sí solas son suficientes. La solución robusta implementa un Registro de Idempotencia utilizando PostgreSQL con una máquina de estados PENDIENTE. Antes de llamar a la API externa, el servicio escribe un registro de intención con una clave determinista (SHA-256 del ID de transacción + cubículo de tiempo). Si la API se agota, un trabajador de Saga en segundo plano consulta el endpoint de consulta de idempotencia del banco (o utiliza reconciliación de Webhook). Solo tras confirmación o negación explícita, el estado cambia a ÉXITO o FALLIDO.
¿Cómo evita la fragmentación de liquidez y el gasto doble en el pool de liquidez compartido cuando bots de arbitraje de alta frecuencia acceden simultáneamente a las mismas reservas de USDC a través de la API REST y eventos de depósito de blockchain entrantes?
Esto requiere Bloqueo Optimista a nivel de base de datos y Bloqueo Distribuido para secciones críticas. El servicio de liquidez mantiene filas versionadas en PostgreSQL; cualquier actualización incrementa la versión. Cuando se intenta un retiro, el sistema verifica la versión. Si un evento de blockchain concurrente ha modificado la fila (desajuste de versión), la transacción se reintenta. Para el camino caliente, se adquiere un Redlock de Redis antes de verificar saldos, asegurando acceso secuencial. Además, un Disyuntor (Resilience4j) monitorea el ratio de contención del pool de liquidez.