Skip to content

Commit b68c961

Browse files
committed
Mark RBFed txs as removed from mempool
1 parent 5e9b905 commit b68c961

File tree

3 files changed

+58
-18
lines changed

3 files changed

+58
-18
lines changed

Bitkit/Services/CoreService.swift

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ class ActivityService {
150150
let preservedTransferTxId = existingOnchain?.transferTxId
151151
let preservedFeeRate = existingOnchain?.feeRate ?? 1
152152
let preservedAddress = existingOnchain?.address ?? "Loading..."
153+
let preservedDoesExist = existingOnchain?.doesExist ?? true
153154

154155
// Check if this transaction is a channel transfer (open or close)
155156
if preservedChannelId == nil || !preservedIsTransfer {
@@ -211,6 +212,9 @@ class ActivityService {
211212
let finalChannelId = preservedChannelId
212213
let finalTransferTxId = preservedTransferTxId
213214

215+
// If confirmed, set doesExist to true; otherwise preserve existing value
216+
let finalDoesExist = isConfirmed ? true : preservedDoesExist
217+
214218
let onchain = OnchainActivity(
215219
id: payment.id,
216220
txType: payment.direction == .outbound ? .sent : .received,
@@ -224,7 +228,7 @@ class ActivityService {
224228
isBoosted: shouldMarkAsBoosted, // Mark as boosted if it's a replacement transaction
225229
boostTxIds: boostTxIds,
226230
isTransfer: finalIsTransfer,
227-
doesExist: true,
231+
doesExist: finalDoesExist,
228232
confirmTimestamp: confirmedTimestamp,
229233
channelId: finalChannelId,
230234
transferTxId: finalTransferTxId,
@@ -241,6 +245,11 @@ class ActivityService {
241245
print(payment)
242246
addedCount += 1
243247
}
248+
249+
// If a removed transaction confirms, mark its replacement transactions as removed
250+
if !preservedDoesExist && isConfirmed {
251+
try await markReplacementTransactionsAsRemoved(originalTxId: txid)
252+
}
244253
} else if case let .bolt11(hash, preimage, secret, description, bolt11) = payment.kind {
245254
// Skip pending inbound payments, just means they created an invoice
246255
guard !(payment.status == .pending && payment.direction == .inbound) else { continue }
@@ -298,6 +307,35 @@ class ActivityService {
298307
}
299308
}
300309

310+
/// Marks replacement transactions (with originalTxId in boostTxIds) as doesExist = false when original confirms
311+
private func markReplacementTransactionsAsRemoved(originalTxId: String) async throws {
312+
let allActivities = try getActivities(
313+
filter: .onchain,
314+
txType: nil,
315+
tags: nil,
316+
search: nil,
317+
minDate: nil,
318+
maxDate: nil,
319+
limit: nil,
320+
sortDirection: nil
321+
)
322+
323+
for activity in allActivities {
324+
guard case let .onchain(onchainActivity) = activity else { continue }
325+
326+
if onchainActivity.boostTxIds.contains(originalTxId) && onchainActivity.doesExist {
327+
Logger.info(
328+
"Marking replacement transaction \(onchainActivity.txId) as doesExist = false (original \(originalTxId) confirmed)",
329+
context: "CoreService.markReplacementTransactionsAsRemoved"
330+
)
331+
332+
var updatedActivity = onchainActivity
333+
updatedActivity.doesExist = false
334+
try updateActivity(activityId: onchainActivity.id, activity: .onchain(updatedActivity))
335+
}
336+
}
337+
}
338+
301339
/// Finds the channel ID associated with a transaction based on its direction
302340
private func findChannelForTransaction(txid: String, direction: PaymentDirection) async -> String? {
303341
switch direction {
@@ -693,25 +731,18 @@ class ActivityService {
693731
"Added original transaction \(onchainActivity.txId) to replaced transactions list", context: "CoreService.boostOnchainTransaction"
694732
)
695733

696-
// For RBF, delete the original activity since it's been replaced
697-
// The new transaction will be synced automatically from LDK
734+
// For RBF, mark the original activity as doesExist = false instead of deleting it
735+
// This allows it to be displayed with the "removed" status
698736
Logger.debug(
699-
"Attempting to delete original activity \(activityId) before RBF replacement", context: "CoreService.boostOnchainTransaction"
737+
"Marking original activity \(activityId) as doesExist = false (replaced by RBF)", context: "CoreService.boostOnchainTransaction"
700738
)
701739

702-
// Use the proper delete function that returns a Bool
703-
let deleteResult = try deleteActivityById(activityId: activityId)
704-
Logger.info("Delete result for original activity \(activityId): \(deleteResult)", context: "CoreService.boostOnchainTransaction")
705-
706-
// Double-check that the activity was deleted
707-
let checkActivity = try getActivityById(activityId: activityId)
708-
if checkActivity == nil {
709-
Logger.info("Confirmed: Original activity \(activityId) was successfully deleted", context: "CoreService.boostOnchainTransaction")
710-
} else {
711-
Logger.error(
712-
"Warning: Original activity \(activityId) still exists after deletion attempt", context: "CoreService.boostOnchainTransaction"
713-
)
714-
}
740+
onchainActivity.doesExist = false
741+
try updateActivity(activityId: activityId, activity: .onchain(onchainActivity))
742+
Logger.info(
743+
"Successfully marked activity \(activityId) as doesExist = false (replaced by RBF)",
744+
context: "CoreService.boostOnchainTransaction"
745+
)
715746

716747
self.activitiesChangedSubject.send()
717748
}

Bitkit/Views/Wallets/Activity/ActivityItemView.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,12 @@ struct ActivityItemView: View {
225225
BodySSBText(t("wallet__activity_failed"), textColor: .purpleAccent)
226226
}
227227
case let .onchain(activity):
228-
if activity.confirmed == true {
228+
if !activity.doesExist {
229+
Image("x-circle")
230+
.foregroundColor(.textSecondary)
231+
.frame(width: 16, height: 16)
232+
BodySSBText(t("wallet__activity_removed_title"), textColor: .textSecondary)
233+
} else if activity.confirmed == true {
229234
Image("check-circle")
230235
.foregroundColor(.greenAccent)
231236
.frame(width: 16, height: 16)

Bitkit/Views/Wallets/Activity/ActivityRowOnchain.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ struct ActivityRowOnchain: View {
4949
}
5050

5151
private var description: String {
52+
if !item.doesExist {
53+
return t("wallet__activity_removed")
54+
}
55+
5256
if item.isTransfer {
5357
switch item.txType {
5458
case .sent:

0 commit comments

Comments
 (0)