Ir al contenido

Capa Anti-Corrupción (ACL) y Cero Pérdida de Precisión

🛡️ Capa Anti-Corrupción (ACL) y Cero Pérdida de Precisión

Sección titulada «🛡️ Capa Anti-Corrupción (ACL) y Cero Pérdida de Precisión»

En la arquitectura de software empresarial, una Capa Anti-Corrupción (ACL) actúa como un perímetro defensivo entre los proveedores externos (APIs, extractos CSV de terceros, datos no confiables de red) y el Modelo de Dominio puro interno.

En aplicaciones financieras, esta barrera asume una segunda función crítica: garantizar la precisión matemática absoluta y erradicar las aberraciones de redondeo por coma flotante.


🚫 El Peligro del Estándar IEEE-754 en Criptomonedas

Sección titulada «🚫 El Peligro del Estándar IEEE-754 en Criptomonedas»

Los números convencionales en JavaScript son flotantes binarios de 64 bits bajo la especificación IEEE-754. En el ámbito financiero, esto origina anomalías de redondeo severas:

// Error clásico de coma flotante en JavaScript
0.1 + 0.2 === 0.30000000000000004 // true
// En micro-transacciones criptográficas:
const satoshis = 0.00000001 * 3;
console.log(satoshis); // 0.000000030000000000000004

Al procesar miles de lotes fiscales FIFO a lo largo de múltiples ejercicios económicos, el error acumulado:

  1. Impide cuadrar las transacciones (amount_in - amount_out !== 0).
  2. Genera balances residuales fantasma (0.000000000000001 BTC en lotes teóricamente liquidados).
  3. Incumple los criterios de cuadratura exigidos por agencias tributarias como la AEAT.

Para asegurar precisión exacta sin introducir dependencias de librerías externas en el dominio, Criptofolio utiliza Branded Types:

packages/core-domain/src/domain/models/PreciseAmount.ts
export type PreciseAmount = string & { readonly __brand: 'PreciseAmount' };
export const toPreciseAmount = (val: string | number): PreciseAmount => {
if (typeof val === 'number' && !Number.isFinite(val)) {
throw new Error('No es posible construir PreciseAmount a partir de un valor no finito');
}
return String(val) as PreciseAmount;
};
  1. Los Puertos del Dominio solo operan con PreciseAmount: Interfaces como ILedgerPort e ITaxPort nunca aceptan tipos number ni instancias de librerías externas.
  2. Aritmética Encapsulada: Las operaciones matemáticas de precisión arbitraria quedan limitadas a Casos de Uso y adaptadores usando decimal.js o tipos columnares DECIMAL(38,18) en DuckDB.

🔍 La Capa Anti-Corrupción (Validación con Zod)

Sección titulada «🔍 La Capa Anti-Corrupción (Validación con Zod)»

Antes de que cualquier dato externo alcance el dominio, debe atravesar los schemas de Zod en la capa de Infraestructura:

flowchart TD
    External["Entrada Externa / API o CSV"] -->|JSON o Cadenas Crudas| Adapter["Adaptador de Infraestructura"]
    Adapter -->|safeParse| Schema{"Esquema Zod ACL\n(preciseAmountSchema)"}
    Schema -->|Válido| Domain["Mapeo a Entidad de Dominio\n(PreciseAmount)"]
    Domain -->|Seguro| Store["Pinia Colada / Casos de Uso"]
    Schema -->|Inválido| ErrorBus["Bus Global de Errores\n(Alerta Controlada, Sin Caída)"]
import { z } from 'zod';
// Regex estricto: formato numérico con signo opcional y parte decimal
export const preciseAmountSchema = z
.string()
.trim()
.regex(/^-?\d+(\.\d+)?$/, 'Formato numérico preciso inválido')
.transform((val) => val as PreciseAmount);
export const ExternalTransactionDtoSchema = z.object({
tx_id: z.string().min(1),
timestamp: z.string().datetime(),
amount_in: preciseAmountSchema.nullable(),
amount_out: preciseAmountSchema.nullable(),
total_fiat: preciseAmountSchema.refine((val) => Number(val) >= 0, {
message: 'El importe total fiat debe ser no negativo',
}),
});

🚨 Manejo de Errores: Bus Global de Errores

Sección titulada «🚨 Manejo de Errores: Bus Global de Errores»

Si un exchange modifica el formato de sus respuestas o se carga un CSV con campos anómalos, la ACL evita la caída del sistema:

  1. schema.safeParse() intercepta el dato corrupto de forma controlada.
  2. En lugar de arrojar una excepción no capturada, el adaptador emite un evento estructurado al errorBus.
  3. La interfaz de usuario muestra una alerta comprensible señalando la fila o propiedad afectada, protegiendo la sesión del usuario.