Skip to content

Anti-Corruption Layer & Zero Float Loss

🛡️ Anti-Corruption Layer & Zero Float Loss

Section titled “🛡️ Anti-Corruption Layer & Zero Float Loss”

In enterprise software engineering, an Anti-Corruption Layer (ACL) acts as a defensive perimeter between external data providers (APIs, third-party CSV files, untrusted network inputs) and the internal pure Domain Model.

In financial software, this boundary has a second critical responsibility: guaranteeing mathematical precision and eliminating floating-point rounding errors.


🚫 The Danger of IEEE-754 Floating-Point Numbers

Section titled “🚫 The Danger of IEEE-754 Floating-Point Numbers”

Standard JavaScript numbers are 64-bit binary floating-point numbers conforming to the IEEE-754 standard. In financial applications, this introduces catastrophic rounding anomalies:

// Classic floating point loss in JavaScript
0.1 + 0.2 === 0.30000000000000004 // true
// In cryptocurrency micro-transactions:
const satoshis = 0.00000001 * 3;
console.log(satoshis); // 0.000000030000000000000004

When calculating multi-year FIFO tax queues with thousands of lots and fractional token fees, floating-point rounding accumulates errors that:

  1. Prevent transactions from balancing (amount_in - amount_out !== 0).
  2. Fabricate fractional dust balances (0.000000000000001 BTC remaining in closed lots).
  3. Violate tax reporting standards (AEAT requires strict monetary balance).

💎 The PreciseAmount Branded Value Object

Section titled “💎 The PreciseAmount Branded Value Object”

To eliminate floating-point drift while maintaining 100% decoupling from third-party libraries inside the core domain, Kryptofolio uses 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('Cannot construct PreciseAmount from non-finite number');
}
return String(val) as PreciseAmount;
};
  1. Domain Ports only speak PreciseAmount: Interfaces like ILedgerPort and ITaxPort never accept raw number or Decimal objects.
  2. Encapsulated Math: High-precision arithmetic is confined strictly to Application use cases and Infrastructure adapters using decimal.js or DuckDB’s DECIMAL(38,18) columnar types.

🔍 The Anti-Corruption Layer (Zod Validation)

Section titled “🔍 The Anti-Corruption Layer (Zod Validation)”

Before any external data touches the domain, it must pass through strict Zod schemas in the Infrastructure layer:

flowchart TD
    External["External API / Raw CSV Input"] -->|Raw JSON / Strings| Adapter["Infrastructure Adapter"]
    Adapter -->|safeParse| Schema{"Zod ACL Schema\n(preciseAmountSchema)"}
    Schema -->|Valid| Domain["Domain Entity Mapping\n(PreciseAmount)"]
    Domain -->|Safe| Store["Pinia Colada / Use Cases"]
    Schema -->|Invalid| ErrorBus["Global Error Bus\n(Controlled Alert, No Crash)"]
import { z } from 'zod';
// Strict regex: requires valid numeric format, non-empty, no exponent notation
export const preciseAmountSchema = z
.string()
.trim()
.regex(/^-?\d+(\.\d+)?$/, 'Invalid precise numerical format')
.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: 'Fiat total must be non-negative',
}),
});

🚨 Controlled Fault Tolerance: Global Error Bus

Section titled “🚨 Controlled Fault Tolerance: Global Error Bus”

If an external exchange modifies their API contract or an invalid CSV row is ingested, the Anti-Corruption Layer prevents catastrophic application failure:

  1. schema.safeParse() captures the malformed data.
  2. Instead of throwing an unhandled runtime exception, the adapter dispatches a structured event to the errorBus.
  3. The UI gracefully surfaces a localized warning to the user, pinpointing the corrupted row or missing field while preserving the integrity of the active state.