Skip to content

fix(cashout): decimal-safe JMD rate on the ACTUAL JMDAmount used by cashout#450

Open
islandbitcoin wants to merge 2 commits into
mainfrom
fix/jmd-cashout-fractional-rate-real
Open

fix(cashout): decimal-safe JMD rate on the ACTUAL JMDAmount used by cashout#450
islandbitcoin wants to merge 2 commits into
mainfrom
fix/jmd-cashout-fractional-rate-real

Conversation

@islandbitcoin

@islandbitcoin islandbitcoin commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Problem

After #449 deployed to TEST, JMD cashout still failed on fractional rates. Debugging the running image found two JMDAmount classes:

The barrel src/domain/shared/index.ts does export * from "./money" and only re-exports USDTAmount from MoneyAmount.ts, so getCashoutExchangeRate (importing JMDAmount via @domain/shared) uses the money/JMDAmount.ts copy. #449 fixed the wrong twin — its error-map change worked (message changed) but the conversion bug remained. Proof from the deployed image: barrel JMDAmount.dollars(155.5)BigIntConversionError; direct-file → 155.50; same class? false.

Fix

Apply the decimal-safe conversion (mirror the adjacent money/USDAmount.dollars, Money-lib + HALF_TO_EVEN) to money/JMDAmount.ts, and add the Round import.

Test (this is the part #449 was missing)

Added a fractional-rate regression case to test/flash/unit/domain/shared/Money.spec.ts, which imports JMDAmount from @domain/shared — the exact barrel-resolved class production uses. The only pre-existing JMDAmount.dollars test used an integer (160), which is why the suite stayed green through the entire incident.

Ran for real (not just runtime-debugged):

  • Without the fix: the new test fails — BigIntConversionError: 155.5 cannot be converted to a BigInt.
  • With the fix: full suite 22/22 pass; tsc -p tsconfig.json --noEmit clean.

The dead twin — tracked, not hand-waved

After this PR, MoneyAmount.ts's JMDAmount (the one #449 patched) is dead code shadowed by the barrel — a trap that will drift again. It can't be trivially deleted (the base MoneyAmount.from() references it), so the cleanup is its own change: ENG-518Collapse duplicate JMDAmount/MoneyAmount implementations.

🤖 Generated with Claude Code

bobodread876 and others added 2 commits July 14, 2026 22:03
…ashout

Follow-up to #449. There are two `JMDAmount` classes in the tree:
`src/domain/shared/MoneyAmount.ts` (fixed in #449) and
`src/domain/shared/money/JMDAmount.ts`. The barrel `domain/shared/index.ts`
exports JMDAmount from `./money` (`export * from "./money"`, taking only
USDTAmount from MoneyAmount.ts), so cashout — via `@domain/shared` — imports
the `money/JMDAmount.ts` copy, which still did `new JMDAmount(BigInt(d) * 100n)`
and threw on every fractional NCB rate. #449's conversion fix therefore had no
effect on cashout (its error-map half did work).

Applied the same decimal-safe rewrite (mirror `money/USDAmount.dollars`) to
`money/JMDAmount.ts`. Verified: dollars(155.5)=155.50, 152.7=152.70, 0.5=0.50.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a fractional-rate case to Money.spec.ts, which imports JMDAmount from
@domain/shared — the exact barrel-resolved class the cashout path uses. The
only pre-existing JMDAmount.dollars test used an integer (160), so the suite
stayed green while every fractional NCB rate crashed cashout in prod.

Verified: fails without the fix (BigIntConversionError on 155.5), passes with
it; full suite 22/22, tsc --noEmit clean.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants