Skip to content

Commit 0e5c058

Browse files
committed
refactor: code cleanup
1 parent 77cb6ac commit 0e5c058

File tree

3 files changed

+138
-70
lines changed

3 files changed

+138
-70
lines changed

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import kotlinx.serialization.Serializable
55
@Serializable
66
data class PendingBoostActivity(
77
val txId: String,
8-
val feeRate: ULong,
9-
val fee: ULong,
108
val updatedAt: ULong,
119
val activityToDelete: String?
1210
)

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,8 +320,6 @@ class ActivityRepo @Inject constructor(
320320
val updatedActivity = Activity.Onchain(
321321
v1 = newOnChainActivity.v1.copy(
322322
isBoosted = true,
323-
feeRate = pendingBoostActivity.feeRate,
324-
fee = pendingBoostActivity.fee,
325323
updatedAt = pendingBoostActivity.updatedAt
326324
)
327325
)

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

Lines changed: 138 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import androidx.lifecycle.ViewModel
44
import androidx.lifecycle.viewModelScope
55
import com.synonym.bitkitcore.Activity
66
import com.synonym.bitkitcore.ActivityFilter
7+
import com.synonym.bitkitcore.OnchainActivity
78
import com.synonym.bitkitcore.PaymentType
89
import dagger.hilt.android.lifecycle.HiltViewModel
910
import kotlinx.coroutines.flow.MutableSharedFlow
@@ -260,90 +261,161 @@ class BoostTransactionViewModel @Inject constructor(
260261
}
261262
}
262263

