Skip to content

Commit 17b44e5

Browse files
claudeovitrif
authored andcommitted
feat: add boosted txids tracking and display parent txids in activity explore
1 parent b5aace7 commit 17b44e5

File tree

4 files changed

+37
-21
lines changed

4 files changed

+37
-21
lines changed

app/src/main/java/to/bitkit/data/dto/PendingBoostActivity.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ import kotlinx.serialization.Serializable
66
data class PendingBoostActivity(
77
val txId: String,
88
val updatedAt: ULong,
9-
val activityToDelete: String?
9+
val activityToDelete: String?,
10+
val boostTxIds: List<String> = emptyList(),
1011
)

app/src/main/java/to/bitkit/repositories/ActivityRepo.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -428,22 +428,25 @@ class ActivityRepo @Inject constructor(
428428
val updatedActivity = Activity.Onchain(
429429
v1 = newOnChainActivity.v1.copy(
430430
isBoosted = true,
431-
updatedAt = pendingBoostActivity.updatedAt
431+
boostTxIds = pendingBoostActivity.boostTxIds,
432+
updatedAt = pendingBoostActivity.updatedAt,
432433
)
433434
)
434435

435436
if (pendingBoostActivity.activityToDelete != null) {
437+
// RBF: Replace old activity with new one, applying parent chain boostTxIds
436438
replaceActivity(
437439
id = updatedActivity.v1.id,
438440
activity = updatedActivity,
439-
activityIdToDelete = pendingBoostActivity.activityToDelete
441+
activityIdToDelete = pendingBoostActivity.activityToDelete,
440442
).onSuccess {
441443
cacheStore.removeActivityFromPendingBoost(pendingBoostActivity)
442444
}
443445
} else {
446+
// CPFP: Update existing activity (though CPFP is handled immediately now)
444447
updateActivity(
445448
id = updatedActivity.v1.id,
446-
activity = updatedActivity
449+
activity = updatedActivity,
447450
).onSuccess {
448451
cacheStore.removeActivityFromPendingBoost(pendingBoostActivity)
449452
}

app/src/main/java/to/bitkit/ui/screens/wallets/activity/ActivityExploreScreen.kt

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -271,13 +271,9 @@ private fun ColumnScope.OnchainDetails(
271271
.size(16.dp)
272272
.align(Alignment.CenterHorizontally)
273273
)
274-
} // TODO use real boosted parents from bitkit-core/ldk-node when available
275-
val boostedParents = listOfNotNull(
276-
"todo_first_parent_txid".takeIf { onchain.isBoosted() && !onchain.v1.confirmed },
277-
"todo_second_parent_txid".takeIf { onchain.isBoosted() && onchain.v1.confirmed },
278-
)
274+
}
279275

280-
boostedParents.forEachIndexed { index, parent ->
276+
onchain.v1.boostTxIds.forEachIndexed { index, parent ->
281277
val isRbf = onchain.boostType() == BoostType.RBF
282278
Section(
283279
title = stringResource(

app/src/main/java/to/bitkit/ui/sheets/BoostTransactionViewModel.kt

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import org.lightningdevkit.ldknode.Txid
1717
import to.bitkit.data.dto.PendingBoostActivity
1818
import to.bitkit.ext.BoostType
1919
import to.bitkit.ext.boostType
20+
import to.bitkit.ext.nowMillis
2021
import to.bitkit.ext.nowTimestamp
2122
import to.bitkit.models.TransactionSpeed
2223
import to.bitkit.repositories.ActivityRepo
@@ -203,6 +204,8 @@ class BoostTransactionViewModel @Inject constructor(
203204
destinationAddress = walletRepo.getOnchainAddress(),
204205
).fold(
205206
onSuccess = { newTxId ->
207+
// For CPFP, immediately update parent with child txId
208+
Logger.debug("CPFP successful. Appending child txId $newTxId to parent's boostTxIds", context = TAG)
206209
handleBoostSuccess(newTxId, isRBF = false)
207210
},
208211
onFailure = { error ->
@@ -283,7 +286,7 @@ class BoostTransactionViewModel @Inject constructor(
283286
/**
284287
* Updates activity based on boost type:
285288
* - RBF: Updates current activity with boost data, then replaces with new transaction
286-
* - CPFP: Simply updates the current activity
289+
* - CPFP: Updates parent activity by appending child txId to boostTxIds
287290
*/
288291
private suspend fun updateActivity(newTxId: Txid, isRBF: Boolean): Result<Unit> {
289292
Logger.debug("Updating activity for txId: $newTxId. isRBF: $isRBF", context = TAG)
@@ -294,24 +297,25 @@ class BoostTransactionViewModel @Inject constructor(
294297
return if (isRBF) {
295298
handleRBFUpdate(newTxId, currentActivity)
296299
} else {
297-
handleCPFPUpdate(currentActivity)
300+
handleCPFPUpdate(currentActivity, newTxId)
298301
}
299302
}
300303

301304
/**
302-
* Handles CPFP (Child Pays For Parent) update by simply updating the current activity
305+
* Handles CPFP (Child Pays For Parent) update by appending child txId to parent's boostTxIds
303306
*/
304-
private suspend fun handleCPFPUpdate(currentActivity: OnchainActivity): Result<Unit> {
307+
private suspend fun handleCPFPUpdate(currentActivity: OnchainActivity, childTxId: Txid): Result<Unit> {
305308
val updatedActivity = Activity.Onchain(
306309
v1 = currentActivity.copy(
307310
isBoosted = true,
308-
updatedAt = nowTimestamp().toEpochMilli().toULong()
311+
boostTxIds = currentActivity.boostTxIds + childTxId,
312+
updatedAt = nowMillis().toULong(),
309313
)
310314
)
311315

312316
return activityRepo.updateActivity(
313317
id = updatedActivity.v1.id,
314-
activity = updatedActivity
318+
activity = updatedActivity,
315319
)
316320
}
317321

@@ -328,13 +332,13 @@ class BoostTransactionViewModel @Inject constructor(
328332
isBoosted = true,
329333
feeRate = _uiState.value.feeRate,
330334
fee = _uiState.value.totalFeeSats,
331-
updatedAt = nowTimestamp().toEpochMilli().toULong()
335+
updatedAt = nowMillis().toULong(),
332336
)
333337
)
334338

335339
activityRepo.updateActivity(
336340
id = updatedCurrentActivity.v1.id,
337-
activity = updatedCurrentActivity
341+
activity = updatedCurrentActivity,
338342
)
339343

340344
// Then find and replace with the new activity
@@ -379,7 +383,7 @@ class BoostTransactionViewModel @Inject constructor(
379383
v1 = newOnChainActivity.v1.copy(
380384
isBoosted = true,
381385
feeRate = _uiState.value.feeRate,
382-
updatedAt = nowTimestamp().toEpochMilli().toULong()
386+
updatedAt = nowMillis().toULong(),
383387
)
384388
)
385389

@@ -412,13 +416,25 @@ class BoostTransactionViewModel @Inject constructor(
412416

413417
/**
414418
* Caches activity data for pending boost operation
419+
* - For RBF: stores parent chain (existing boostTxIds + current txId)
420+
* - For CPFP: stores empty list (child tx is added to parent's boostTxIds during sync)
415421
*/
416422
private suspend fun cachePendingBoostActivity(newTxId: Txid, activityToDelete: String?) {
423+
val currentActivity = activity?.v1
424+
val boostTxIds = if (activityToDelete != null && currentActivity != null) {
425+
// RBF: Track full parent chain (existing boostTxIds + current txId being replaced)
426+
currentActivity.boostTxIds + currentActivity.txId
427+
} else {
428+
// CPFP: No parent tracking needed
429+
emptyList()
430+
}
431+
417432
activityRepo.addActivityToPendingBoost(
418433
PendingBoostActivity(
419434
txId = newTxId,
420-
updatedAt = nowTimestamp().toEpochMilli().toULong(),
421-
activityToDelete = activityToDelete
435+
updatedAt = nowMillis().toULong(),
436+
activityToDelete = activityToDelete,
437+
boostTxIds = boostTxIds,
422438
)
423439
)
424440
}

0 commit comments

Comments
 (0)