Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 72 additions & 12 deletions src/analytics/math_scaler.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from decimal import ROUND_DOWN, Decimal, InvalidOperation
from typing import Union
from fractions import Fraction


# ---------------------------------------------------------------------------
# Scale constants
Expand All @@ -20,7 +22,6 @@

Number = Union[int, float, Decimal]


# ---------------------------------------------------------------------------
# Internal helpers
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -160,30 +161,89 @@ def pack_rate(value: Number) -> int:
"""Convenience wrapper: scale *value* to a ``SCALE_7`` integer for payload packing.

This is the canonical entry-point used before serialising a rate into any
Soroban contract data payload. It enforces the ``10^7`` fixed-integer base
Soroban contract data payload. It enforces the ``10^7`` fixed-integer base
contract and rejects non-finite or boolean inputs early.
"""
return scale_up(value, SCALE_7)

Parameters
----------
value:
Raw exchange rate (int, float, or Decimal).

Returns
-------
int
Deterministic ``SCALE_7`` integer ready for transmission.
ConversionMatrix = dict[str, dict[str, Fraction]]


def build_conversion_matrix(
rates: dict[tuple[str, str], Number],
) -> ConversionMatrix:
"""
return scale_up(value, SCALE_7)
Build an exact fraction-based conversion matrix.
"""
matrix: ConversionMatrix = {}

for (source, target), rate in rates.items():
matrix.setdefault(source, {})

decimal_rate = _to_decimal(rate)
matrix[source][target] = Fraction(decimal_rate)

return matrix


def convert_path(
matrix: ConversionMatrix,
path: list[str],
) -> Fraction:
"""
Compute an exact conversion along a multi-hop path.
"""
if len(path) < 2:
return Fraction(1)

result = Fraction(1)

for src, dst in zip(path, path[1:]):
try:
result *= matrix[src][dst]
except KeyError as exc:
raise KeyError(f"Missing conversion rate: {src} -> {dst}") from exc

return result


def fraction_to_scaled(
value: Fraction,
factor: int = SCALE_7,
) -> int:
"""
Convert an exact Fraction into a SCALE_7 integer.
"""
return scale_up(
Decimal(value.numerator) / Decimal(value.denominator),
factor,
)


def scaled_to_fraction(
value: int,
factor: int = SCALE_7,
) -> Fraction:
"""
Convert a SCALE_7 integer into an exact Fraction.
"""
return Fraction(value, factor)


__all__ = [
"SCALE_7",
"SCALE_14",
"Number",
"ConversionMatrix",
"scale_up",
"scale_down",
"multiply_rates",
"cross_feed_multiply",
"floor_divide",
"pack_rate",
]
"build_conversion_matrix",
"convert_path",
"fraction_to_scaled",
"scaled_to_fraction",
]
Loading