Skip to content

Currency conversion producing zero amounts due to precision issues in server.js #100

Description

@osw282

Diagnosis

Based on analysis of the currencyservice logs and the server.js file, I've identified a critical issue in the currency conversion logic that's causing frequent errors.

The application is repeatedly logging:

Currency conversion resulted in zero amount, switching back to original currency

Root Cause

The issue is in the convert function in src/currencyservice/server.js (lines 178-215). The problem occurs during the two-step conversion process:

  1. Convert from_currency → EUR: The code divides by the exchange rate
  2. Convert EUR → to_currency: The code multiplies by the target exchange rate

However, there are precision issues with the handling of the nanos field (which represents fractional currency units in nanoseconds). Specifically:

  • The conversion calculations use floating-point arithmetic on both units and nanos
  • The final results are floored using Math.floor() which can round small positive values down to zero
  • Small amounts or currencies with large exchange rate differences are particularly affected

Impact

  • Currency conversions frequently result in zero amounts
  • The service falls back to the original currency, but this creates inconsistent user experience
  • Error logs are generated repeatedly, indicating this is a widespread issue
  • The Slack notification system is being triggered frequently (with cooldown protection)

Recommended Fix

  1. Improve precision handling: Use a proper decimal arithmetic library (like decimal.js or big.js) instead of native JavaScript floating-point arithmetic for currency calculations.

  2. Add minimum amount validation: Before performing the conversion, check if the input amount is meaningful and handle edge cases appropriately.

  3. Fix the nanos calculation: The current approach of dividing/multiplying nanos directly by exchange rates is incorrect. Nanos should be handled as part of the total amount calculation.

Example fix for the conversion logic:

const Decimal = require('decimal.js');

// Convert the full amount to a decimal for precise calculation
const fromAmount = new Decimal(from.units).plus(new Decimal(from.nanos).div(1e9));
const euroAmount = fromAmount.div(data[from.currency_code]);
const resultAmount = euroAmount.mul(data[request.to_code]);

// Convert back to units/nanos
result.units = Math.floor(resultAmount.toNumber());
result.nanos = Math.floor((resultAmount.minus(result.units)).mul(1e9).toNumber());
  1. Add better error handling and logging: Include more details about the conversion amounts and rates when errors occur to help with debugging.

This fix will resolve the precision issues causing zero-amount conversions and improve the reliability of the currency service.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions