Skip to content

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

@osw282

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions