@@ -338,6 +338,7 @@ class MigrationsService: ObservableObject {
338338 private static let rnPendingChannelMigrationKey = " rnPendingChannelMigration "
339339 private static let rnPendingBlocktankOrderIdsKey = " rnPendingBlocktankOrderIds "
340340 private static let rnDidAttemptPeerRecoveryKey = " rnDidAttemptMigrationPeerRecovery "
341+ private static let didCleanupInvalidTransfersKey = " didCleanupInvalidMigrationTransfers "
341342
342343 @Published var isShowingMigrationLoading = false {
343344 didSet {
@@ -761,6 +762,47 @@ extension MigrationsService {
761762 return true
762763 }
763764
765+ /// One-time cleanup for transfers created from unpaid/expired Blocktank orders during migration.
766+ /// The RN backup's paidOrders map could contain orders that were never actually paid.
767+ func cleanupInvalidMigrationTransfers( ) async {
768+ guard !UserDefaults. standard. bool ( forKey: Self . didCleanupInvalidTransfersKey) else { return }
769+ guard rnMigrationCompleted else { return }
770+
771+ guard let transfers = try ? TransferStorage . shared. getActiveTransfers ( ) else { return }
772+ let orderTransfers = transfers. filter { $0. type. isToSpending ( ) && $0. lspOrderId != nil }
773+
774+ guard !orderTransfers. isEmpty else {
775+ UserDefaults . standard. set ( true , forKey: Self . didCleanupInvalidTransfersKey)
776+ return
777+ }
778+
779+ let orderIds = orderTransfers. compactMap ( \. lspOrderId)
780+
781+ guard let orders = try ? await CoreService . shared. blocktank. orders ( orderIds: orderIds, filter: nil , refresh: true ) else {
782+ // Don't mark as done if we can't reach Blocktank — retry next launch
783+ Logger . warn ( " Cannot cleanup migration transfers: Blocktank unreachable " , context: " Migration " )
784+ return
785+ }
786+
787+ let now = UInt64 ( Date ( ) . timeIntervalSince1970)
788+ for transfer in orderTransfers {
789+ guard let orderId = transfer. lspOrderId,
790+ let order = orders. first ( where: { $0. id == orderId } )
791+ else { continue }
792+
793+ if order. state2 != . paid {
794+ try ? TransferStorage . shared. markSettled ( id: transfer. id, settledAt: now)
795+ Logger . info (
796+ " Cleanup: settled invalid migration transfer \( transfer. id) for order \( orderId) (state: \( order. state2) ) " ,
797+ context: " Migration "
798+ )
799+ }
800+ }
801+
802+ UserDefaults . standard. set ( true , forKey: Self . didCleanupInvalidTransfersKey)
803+ Logger . info ( " Migration transfer cleanup completed " , context: " Migration " )
804+ }
805+
764806 /// Clears all persisted pending migration data from UserDefaults
765807 private func clearPendingMigrationData( ) {
766808 pendingChannelMigration = nil
@@ -2372,14 +2414,16 @@ extension MigrationsService {
23722414 continue
23732415 }
23742416
2375- if order. state2 == . executed {
2417+ // Only create transfers for orders actually paid and awaiting channel
2418+ guard order. state2 == . paid else {
2419+ Logger . debug ( " Skipping order \( orderId) with state \( order. state2) for transfer creation " , context: " Migration " )
23762420 continue
23772421 }
23782422
23792423 let transfer = Transfer (
23802424 id: txId,
23812425 type: . toSpending,
2382- amountSats: order. clientBalanceSat + order . feeSat ,
2426+ amountSats: order. clientBalanceSat,
23832427 channelId: nil ,
23842428 fundingTxId: nil ,
23852429 lspOrderId: orderId,
0 commit comments