From b9e18df88efe40c29191f269643ca0ab8f868604 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Fri, 27 Feb 2026 14:01:42 -0300 Subject: [PATCH 1/3] fix: settle expired orders --- .../main/java/to/bitkit/repositories/TransferRepo.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/src/main/java/to/bitkit/repositories/TransferRepo.kt b/app/src/main/java/to/bitkit/repositories/TransferRepo.kt index 48a64f400..aff48fec8 100644 --- a/app/src/main/java/to/bitkit/repositories/TransferRepo.kt +++ b/app/src/main/java/to/bitkit/repositories/TransferRepo.kt @@ -2,6 +2,7 @@ package to.bitkit.repositories import com.synonym.bitkitcore.Activity import com.synonym.bitkitcore.ActivityFilter +import com.synonym.bitkitcore.BtOrderState2 import com.synonym.bitkitcore.SortDirection import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow @@ -111,6 +112,15 @@ class TransferRepo @Inject constructor( if (channel != null && channel.isChannelReady) { markSettled(transfer.id) Logger.debug("Channel $channelId ready, settled transfer: ${transfer.id}", context = TAG) + } else if (channelId == null && transfer.lspOrderId != null) { + val order = blocktankRepo.getOrder(transfer.lspOrderId, refresh = false).getOrNull() + if (order?.state2 == BtOrderState2.EXPIRED) { + markSettled(transfer.id) + Logger.info( + "Order ${transfer.lspOrderId} expired, settled transfer: ${transfer.id}", + context = TAG, + ) + } } } From 432a4089cea62e4b37b8fe4295cf49884527e0ef Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Fri, 27 Feb 2026 14:04:06 -0300 Subject: [PATCH 2/3] fix: only import paid orders in migration and cleanup invalid transfers --- .../to/bitkit/services/MigrationService.kt | 50 +++++++++++++++++-- .../java/to/bitkit/viewmodels/AppViewModel.kt | 3 ++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/to/bitkit/services/MigrationService.kt b/app/src/main/java/to/bitkit/services/MigrationService.kt index 13186d23f..ea8b54173 100644 --- a/app/src/main/java/to/bitkit/services/MigrationService.kt +++ b/app/src/main/java/to/bitkit/services/MigrationService.kt @@ -8,6 +8,7 @@ import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.preferencesDataStore import com.synonym.bitkitcore.Activity import com.synonym.bitkitcore.ActivityTags +import com.synonym.bitkitcore.BtOrderState2 import com.synonym.bitkitcore.ClosedChannelDetails import com.synonym.bitkitcore.LightningActivity import com.synonym.bitkitcore.OnchainActivity @@ -53,7 +54,6 @@ import to.bitkit.models.TransactionSpeed import to.bitkit.models.TransferType import to.bitkit.models.WidgetType import to.bitkit.models.WidgetWithPosition -import to.bitkit.models.safe import to.bitkit.models.widget.BlocksPreferences import to.bitkit.models.widget.FactsPreferences import to.bitkit.models.widget.HeadlinePreferences @@ -94,6 +94,7 @@ class MigrationService @Inject constructor( private const val RN_PENDING_BOOSTS_KEY = "rnPendingBoosts" private const val RN_CHANNEL_RECOVERY_CHECKED_KEY = "rnChannelRecoveryChecked" private const val RN_DID_ATTEMPT_PEER_RECOVERY_KEY = "rnDidAttemptMigrationPeerRecovery" + private const val RN_DID_CLEANUP_INVALID_TRANSFERS_KEY = "didCleanupInvalidMigrationTransfers" private const val OPENING_CURLY_BRACE = "{" private const val MMKV_ROOT = "persist:root" private const val RN_WALLET_NAME = "wallet0" @@ -1303,6 +1304,43 @@ class MigrationService @Inject constructor( }.getOrDefault(emptyList()) } + suspend fun cleanupInvalidMigrationTransfers() { + val key = stringPreferencesKey(RN_DID_CLEANUP_INVALID_TRANSFERS_KEY) + if (rnMigrationStore.data.first()[key] == "true") return + if (!isRnMigrationCompleted()) return + + val transfers = transferDao.getActiveTransfers().first() + .filter { it.type == TransferType.TO_SPENDING && it.lspOrderId != null } + + if (transfers.isEmpty()) { + rnMigrationStore.edit { it[key] = "true" } + return + } + + val orderIds = transfers.mapNotNull { it.lspOrderId } + val orders = runCatching { + coreService.blocktank.orders(orderIds = orderIds, filter = null, refresh = true) + }.onFailure { + Logger.warn("Cannot cleanup migration transfers: Blocktank unreachable", it, context = TAG) + }.getOrNull() ?: return + + val now = System.currentTimeMillis() / MS_PER_SEC + for (transfer in transfers) { + val order = orders.find { it.id == transfer.lspOrderId } ?: continue + if (order.state2 != BtOrderState2.PAID) { + transferDao.markSettled(transfer.id, now) + Logger.info( + "Cleanup: settled invalid migration transfer ${transfer.id} " + + "for order ${transfer.lspOrderId} (state: ${order.state2})", + context = TAG, + ) + } + } + + rnMigrationStore.edit { it[key] = "true" } + Logger.info("Migration transfer cleanup completed", context = TAG) + } + suspend fun cleanupAfterMigration() { clearPersistedMigrationData() setNeedsPostMigrationSync(false) @@ -1517,11 +1555,17 @@ class MigrationService @Inject constructor( null } - order.state2 == com.synonym.bitkitcore.BtOrderState2.EXECUTED -> null + order.state2 != BtOrderState2.PAID -> { + Logger.debug( + "Skipping order $orderId with state ${order.state2} for transfer creation", + context = TAG, + ) + null + } else -> TransferEntity( id = txId, type = TransferType.TO_SPENDING, - amountSats = (order.clientBalanceSat.safe() + order.feeSat.safe()).toLong(), + amountSats = order.clientBalanceSat.toLong(), channelId = null, fundingTxId = null, lspOrderId = orderId, diff --git a/app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt b/app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt index 00ece95a3..353a2cb07 100644 --- a/app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt +++ b/app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt @@ -355,6 +355,7 @@ class AppViewModel @Inject constructor( private suspend fun handleBalanceChanged() { walletRepo.syncBalances() + migrationService.cleanupInvalidMigrationTransfers() transferRepo.syncTransferStates() } @@ -503,6 +504,7 @@ class AppViewModel @Inject constructor( lightningRepo.getPayments().onSuccess { payments -> activityRepo.syncLdkNodePayments(payments) } + migrationService.cleanupInvalidMigrationTransfers() transferRepo.syncTransferStates() migrationService.reapplyMetadataAfterSync() @@ -523,6 +525,7 @@ class AppViewModel @Inject constructor( lightningRepo.getPayments().onSuccess { payments -> activityRepo.syncLdkNodePayments(payments) } + migrationService.cleanupInvalidMigrationTransfers() transferRepo.syncTransferStates() migrationService.reapplyMetadataAfterSync() From de7dedf909fa10346624a9fddabb62bf1b700a95 Mon Sep 17 00:00:00 2001 From: jvsena42 Date: Fri, 27 Feb 2026 14:10:13 -0300 Subject: [PATCH 3/3] refactor: move one-time check to node start flow --- app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt | 3 --- app/src/main/java/to/bitkit/viewmodels/WalletViewModel.kt | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt b/app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt index 353a2cb07..00ece95a3 100644 --- a/app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt +++ b/app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt @@ -355,7 +355,6 @@ class AppViewModel @Inject constructor( private suspend fun handleBalanceChanged() { walletRepo.syncBalances() - migrationService.cleanupInvalidMigrationTransfers() transferRepo.syncTransferStates() } @@ -504,7 +503,6 @@ class AppViewModel @Inject constructor( lightningRepo.getPayments().onSuccess { payments -> activityRepo.syncLdkNodePayments(payments) } - migrationService.cleanupInvalidMigrationTransfers() transferRepo.syncTransferStates() migrationService.reapplyMetadataAfterSync() @@ -525,7 +523,6 @@ class AppViewModel @Inject constructor( lightningRepo.getPayments().onSuccess { payments -> activityRepo.syncLdkNodePayments(payments) } - migrationService.cleanupInvalidMigrationTransfers() transferRepo.syncTransferStates() migrationService.reapplyMetadataAfterSync() diff --git a/app/src/main/java/to/bitkit/viewmodels/WalletViewModel.kt b/app/src/main/java/to/bitkit/viewmodels/WalletViewModel.kt index ba72b96e9..46b8307f1 100644 --- a/app/src/main/java/to/bitkit/viewmodels/WalletViewModel.kt +++ b/app/src/main/java/to/bitkit/viewmodels/WalletViewModel.kt @@ -294,6 +294,7 @@ class WalletViewModel @Inject constructor( } walletRepo.setWalletExistsState() connectMigrationPeers() + migrationService.cleanupInvalidMigrationTransfers() walletRepo.syncBalances() if (_restoreState.value.isIdle()) { walletRepo.refreshBip21()