Skip to content

Commit a1a1e37

Browse files
authored
Merge pull request #306 from synonymdev/fix/notifications
fix(notifications): handling for payments and channel opening
2 parents 95d7b26 + cdb87dc commit a1a1e37

File tree

2 files changed

+139
-19
lines changed

2 files changed

+139
-19
lines changed

Bitkit/ViewModels/AppViewModel.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,11 @@ extension AppViewModel {
423423
)
424424

425425
try await CoreService.shared.activity.insert(.lightning(ln))
426+
427+
// Show receivedTx sheet for CJIT payment
428+
await MainActor.run {
429+
sheetViewModel.showSheet(.receivedTx, data: ReceivedTxSheetDetails(type: .lightning, sats: amount))
430+
}
426431
} else {
427432
toast(
428433
type: .lightning,

BitkitNotification/NotificationService.swift

Lines changed: 134 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import BitkitCore
12
import LDKNode
23
import os.log
34
import UserNotifications
@@ -17,7 +18,7 @@ class NotificationService: UNNotificationServiceExtension {
1718
var notificationPayload: [String: Any]?
1819

1920
private lazy var notificationLogger: OSLog = {
20-
let bundleID = Bundle.main.bundleIdentifier ?? "to.bitkit-regtest.notification"
21+
let bundleID = Bundle.main.bundleIdentifier ?? "to.bitkit.notification"
2122
return OSLog(subsystem: bundleID, category: "NotificationService")
2223
}()
2324

@@ -57,10 +58,6 @@ class NotificationService: UNNotificationServiceExtension {
5758
}
5859

5960
do {
60-
// TODO: switch to electrum after syncing issues are fixed
61-
// For notification extension, use default Electrum server URL for now
62-
// try await LightningService.shared.setup(walletIndex: self.walletIndex, electrumServerUrl: Env.electrumServerUrl)
63-
6461
try await LightningService.shared.setup(walletIndex: self.walletIndex)
6562
try await LightningService.shared.start { event in
6663
self.lightningEventTime = CFAbsoluteTimeGetCurrent()
@@ -90,16 +87,31 @@ class NotificationService: UNNotificationServiceExtension {
9087
return
9188
}
9289

93-
os_log("🔔 NotificationService: Open channel request for order %{public}@", log: notificationLogger, type: .error, orderId)
90+
guard let lspId = notificationPayload?["lspId"] as? String else {
91+
os_log("🔔 NotificationService: Missing lspId", log: notificationLogger, type: .error)
92+
return
93+
}
94+
95+
os_log(
96+
"🔔 NotificationService: Open channel request for order %{public}@ with LSP %{public}@",
97+
log: notificationLogger,
98+
type: .error,
99+
orderId,
100+
lspId
101+
)
94102

95103
do {
104+
// First, ensure we're connected to the LSP peer
105+
try await self.ensurePeerConnected(lspId: lspId)
106+
107+
// Now open the channel
96108
let order = try await CoreService.shared.blocktank.open(orderId: orderId)
97109
os_log("🔔 NotificationService: Channel opened for order %{public}@", log: notificationLogger, type: .error, order.id)
98110
} catch {
99111
logError(error, context: "Failed to open channel")
100112

101-
self.bestAttemptContent?.title = "Spending Balance Setup Failed"
102-
self.bestAttemptContent?.body = error.localizedDescription
113+
self.bestAttemptContent?.title = "Spending Balance Setup Ready"
114+
self.bestAttemptContent?.body = "Tap to finalize transfer to spending"
103115

104116
self.deliver()
105117
}
@@ -164,11 +176,30 @@ class NotificationService: UNNotificationServiceExtension {
164176
os_log("🔔 New LDK event: %{public}@", log: notificationLogger, type: .error, String(describing: event))
165177

166178
switch event {
167-
case let .paymentReceived(_, _, amountMsat, _):
179+
case let .paymentReceived(_, paymentHash, amountMsat, _):
180+
// For incomingHtlc notifications, only show notification if payment hash matches
181+
if notificationType == .incomingHtlc {
182+
guard let expectedPaymentHash = notificationPayload?["paymentHash"] as? String else {
183+
os_log("🔔 NotificationService: Missing paymentHash in notification payload", log: notificationLogger, type: .error)
184+
return
185+
}
186+
187+
// Only process if this is the payment we're waiting for
188+
guard paymentHash == expectedPaymentHash else {
189+
os_log(
190+
"🔔 NotificationService: Payment hash mismatch. Expected: %{public}@, Got: %{public}@",
191+
log: notificationLogger,
192+
type: .error,
193+
expectedPaymentHash,
194+
paymentHash
195+
)
196+
return
197+
}
198+
}
199+
168200
let sats = amountMsat / 1000
169201
bestAttemptContent?.title = "Payment Received"
170202
bestAttemptContent?.body = "\(sats)"
171-
ReceivedTxSheetDetails(type: .lightning, sats: sats).save() // Save for UI to pick up
172203

173204
if notificationType == .incomingHtlc {
174205
deliver()
@@ -190,6 +221,41 @@ class NotificationService: UNNotificationServiceExtension {
190221
bestAttemptContent?.title = "Payment Received"
191222
bestAttemptContent?.body = "\(sats)"
192223
ReceivedTxSheetDetails(type: .lightning, sats: sats).save() // Save for UI to pick up
224+
225+
// Add activity item for CJIT payment
226+
Task {
227+
do {
228+
let cjitOrder = await CoreService.shared.blocktank.getCjit(channel: channel)
229+
if let cjitOrder {
230+
let now = UInt64(Date().timeIntervalSince1970)
231+
232+
let ln = LightningActivity(
233+
id: channel.fundingTxo?.txid.description ?? "",
234+
txType: .received,
235+
status: .succeeded,
236+
value: sats,
237+
fee: 0,
238+
invoice: cjitOrder.invoice.request,
239+
message: "",
240+
timestamp: now,
241+
preimage: nil,
242+
createdAt: now,
243+
updatedAt: nil,
244+
seenAt: nil
245+
)
246+
247+
try await CoreService.shared.activity.insert(.lightning(ln))
248+
os_log("🔔 NotificationService: Added CJIT activity item", log: notificationLogger, type: .error)
249+
}
250+
} catch {
251+
os_log(
252+
"🔔 NotificationService: Failed to add CJIT activity: %{public}@",
253+
log: notificationLogger,
254+
type: .error,
255+
error.localizedDescription
256+
)
257+
}
258+
}
193259
}
194260

195261
deliver()
@@ -224,7 +290,7 @@ class NotificationService: UNNotificationServiceExtension {
224290

225291
// MARK: New Onchain Transaction Events
226292

227-
case let .onchainTransactionReceived(txid, details):
293+
case let .onchainTransactionReceived(_, details):
228294
// Show notification for incoming onchain transactions
229295
if details.amountSats > 0 {
230296
let sats = UInt64(abs(Int64(details.amountSats)))
@@ -233,14 +299,15 @@ class NotificationService: UNNotificationServiceExtension {
233299
ReceivedTxSheetDetails(type: .onchain, sats: sats).save() // Save for UI to pick up
234300
deliver()
235301
}
236-
case let .onchainTransactionConfirmed(txid, blockHash, blockHeight, confirmationTime, details):
237-
// Transaction confirmed - could show notification if it was previously unconfirmed
238-
if details.amountSats > 0 {
239-
let sats = UInt64(abs(Int64(details.amountSats)))
240-
bestAttemptContent?.title = "Payment Confirmed"
241-
bestAttemptContent?.body = "\(sats) confirmed at block \(blockHeight)"
242-
deliver()
243-
}
302+
case .onchainTransactionConfirmed:
303+
// // Transaction confirmed - could show notification if it was previously unconfirmed
304+
// if details.amountSats > 0 {
305+
// let sats = UInt64(abs(Int64(details.amountSats)))
306+
// bestAttemptContent?.title = "Payment Confirmed"
307+
// bestAttemptContent?.body = "₿ \(sats) confirmed at block \(blockHeight)"
308+
// deliver()
309+
// }
310+
break
244311
case .onchainTransactionReplaced, .onchainTransactionReorged, .onchainTransactionEvicted:
245312
// These events are less critical for notifications, but could be logged
246313
os_log("🔔 Onchain transaction state changed: %{public}@", log: notificationLogger, type: .error, String(describing: event))
@@ -331,6 +398,54 @@ class NotificationService: UNNotificationServiceExtension {
331398
}
332399
}
333400

401+
/// Ensures the peer is connected before attempting to open a channel
402+
/// - Parameter lspId: The LSP node ID to connect to
403+
private func ensurePeerConnected(lspId: String) async throws {
404+
// Find the peer in trusted peers list
405+
guard let peer = Env.trustedLnPeers.first(where: { $0.nodeId == lspId }) else {
406+
os_log("🔔 NotificationService: LSP %{public}@ not found in trusted peers", log: notificationLogger, type: .error, lspId)
407+
throw AppError(message: "LSP not found in trusted peers", debugMessage: "LSP ID: \(lspId)")
408+
}
409+
410+
// Check if already connected
411+
if let peers = LightningService.shared.peers, peers.contains(where: { $0.nodeId == lspId }) {
412+
os_log("🔔 NotificationService: Already connected to LSP %{public}@", log: notificationLogger, type: .error, lspId)
413+
return
414+
}
415+
416+
// Connect to the peer
417+
os_log("🔔 NotificationService: Connecting to LSP %{public}@ at %{public}@", log: notificationLogger, type: .error, lspId, peer.address)
418+
try await LightningService.shared.connectPeer(peer: peer)
419+
420+
// Wait for connection to be established (with timeout)
421+
let maxWaitTime: TimeInterval = 10.0
422+
let pollInterval: TimeInterval = 0.5
423+
let startTime = Date()
424+
425+
while Date().timeIntervalSince(startTime) < maxWaitTime {
426+
if let peers = LightningService.shared.peers, peers.contains(where: { $0.nodeId == lspId }) {
427+
os_log("🔔 NotificationService: Successfully connected to LSP %{public}@", log: notificationLogger, type: .error, lspId)
428+
return
429+
}
430+
431+
try await Task.sleep(nanoseconds: UInt64(pollInterval * 1_000_000_000))
432+
}
433+
434+
// Timeout - check one more time
435+
if let peers = LightningService.shared.peers, peers.contains(where: { $0.nodeId == lspId }) {
436+
os_log(
437+
"🔔 NotificationService: Successfully connected to LSP %{public}@ (after timeout check)",
438+
log: notificationLogger,
439+
type: .error,
440+
lspId
441+
)
442+
return
443+
}
444+
445+
os_log("🔔 NotificationService: Timeout waiting for LSP connection %{public}@", log: notificationLogger, type: .error, lspId)
446+
throw AppError(message: "Failed to connect to LSP", debugMessage: "Timeout after \(maxWaitTime)s waiting for peer \(lspId)")
447+
}
448+
334449
/// Logs comprehensive error details
335450
private func logError(_ error: Error, context: String) {
336451
os_log(

0 commit comments

Comments
 (0)