263-
/**RBF: Update the current activity with boost data -> when the new transaction is created, se it as boosting and
264-
* delete the old one
265-
* CPFP: Just update the current activity*/
264+
/**
265+
* Updates activity based on boost type:
266+
* - RBF: Updates current activity with boost data, then replaces with new transaction
267+
* - CPFP: Simply updates the current activity
268+
*/
266269
private suspend fun updateActivity(newTxId: Txid, isRBF: Boolean): Result<Unit> {
267-
Logger.debug("Updating activity for txId: $newTxId. isRBF:$isRBF", context = TAG)
270+
Logger.debug("Updating activity for txId: $newTxId. isRBF: $isRBF", context = TAG)
268271

269-
val currentActivity = activity?.v1 ?: return Result.failure(Exception("Activity required"))
272+
val currentActivity = activity?.v1
273+
?: return Result.failure(Exception("Activity required"))
270274

271-
// For CPFP, just update the activity
275+
return if (isRBF) {
276+
handleRBFUpdate(newTxId, currentActivity)
277+
} else {
278+
handleCPFPUpdate(currentActivity)
279+
}
280+
}
281+
282+
/**
283+
* Handles CPFP (Child Pays For Parent) update by simply updating the current activity
284+
*/
285+
private suspend fun handleCPFPUpdate(currentActivity: OnchainActivity): Result<Unit> {
272286
val updatedActivity = Activity.Onchain(
273287
v1 = currentActivity.copy(
274288
isBoosted = true,
275-
feeRate = _uiState.value.feeRate,
276-
fee = _uiState.value.totalFeeSats,
277289
updatedAt = nowTimestamp().toEpochMilli().toULong()
278290
)
279291
)
280292

281-
val updateResult = activityRepo.updateActivity(
293+
return activityRepo.updateActivity(
282294
id = updatedActivity.v1.id,
283295
activity = updatedActivity
284296
)
297+
}
285298

286-
return if (!isRBF) {
287-
updateResult
288-
} else {
289-
// For RBF, update new activity and delete old one
290-
activityRepo.findActivityByPaymentId(
291-
paymentHashOrTxId = newTxId,
292-
type = ActivityFilter.ONCHAIN,
293-
txType = PaymentType.SENT
294-
).fold(
295-
onSuccess = { newActivity ->
296-
Logger.debug("Activity found: $newActivity", context = TAG)
297-
298-
val newOnChainActivity = newActivity as? Activity.Onchain
299-
?: return Result.failure(Exception("Activity is not onchain type"))
300-
301-
val updatedActivity = Activity.Onchain(
302-
v1 = newOnChainActivity.v1.copy(
303-
isBoosted = true,
304-
feeRate = _uiState.value.feeRate,
305-
fee = _uiState.value.totalFeeSats,
306-
updatedAt = nowTimestamp().toEpochMilli().toULong()
307-
)
308-
)
309-
310-
activityRepo.replaceActivity(
311-
id = updatedActivity.v1.id,
312-
activityIdToDelete = activity?.v1?.id.orEmpty(),
313-
activity = updatedActivity,
314-
).onFailure {
315-
activityRepo.addActivityToPendingBoost(
316-
PendingBoostActivity(
317-
txId = newTxId,
318-
feeRate = _uiState.value.feeRate,
319-
fee = _uiState.value.totalFeeSats,
320-
updatedAt = nowTimestamp().toEpochMilli().toULong(),
321-
activityToDelete = activity?.v1?.id
322-
)
323-
)
324-
}
325-
},
326-
onFailure = { error ->
327-
Logger.error(
328-
"Activity $newTxId not found. Caching data to try again on next sync",
329-
e = error,
330-
context = TAG
331-
)
332-
activityRepo.addActivityToPendingBoost(
333-
PendingBoostActivity(
334-
txId = newTxId,
335-
feeRate = _uiState.value.feeRate,
336-
fee = _uiState.value.totalFeeSats,
337-
updatedAt = nowTimestamp().toEpochMilli().toULong(),
338-
activityToDelete = activity?.v1?.id.takeIf { isRBF }
339-
)
340-
)
341-
Result.failure(error)
342-
}
299+
/**
300+
* Handles RBF (Replace By Fee) update by updating current activity and replacing with new one
301+
*/
302+
private suspend fun handleRBFUpdate(
303+
newTxId: Txid,
304+
currentActivity: OnchainActivity,
305+
): Result<Unit> {
306+
// First update the current activity to show boost status
307+
val updatedCurrentActivity = Activity.Onchain(
308+
v1 = currentActivity.copy(
309+
isBoosted = true,
310+
feeRate = _uiState.value.feeRate,
311+
updatedAt = nowTimestamp().toEpochMilli().toULong()
343312
)
313+
)
314+
315+
activityRepo.updateActivity(
316+
id = updatedCurrentActivity.v1.id,
317+
activity = updatedCurrentActivity
318+
)
319+
320+
// Then find and replace with the new activity
321+
return findAndReplaceWithNewActivity(newTxId, currentActivity.id)
322+
}
323+
324+
/**
325+
* Creates a boosted version of the given activity with current fee data
326+
*/
327+
private fun createBoostedActivity(currentActivity: OnchainActivity): Activity.Onchain {
328+
return Activity.Onchain(
329+
v1 = currentActivity.copy(
330+
isBoosted = true,
331+
feeRate = _uiState.value.feeRate,
332+
updatedAt = nowTimestamp().toEpochMilli().toULong()
333+
)
334+
)
335+
}
336+
337+
/**
338+
* Finds the new activity and replaces the old one, handling failures gracefully
339+
*/
340+
private suspend fun findAndReplaceWithNewActivity(
341+
newTxId: Txid,
342+
oldActivityId: String,
343+
): Result<Unit> {
344+
return activityRepo.findActivityByPaymentId(
345+
paymentHashOrTxId = newTxId,
346+
type = ActivityFilter.ONCHAIN,
347+
txType = PaymentType.SENT
348+
).fold(
349+
onSuccess = { newActivity ->
350+
replaceActivityWithNewOne(newActivity, oldActivityId, newTxId)
351+
},
352+
onFailure = { error ->
353+
handleActivityNotFound(error, newTxId, oldActivityId)
354+
}
355+
)
356+
}
357+
358+
/**
359+
* Replaces the old activity with the new boosted one
360+
*/
361+
private suspend fun replaceActivityWithNewOne(
362+
newActivity: Activity,
363+
oldActivityId: String,
364+
newTxId: Txid,
365+
): Result<Unit> {
366+
Logger.debug("Activity found: $newActivity", context = TAG)
367+
368+
val newOnChainActivity = newActivity as? Activity.Onchain
369+
?: return Result.failure(Exception("Activity is not onchain type"))
370+
371+
val updatedNewActivity = Activity.Onchain(
372+
v1 = newOnChainActivity.v1.copy(
373+
isBoosted = true,
374+
feeRate = _uiState.value.feeRate,
375+
updatedAt = nowTimestamp().toEpochMilli().toULong()
376+
)
377+
)
378+
379+
return activityRepo.replaceActivity(
380+
id = updatedNewActivity.v1.id,
381+
activityIdToDelete = oldActivityId,
382+
activity = updatedNewActivity,
383+
).onFailure {
384+
cachePendingBoostActivity(newTxId, oldActivityId)
344385
}
345386
}
346387

388+
/**
389+
* Handles the case when new activity is not found by caching for later retry
390+
*/
391+
private suspend fun handleActivityNotFound(
392+
error: Throwable,
393+
newTxId: Txid,
394+
oldActivityId: String?,
395+
): Result<Unit> {
396+
Logger.error(
397+
"Activity $newTxId not found. Caching data to try again on next sync",
398+
e = error,
399+
context = TAG
400+
)
401+
402+
cachePendingBoostActivity(newTxId, oldActivityId)
403+
return Result.failure(error)
404+
}
405+
406+
/**
407+
* Caches activity data for pending boost operation
408+
*/
409+
private suspend fun cachePendingBoostActivity(newTxId: Txid, activityToDelete: String?) {
410+
activityRepo.addActivityToPendingBoost(
411+
PendingBoostActivity(
412+
txId = newTxId,
413+
updatedAt = nowTimestamp().toEpochMilli().toULong(),
414+
activityToDelete = activityToDelete
415+
)
416+
)
417+
}
418+
347419
private fun handleError(message: String, error: Throwable? = null) {
348420
Logger.error(message, error, context = TAG)
349421
_uiState.update {

0 commit comments

Comments
 (0)