Skip to content
Open
Show file tree
Hide file tree
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
1 change: 0 additions & 1 deletion Bitkit/Services/PrivatePaykitService+Contacts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,6 @@ extension PrivatePaykitService {
let linkableReceiverPaths = receiverPathSelection.linkableReceiverPaths
let publicationReceiverPaths = receiverPathSelection.publishableReceiverPaths
if let error = receiverPathSelection.error {
firstError = firstError ?? error
Logger.warn(
"Failed to inspect private Paykit receiver markers for \(PubkyPublicKeyFormat.redacted(publicKey)) during \(reason): \(error)",
context: "PrivatePaykit"
Expand Down
20 changes: 14 additions & 6 deletions Bitkit/ViewModels/AppViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ extension AppViewModel {
data = try await decode(invoice: uri)
try ensureScannedDataHandlingOwnership(handlingId, claimedContactPaymentContext: claimedContactPaymentContext)
}
let requestedAmount = contactPaymentContext?.incomingPaymentRequest?.amountSats

switch data {
// BIP21 (Unified) invoice handling
Expand Down Expand Up @@ -500,7 +501,7 @@ extension AppViewModel {
if nodeIsRunning {
// Node is running → we have fresh balances; validate immediately.
// Prefer lightning; if insufficient or no channels/capacity, fall back to onchain.
let canSendLightning = lightningService.canSend(amountSats: lightningInvoice.amountSatoshis)
let canSendLightning = lightningService.canSend(amountSats: requestedAmount ?? lightningInvoice.amountSatoshis)

if canSendLightning {
handleScannedLightningInvoice(lightningInvoice, bolt11: lnInvoice, onchainInvoice: invoice)
Expand All @@ -520,7 +521,10 @@ extension AppViewModel {
// usable channels without capacity).
// Fall back to onchain and validate onchain balance immediately.
let onchainBalance = lightningService.balances?.spendableOnchainBalanceSats ?? 0
guard validateOnchainBalance(invoiceAmount: invoice.amountSatoshis, onchainBalance: onchainBalance) else {
guard validateOnchainBalance(
invoiceAmount: requestedAmount ?? invoice.amountSatoshis,
onchainBalance: onchainBalance
) else {
return
}

Expand All @@ -544,7 +548,10 @@ extension AppViewModel {
// If node is running, validate balance immediately
if lightningService.status?.isRunning == true {
let onchainBalance = lightningService.balances?.spendableOnchainBalanceSats ?? 0
guard validateOnchainBalance(invoiceAmount: invoice.amountSatoshis, onchainBalance: onchainBalance) else {
guard validateOnchainBalance(
invoiceAmount: requestedAmount ?? invoice.amountSatoshis,
onchainBalance: onchainBalance
) else {
return
}
}
Expand Down Expand Up @@ -575,20 +582,21 @@ extension AppViewModel {

// If node is running, we can check for channels and validate immediately
if lightningService.status?.isRunning == true {
let paymentAmount = requestedAmount ?? invoice.amountSatoshis
// If user has no channels at all, they can never pay a pure lightning invoice.
// Show insufficient spending toast and do not navigate to the send flow.
let hasAnyChannels = (lightningService.channels?.isEmpty == false)
if !hasAnyChannels {
let spendingBalance = lightningService.balances?.totalLightningBalanceSats ?? 0
showInsufficientSpendingToast(invoiceAmount: invoice.amountSatoshis, spendingBalance: spendingBalance)
showInsufficientSpendingToast(invoiceAmount: paymentAmount, spendingBalance: spendingBalance)
return
}

// If channels are usable, validate capacity immediately
if let channels = lightningService.channels, channels.contains(where: \.isUsable) {
guard lightningService.canSend(amountSats: invoice.amountSatoshis) else {
guard lightningService.canSend(amountSats: paymentAmount) else {
let spendingBalance = lightningService.balances?.totalLightningBalanceSats ?? 0
showInsufficientSpendingToast(invoiceAmount: invoice.amountSatoshis, spendingBalance: spendingBalance)
showInsufficientSpendingToast(invoiceAmount: paymentAmount, spendingBalance: spendingBalance)
return
}
}
Expand Down
1 change: 1 addition & 0 deletions changelog.d/next/684.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Contact payments now ignore malformed receiver markers from other contacts and show the correct insufficient-balance error for unaffordable payment requests.
Loading