Skip to content

Commit ba847bf

Browse files
jvsena42claude
andcommitted
Merge branch 'master' into fix/reimport-channel-monitor
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2 parents 0c505d7 + a78283b commit ba847bf

9 files changed

Lines changed: 71 additions & 14 deletions

File tree

.github/workflows/claude-code-review.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: Claude Code Review
22

33
on:
44
pull_request:
5-
types: [opened, synchronize, ready_for_review, reopened]
5+
types: [opened, synchronize, reopened, ready_for_review]
66
# Optional: Only run on specific file changes
77
# paths:
88
# - "src/**/*.ts"

.github/workflows/e2e-tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ on:
88
required: false
99
default: "default-feature-branch"
1010
pull_request:
11+
types: [opened, synchronize, reopened, ready_for_review]
1112

1213
env:
1314
TERM: xterm-256color

.github/workflows/integration-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ on:
55
branches: [master]
66
pull_request:
77
branches: [master]
8-
8+
types: [opened, synchronize, reopened, ready_for_review]
99
workflow_dispatch:
1010

1111
concurrency:

.github/workflows/unit-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ on:
44
push:
55
branches: [master]
66
pull_request:
7-
7+
types: [opened, synchronize, reopened, ready_for_review]
88
workflow_dispatch:
99

1010
concurrency:

.github/workflows/validate-translations.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ on:
55
branches: [master]
66
pull_request:
77
branches: [master]
8+
types: [opened, synchronize, reopened, ready_for_review]
89

910
jobs:
1011
validate:

Bitkit.xcodeproj/project.pbxproj

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@
498498
buildSettings = {
499499
CODE_SIGN_ENTITLEMENTS = BitkitNotification/BitkitNotification.entitlements;
500500
CODE_SIGN_STYLE = Automatic;
501-
CURRENT_PROJECT_VERSION = 178;
501+
CURRENT_PROJECT_VERSION = 180;
502502
DEVELOPMENT_TEAM = KYH47R284B;
503503
GENERATE_INFOPLIST_FILE = YES;
504504
INFOPLIST_FILE = BitkitNotification/Info.plist;
@@ -510,7 +510,7 @@
510510
"@executable_path/Frameworks",
511511
"@executable_path/../../Frameworks",
512512
);
513-
MARKETING_VERSION = 2.0.5;
513+
MARKETING_VERSION = 2.0.6;
514514
PRODUCT_BUNDLE_IDENTIFIER = to.bitkit.notification;
515515
PRODUCT_NAME = "$(TARGET_NAME)";
516516
SDKROOT = iphoneos;
@@ -526,7 +526,7 @@
526526
buildSettings = {
527527
CODE_SIGN_ENTITLEMENTS = BitkitNotification/BitkitNotification.entitlements;
528528
CODE_SIGN_STYLE = Automatic;
529-
CURRENT_PROJECT_VERSION = 178;
529+
CURRENT_PROJECT_VERSION = 180;
530530
DEVELOPMENT_TEAM = KYH47R284B;
531531
GENERATE_INFOPLIST_FILE = YES;
532532
INFOPLIST_FILE = BitkitNotification/Info.plist;
@@ -538,7 +538,7 @@
538538
"@executable_path/Frameworks",
539539
"@executable_path/../../Frameworks",
540540
);
541-
MARKETING_VERSION = 2.0.5;
541+
MARKETING_VERSION = 2.0.6;
542542
PRODUCT_BUNDLE_IDENTIFIER = to.bitkit.notification;
543543
PRODUCT_NAME = "$(TARGET_NAME)";
544544
SDKROOT = iphoneos;
@@ -672,7 +672,7 @@
672672
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
673673
CODE_SIGN_ENTITLEMENTS = Bitkit/Bitkit.entitlements;
674674
CODE_SIGN_STYLE = Automatic;
675-
CURRENT_PROJECT_VERSION = 178;
675+
CURRENT_PROJECT_VERSION = 180;
676676
DEVELOPMENT_ASSET_PATHS = "\"Bitkit/Preview Content\"";
677677
DEVELOPMENT_TEAM = KYH47R284B;
678678
ENABLE_HARDENED_RUNTIME = YES;
@@ -697,7 +697,7 @@
697697
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
698698
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
699699
MACOSX_DEPLOYMENT_TARGET = 14.0;
700-
MARKETING_VERSION = 2.0.5;
700+
MARKETING_VERSION = 2.0.6;
701701
PRODUCT_BUNDLE_IDENTIFIER = to.bitkit;
702702
PRODUCT_NAME = "$(TARGET_NAME)";
703703
SDKROOT = auto;
@@ -715,7 +715,7 @@
715715
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
716716
CODE_SIGN_ENTITLEMENTS = Bitkit/Bitkit.entitlements;
717717
CODE_SIGN_STYLE = Automatic;
718-
CURRENT_PROJECT_VERSION = 178;
718+
CURRENT_PROJECT_VERSION = 180;
719719
DEVELOPMENT_ASSET_PATHS = "\"Bitkit/Preview Content\"";
720720
DEVELOPMENT_TEAM = KYH47R284B;
721721
ENABLE_HARDENED_RUNTIME = YES;
@@ -740,7 +740,7 @@
740740
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
741741
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
742742
MACOSX_DEPLOYMENT_TARGET = 14.0;
743-
MARKETING_VERSION = 2.0.5;
743+
MARKETING_VERSION = 2.0.6;
744744
PRODUCT_BUNDLE_IDENTIFIER = to.bitkit;
745745
PRODUCT_NAME = "$(TARGET_NAME)";
746746
SDKROOT = auto;

Bitkit/Services/MigrationsService.swift

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ class MigrationsService: ObservableObject {
337337
private static let rnPendingBlocktankOrderIdsKey = "rnPendingBlocktankOrderIds"
338338
private static let rnDidAttemptPeerRecoveryKey = "rnDidAttemptMigrationPeerRecovery"
339339
private static let rnChannelRecoveryCheckedKey = "rnChannelRecoveryChecked"
340+
private static let didCleanupInvalidTransfersKey = "didCleanupInvalidMigrationTransfers"
340341

341342
@Published var isShowingMigrationLoading = false {
342343
didSet {
@@ -766,6 +767,47 @@ extension MigrationsService {
766767
return true
767768
}
768769

770+
/// One-time cleanup for transfers created from unpaid/expired Blocktank orders during migration.
771+
/// The RN backup's paidOrders map could contain orders that were never actually paid.
772+
func cleanupInvalidMigrationTransfers() async {
773+
guard !UserDefaults.standard.bool(forKey: Self.didCleanupInvalidTransfersKey) else { return }
774+
guard rnMigrationCompleted else { return }
775+
776+
guard let transfers = try? TransferStorage.shared.getActiveTransfers() else { return }
777+
let orderTransfers = transfers.filter { $0.type.isToSpending() && $0.lspOrderId != nil }
778+
779+
guard !orderTransfers.isEmpty else {
780+
UserDefaults.standard.set(true, forKey: Self.didCleanupInvalidTransfersKey)
781+
return
782+
}
783+
784+
let orderIds = orderTransfers.compactMap(\.lspOrderId)
785+
786+
guard let orders = try? await CoreService.shared.blocktank.orders(orderIds: orderIds, filter: nil, refresh: true) else {
787+
// Don't mark as done if we can't reach Blocktank — retry next launch
788+
Logger.warn("Cannot cleanup migration transfers: Blocktank unreachable", context: "Migration")
789+
return
790+
}
791+
792+
let now = UInt64(Date().timeIntervalSince1970)
793+
for transfer in orderTransfers {
794+
guard let orderId = transfer.lspOrderId,
795+
let order = orders.first(where: { $0.id == orderId })
796+
else { continue }
797+
798+
if order.state2 != .paid {
799+
try? TransferStorage.shared.markSettled(id: transfer.id, settledAt: now)
800+
Logger.info(
801+
"Cleanup: settled invalid migration transfer \(transfer.id) for order \(orderId) (state: \(order.state2))",
802+
context: "Migration"
803+
)
804+
}
805+
}
806+
807+
UserDefaults.standard.set(true, forKey: Self.didCleanupInvalidTransfersKey)
808+
Logger.info("Migration transfer cleanup completed", context: "Migration")
809+
}
810+
769811
/// Clears all persisted pending migration data from UserDefaults
770812
private func clearPendingMigrationData() {
771813
pendingChannelMigration = nil
@@ -2293,14 +2335,16 @@ extension MigrationsService {
22932335
continue
22942336
}
22952337

2296-
if order.state2 == .executed {
2338+
// Only create transfers for orders actually paid and awaiting channel
2339+
guard order.state2 == .paid else {
2340+
Logger.debug("Skipping order \(orderId) with state \(order.state2) for transfer creation", context: "Migration")
22972341
continue
22982342
}
22992343

23002344
let transfer = Transfer(
23012345
id: txId,
23022346
type: .toSpending,
2303-
amountSats: order.clientBalanceSat + order.feeSat,
2347+
amountSats: order.clientBalanceSat,
23042348
channelId: nil,
23052349
fundingTxId: nil,
23062350
lspOrderId: orderId,

Bitkit/Services/TransferService.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,17 @@ class TransferService {
135135
Logger.debug("Channel \(channelId) exists but not yet usable for transfer: \(transfer.id)", context: "TransferService")
136136
}
137137
} else {
138-
// No channel ID resolved - check if we should timeout this transfer
138+
// No channel ID resolved - check if order is expired/terminal
139+
if let orderId = transfer.lspOrderId {
140+
if let orders = try? await blocktankService.orders(orderIds: [orderId], filter: nil, refresh: false),
141+
let order = orders.first,
142+
order.state2 == .expired
143+
{
144+
try await markSettled(id: transfer.id)
145+
Logger.info("Order \(orderId) expired, settled transfer: \(transfer.id)", context: "TransferService")
146+
continue
147+
}
148+
}
139149
Logger.debug(
140150
"Could not resolve channel for transfer: \(transfer.id) orderId: \(transfer.lspOrderId ?? "none")",
141151
context: "TransferService"

Bitkit/ViewModels/WalletViewModel.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,7 @@ class WalletViewModel: ObservableObject {
731731
await lightningService.refreshCache()
732732

733733
do {
734+
await MigrationsService.shared.cleanupInvalidMigrationTransfers()
734735
try? await transferService.syncTransferStates()
735736
let state = try await balanceManager.deriveBalanceState()
736737
balanceInTransferToSavings = Int(state.balanceInTransferToSavings)

0 commit comments

Comments
 (0)