diff --git a/src/modules/base/composables/usePriceConversion.ts b/src/modules/base/composables/usePriceConversion.ts index 5dfc083..b5766e5 100644 --- a/src/modules/base/composables/usePriceConversion.ts +++ b/src/modules/base/composables/usePriceConversion.ts @@ -21,6 +21,37 @@ function cacheKey(amount: number, from: string, to: string): string { * conversion preview as best-effort UX, never as a blocker. 60s in-memory * cache de-duplicates dialog re-renders. */ +/** + * Pull the converted value out of an LNbits `/conversion` response. + * + * The endpoint does not echo the `to` key it was given. It always names the + * satoshi amount `"sats"` (plural) regardless of whether the caller asked for + * "sat" or "sats", and it returns fiat under the upper-case ISO code: + * + * POST {from_: "EUR", to: "sat", amount: 5.50} -> {EUR: 5.5, sats: 7298, BTC: 7.298e-05} + * POST {from_: "sat", to: "EUR", amount: 7295} -> {BTC: ..., sats: 7295, EUR: 5.4972} + * + * So a lookup of `data["sat"]` misses, which meant every sat-denominated + * conversion silently returned null. + */ +function pickConverted(data: Record, to: string): number | undefined { + const lower = to.toLowerCase() + const candidates = + lower === 'sat' || lower === 'sats' + ? ['sats', 'sat'] + : [to, to.toUpperCase(), lower] + + for (const key of candidates) { + if (typeof data[key] === 'number') return data[key] + } + // Older/other shapes kept as a last resort. + return typeof data.amount === 'number' + ? data.amount + : typeof data.result === 'number' + ? data.result + : undefined +} + export function usePriceConversion() { const lnbitsAPI = injectService(SERVICE_TOKENS.LNBITS_API) @@ -38,12 +69,7 @@ export function usePriceConversion() { try { const data = await lnbitsAPI.getConversion({ from, to, amount }) - const result = - data[to] ?? - data[to.toUpperCase()] ?? - data[to.toLowerCase()] ?? - (data as Record).amount ?? - (data as Record).result + const result = pickConverted(data, to) if (typeof result !== 'number') return null cache.set(key, { value: result, expiresAt: Date.now() + TTL_MS }) return result