fix(core): read the routing fee from fee, not the absent fee_msat
Closes #170. LNbits payment payloads carry `fee`, signed millisats like `amount`. There is no `fee_msat` field, so three modules read `undefined`: PaymentService.PaymentResult declared `fee_msat: number` — a field the API never sends — so the compiler vouched for a number that was always undefined, and the lie propagated to every consumer. market/useLightningPayment persisted `feeMsat: undefined` onto paid orders (on a property the Order type does not even declare). events/LnbitsPaymentProvider had `data.fee_msat ?? 0`, whose fallback masked the miss so every payment recorded a zero fee. `payInvoice` now normalizes at the boundary instead of returning the raw payload: it maps `fee` to a positive `feeMsat`. Doing it once there means no call site can pick the wrong field name or forget that outgoing amounts are signed. `PaymentResult.feeMsat` replaces the phantom field, so the type finally matches what callers receive. Verified against a live pay-invoice response, plus a synthetic payment carrying a real routing fee (internal LNbits transfers are fee-free, so the live case cannot exercise a non-zero fee): live response fee present: True fee_msat present: False synthetic -1234 msat old (events) -> 0 fee silently lost old (market) -> undefined new (both) -> 1234 positive magnitude Nothing read these values downstream, so no totals were miscomputed; the fee was simply recorded as missing or zero.
This commit is contained in:
parent
3e5eeaf7a9
commit
7d4cb3d49d
3 changed files with 25 additions and 6 deletions
|
|
@ -5,7 +5,15 @@ import { toast } from 'vue-sonner'
|
|||
|
||||
export interface PaymentResult {
|
||||
payment_hash: string
|
||||
fee_msat: number
|
||||
/**
|
||||
* Routing fee in millisats, always positive.
|
||||
*
|
||||
* LNbits returns this as `fee`, not `fee_msat`, and signs it negative for
|
||||
* outgoing payments (like `amount`). This interface previously declared
|
||||
* `fee_msat: number`, a field the API never sends, so every consumer read
|
||||
* `undefined` while the compiler vouched for a number.
|
||||
*/
|
||||
feeMsat: number
|
||||
preimage: string
|
||||
}
|
||||
|
||||
|
|
@ -230,7 +238,16 @@ export class PaymentService extends BaseService {
|
|||
throw new Error(errorMessage)
|
||||
}
|
||||
|
||||
return await response.json()
|
||||
// Normalize at the boundary rather than handing the raw LNbits payload
|
||||
// to callers: `fee` is signed millisats, and consumers all want a
|
||||
// positive magnitude. Doing it here means no call site can pick the
|
||||
// wrong field name or forget the sign.
|
||||
const raw = await response.json()
|
||||
return {
|
||||
payment_hash: raw.payment_hash,
|
||||
feeMsat: Math.abs(Number(raw.fee ?? 0)),
|
||||
preimage: raw.preimage ?? ''
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -266,7 +283,7 @@ export class PaymentService extends BaseService {
|
|||
|
||||
this.debug('Payment successful', {
|
||||
paymentHash: paymentResult.payment_hash,
|
||||
feeMsat: paymentResult.fee_msat
|
||||
feeMsat: paymentResult.feeMsat
|
||||
})
|
||||
|
||||
// Show success notification if enabled
|
||||
|
|
|
|||
|
|
@ -84,7 +84,9 @@ export class LnbitsPaymentProvider implements PaymentProvider {
|
|||
const data = await response.json()
|
||||
return {
|
||||
paymentHash: data.payment_hash,
|
||||
feeMsat: data.fee_msat ?? 0,
|
||||
// LNbits sends `fee` (signed millisats), never `fee_msat`. Reading the
|
||||
// latter meant every payment recorded a zero fee.
|
||||
feeMsat: Math.abs(Number(data.fee ?? 0)),
|
||||
preimage: data.preimage ?? '',
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ export function useLightningPayment() {
|
|||
status: 'paid' as const,
|
||||
paidAt: Math.floor(Date.now() / 1000),
|
||||
paymentHash: paymentResult.payment_hash,
|
||||
feeMsat: paymentResult.fee_msat,
|
||||
feeMsat: paymentResult.feeMsat,
|
||||
items: [...order.items], // Convert readonly to mutable
|
||||
shippingZone: order.shippingZone ? {
|
||||
...order.shippingZone,
|
||||
|
|
@ -88,7 +88,7 @@ export function useLightningPayment() {
|
|||
status: 'paid' as const,
|
||||
paidAt: Math.floor(Date.now() / 1000),
|
||||
paymentHash: result.payment_hash,
|
||||
feeMsat: result.fee_msat,
|
||||
feeMsat: result.feeMsat,
|
||||
items: [...order.items], // Convert readonly to mutable
|
||||
shippingZone: order.shippingZone ? {
|
||||
...order.shippingZone,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue