From 6164dfd95842c16fd91e4b3e82328fead8409703 Mon Sep 17 00:00:00 2001 From: infraclaw <283232465+infraclaw-dash@users.noreply.github.com> Date: Mon, 28 Sep 2026 17:27:11 +0300 Subject: [PATCH] fix(swift-example-app): expose locked outpoints in storage explorer --- .../Views/StorageExplorerView.swift | 4 +++ .../Views/StorageModelListViews.swift | 36 +++++++++++++++++++ .../Views/StorageRecordDetailViews.swift | 23 ++++++++++++ 3 files changed, 63 insertions(+) diff --git a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/StorageExplorerView.swift b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/StorageExplorerView.swift index a567917dedf..8c49a18fc62 100644 --- a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/StorageExplorerView.swift +++ b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/StorageExplorerView.swift @@ -142,6 +142,9 @@ struct StorageExplorerView: View { modelRow("TXOs", icon: "bitcoinsign.circle", type: PersistentTxo.self) { TxoStorageListView(network: network) } + modelRow("Locked Outpoints", icon: "lock", type: PersistentLockedOutpoint.self) { + LockedOutpointStorageListView(network: network) + } modelRow("Pending Inputs", icon: "hourglass", type: PersistentPendingInput.self) { PendingInputStorageListView(network: network) } @@ -296,6 +299,7 @@ struct StorageExplorerView: View { directCount(PersistentTokenBalance.self, predicate: #Predicate { $0.networkRaw == raw }) directCount(PersistentPlatformAddressesSyncState.self, predicate: #Predicate { $0.networkRaw == raw }) directCount(PersistentWallet.self, predicate: #Predicate { $0.networkRaw == raw }) + directCount(PersistentLockedOutpoint.self, predicate: #Predicate { $0.networkRaw == raw }) directCount(PersistentWalletManagerMetadata.self, predicate: #Predicate { $0.networkRaw == raw }) // Models that derive their network through a relationship — diff --git a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/StorageModelListViews.swift b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/StorageModelListViews.swift index b4627318cf0..ebe86f7eefd 100644 --- a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/StorageModelListViews.swift +++ b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/StorageModelListViews.swift @@ -1757,6 +1757,42 @@ struct TxoStorageListView: View { } } +// MARK: - PersistentLockedOutpoint + +/// Locks can exist before their TXO or wallet row, so scope them by their +/// own network column rather than requiring either relationship to exist. +struct LockedOutpointStorageListView: View { + let network: Network + @Query private var records: [PersistentLockedOutpoint] + + private var scopedRecords: [PersistentLockedOutpoint] { + records.filter { $0.networkRaw == network.rawValue } + } + + var body: some View { + let visible = scopedRecords + List(visible) { record in + NavigationLink(destination: LockedOutpointStorageDetailView(record: record)) { + VStack(alignment: .leading, spacing: 4) { + Text(record.outpoint.map { String(format: "%02x", $0) }.joined()) + .font(.system(.caption, design: .monospaced)) + .lineLimit(1).truncationMode(.middle) + Text("Wallet: \(record.walletId.map { String(format: "%02x", $0) }.joined())") + .font(.system(.caption2, design: .monospaced)) + .foregroundColor(.secondary) + .lineLimit(1).truncationMode(.middle) + } + } + } + .navigationTitle("Locked Outpoints (\(visible.count))") + .overlay { + if visible.isEmpty { + ContentUnavailableView("No Locked Outpoints", systemImage: "lock") + } + } + } +} + // MARK: - PersistentPendingInput /// Diagnostic list of every `PersistentPendingInput` row — one per diff --git a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/StorageRecordDetailViews.swift b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/StorageRecordDetailViews.swift index 7fe6ed1cd28..8a77b28c023 100644 --- a/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/StorageRecordDetailViews.swift +++ b/packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/StorageRecordDetailViews.swift @@ -2180,6 +2180,29 @@ struct TxoStorageDetailView: View { } } +// MARK: - PersistentLockedOutpoint + +struct LockedOutpointStorageDetailView: View { + let record: PersistentLockedOutpoint + + var body: some View { + Form { + Section("Identity") { + FieldRow(label: "Network", value: Network(rawValue: record.networkRaw)?.displayName ?? "raw \(record.networkRaw)") + FieldRow(label: "Wallet ID", value: hexString(record.walletId)) + FieldRow(label: "Outpoint (wire)", value: hexString(record.outpoint)) + } + Section { + Text("This output is excluded from coin selection, either as masternode collateral or because it was locked manually. The lock can remain even when its transaction output is not stored locally.") + .font(.caption2) + .foregroundColor(.secondary) + } + } + .navigationTitle("Locked Outpoint") + .navigationBarTitleDisplayMode(.inline) + } +} + // MARK: - PersistentPendingInput struct PendingInputStorageDetailView: View {