diff --git a/Bitkit/AppScene.swift b/Bitkit/AppScene.swift
index 83df9fe3..add6f520 100644
--- a/Bitkit/AppScene.swift
+++ b/Bitkit/AppScene.swift
@@ -239,7 +239,7 @@ struct AppScene: View {
// Schedule full backup after wallet create/restore to prevent epoch dates in backup status
await BackupService.shared.scheduleFullBackup()
} catch {
- Logger.error("Failed to start wallet")
+ Logger.error(error, context: "Failed to start wallet")
Haptics.notify(.error)
}
}
diff --git a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
index 768f28e5..99397463 100644
Binary files a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ
diff --git a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
index b56481cb..06e11b50 100644
Binary files a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ
diff --git a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
index a60ef332..dcbd8c6f 100644
Binary files a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ
diff --git a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
index b4030353..1759c8a5 100644
Binary files a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ
diff --git a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
index e4035573..00513e61 100644
Binary files a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ
diff --git a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
index ae52a803..4aa0ef92 100644
Binary files a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ
diff --git a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
index b56481cb..06e11b50 100644
Binary files a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ
diff --git a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
index 18caa44a..21dfd9cb 100644
Binary files a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ
diff --git a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
index c927d6b8..79675fa7 100644
Binary files a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ
diff --git a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
index c927d6b8..79675fa7 100644
Binary files a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ
diff --git a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
index 4967bf33..07460a3f 100644
Binary files a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ
diff --git a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
index 7d8062d8..186fb70b 100644
Binary files a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ
diff --git a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
index eb8dbee2..1bb7a143 100644
Binary files a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ
diff --git a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
index 6cd57d24..b34a1240 100644
Binary files a/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/Bitkit/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ
diff --git a/Bitkit/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png b/Bitkit/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png
index 81fb9f14..ad3973e5 100644
Binary files a/Bitkit/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png and b/Bitkit/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png differ
diff --git a/Bitkit/Bitkit.entitlements b/Bitkit/Bitkit.entitlements
index d2a6d546..0898d896 100644
--- a/Bitkit/Bitkit.entitlements
+++ b/Bitkit/Bitkit.entitlements
@@ -17,6 +17,9 @@
keychain-access-groups
$(AppIdentifierPrefix)to.bitkit
+ $(AppIdentifierPrefix)to.bitkit.signet
+ $(AppIdentifierPrefix)to.bitkit.testnet
+ $(AppIdentifierPrefix)to.bitkit.regtest
diff --git a/Bitkit/Constants/Env.swift b/Bitkit/Constants/Env.swift
index b2d3db66..a821ff29 100644
--- a/Bitkit/Constants/Env.swift
+++ b/Bitkit/Constants/Env.swift
@@ -9,56 +9,67 @@ enum Env {
static let isPreview = ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1"
static let isTestFlight = Bundle.main.appStoreReceiptURL?.lastPathComponent == "sandboxReceipt"
static let isUnitTest = ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil
- #if E2E_BUILD
- static let isE2E = true
- #else
- static let isE2E = ProcessInfo.processInfo.environment["E2E"] == "true"
- #endif
- static let dustLimit = 547
- static let msatsPerSat: UInt64 = 1000
- #if CHECK_GEOBLOCK
- static let isGeoblockingEnabled = true
+ #if DEBUG
+ static let isDebug = true
#else
- static let isGeoblockingEnabled = ProcessInfo.processInfo.environment["GEO"] == "true"
+ static let isDebug = false
#endif
+ static var isE2E: Bool {
+ #if E2E_BUILD
+ return true
+ #else
+ return ProcessInfo.processInfo.environment["E2E"] == "true"
+ #endif
+ }
+
+ static var isGeoblockingEnabled: Bool {
+ #if CHECK_GEOBLOCK
+ return true
+ #else
+ return ProcessInfo.processInfo.environment["GEO"] == "true"
+ #endif
+ }
+
/// The current execution context of the app
static var currentExecutionContext: ExecutionContext {
- return Bundle.main.bundleIdentifier?.lowercased().contains("notification") == true ? .pushNotificationExtension : .foregroundApp
+ let isNotificationExtension = Bundle.main.bundleIdentifier?.lowercased().contains("notification") == true
+ return isNotificationExtension ? .pushNotificationExtension : .foregroundApp
}
// {Team ID}.{Keychain Group}
- static let keychainGroup = "KYH47R284B.to.bitkit" // TODO: needs to change for regtest/mainnet so we don't use same group
-
- #if targetEnvironment(simulator)
- static let isSim = true
- #else
- static let isSim = false
- #endif
-
- #if DEBUG
- static let isDebug = true
- #else
- static let isDebug = false
- #endif
+ /// Returns the keychain access group based on the current network
+ static var keychainGroup: String {
+ let base = "KYH47R284B.to.bitkit"
+ let networkSuffix = networkName(network)
+ return networkSuffix == "bitcoin" ? base : "\(base).\(networkSuffix)"
+ }
// MARK: wallet services
- static let network: LDKNode.Network = .regtest
+ static let network: LDKNode.Network = (isE2E || isUnitTest) ? .regtest : .bitcoin
+ static let ldkLogLevel = LDKNode.LogLevel.trace
+
static let walletSyncIntervalSecs: UInt64 = 10 // TODO: play around with this
/// Converts the LDKNode.Network to BitkitCore.Network for use with bitkitcore functions
static var bitkitCoreNetwork: BitkitCore.Network {
switch network {
- case .bitcoin:
- return .bitcoin
- case .testnet:
- return .testnet
- case .signet:
- return .signet
- case .regtest:
- return .regtest
+ case .bitcoin: .bitcoin
+ case .testnet: .testnet
+ case .signet: .signet
+ case .regtest: .regtest
+ }
+ }
+
+ /// Returns the lowercase name of the network (e.g., "bitcoin", "testnet", "signet", "regtest")
+ private static func networkName(_ network: LDKNode.Network) -> String {
+ switch network {
+ case .bitcoin: "bitcoin"
+ case .testnet: "testnet"
+ case .signet: "signet"
+ case .regtest: "regtest"
}
}
@@ -74,27 +85,10 @@ enum Env {
}
switch network {
- case .bitcoin:
- return "ssl://35.187.18.233:8900"
- case .signet:
- fatalError("Signet network not implemented")
- case .testnet:
- return "ssl://electrum.blockstream.info:60002"
- case .regtest:
- return "tcp://34.65.252.32:18483"
- }
- }
-
- static var esploraServerUrl: String {
- switch network {
- case .regtest:
- return "https://bitkit.stag0.blocktank.to/electrs"
- case .bitcoin:
- fatalError("Bitcoin network not implemented")
- case .testnet:
- fatalError("Testnet network not implemented")
- case .signet:
- fatalError("Signet network not implemented")
+ case .bitcoin: return "ssl://fulcrum.bitkit.blocktank.to:8900"
+ case .signet: return "ssl://mempool.space:60602"
+ case .testnet: return "ssl://electrum.blockstream.info:60002"
+ case .regtest: return "ssl://fulcrum.bitkit.stag0.blocktank.to:18484"
}
}
@@ -112,83 +106,50 @@ enum Env {
}
static func ldkStorage(walletIndex: Int) -> URL {
- switch network {
- case .regtest:
- return
- appStorageUrl
- .appendingPathComponent("regtest")
- .appendingPathComponent("wallet\(walletIndex)/ldk")
- case .bitcoin:
- return
- appStorageUrl
- .appendingPathComponent("bitcoin")
- .appendingPathComponent("wallet\(walletIndex)/ldk")
- case .testnet:
- fatalError("Testnet network not implemented")
- case .signet:
- fatalError("Signet network not implemented")
- }
+ appStorageUrl
+ .appendingPathComponent(networkName(network))
+ .appendingPathComponent("wallet\(walletIndex)/ldk")
}
static func bitkitCoreStorage(walletIndex: Int) -> URL {
- switch network {
- case .regtest:
- return
- appStorageUrl
- .appendingPathComponent("regtest")
- .appendingPathComponent("wallet\(walletIndex)/core")
- case .bitcoin:
- return
- appStorageUrl
- .appendingPathComponent("bitcoin")
- .appendingPathComponent("wallet\(walletIndex)/core")
- case .testnet:
- fatalError("Testnet network not implemented")
- case .signet:
- fatalError("Signet network not implemented")
- }
+ appStorageUrl
+ .appendingPathComponent(networkName(network))
+ .appendingPathComponent("wallet\(walletIndex)/core")
}
static var ldkRgsServerUrl: String? {
switch network {
- case .regtest:
- return "https://bitkit.stag0.blocktank.to/rgs/snapshot"
- case .bitcoin:
- return "https://rgs.blocktank.to/snapshot"
- case .testnet:
- return "https://rapidsync.lightningdevkit.org/testnet/snapshot"
- case .signet:
- return nil
+ case .bitcoin: "https://rgs.blocktank.to/snapshot"
+ case .signet: "https://rapidsync.lightningdevkit.org/signet/snapshot"
+ case .testnet: "https://rapidsync.lightningdevkit.org/testnet/snapshot"
+ case .regtest: "https://bitkit.stag0.blocktank.to/rgs/snapshot"
}
}
// TODO: remove this to load from BT API instead
static var trustedLnPeers: [LnPeer] {
switch network {
- case .regtest:
+ case .bitcoin:
return [
- // Staging Blocktank node
- .init(nodeId: "028a8910b0048630d4eb17af25668cdd7ea6f2d8ae20956e7a06e2ae46ebcb69fc", host: "34.65.86.104", port: 9400),
+ .init(nodeId: "039b8b4dd1d88c2c5db374290cda397a8f5d79f312d6ea5d5bfdfc7c6ff363eae3", host: "34.65.111.104", port: 9735),
+ .init(nodeId: "03816141f1dce7782ec32b66a300783b1d436b19777e7c686ed00115bd4b88ff4b", host: "34.65.191.64", port: 9735),
+ .init(nodeId: "02a371038863605300d0b3fc9de0cf5ccb57728b7f8906535709a831b16e311187", host: "34.65.186.40", port: 9735),
]
- case .bitcoin:
+ case .signet:
return []
case .testnet:
return []
- case .signet:
- return []
+ case .regtest:
+ return [
+ .init(nodeId: "028a8910b0048630d4eb17af25668cdd7ea6f2d8ae20956e7a06e2ae46ebcb69fc", host: "34.65.86.104", port: 9400),
+ ]
}
}
static var blocktankBaseUrl: String {
switch network {
- case .regtest:
- return "https://api.stag0.blocktank.to"
- case .bitcoin:
- fatalError("Bitcoin network not implemented")
- case .testnet:
- fatalError("Testnet network not implemented")
- case .signet:
- fatalError("Signet network not implemented")
+ case .bitcoin: "https://api1.blocktank.to/api"
+ default: "https://api.stag0.blocktank.to/"
}
}
@@ -197,11 +158,19 @@ enum Env {
}
static var blocktankClientServer: String {
- "\(blocktankBaseUrl)/blocktank/api/v2"
+ switch network {
+ case .bitcoin: "\(blocktankBaseUrl)"
+ default: "\(blocktankBaseUrl)/blocktank/api/v2"
+ }
}
static var btcRatesServer: String {
- "https://bitkit.stag0.blocktank.to/fx/rates/btc" // TODO: switch to prod when available
+ switch network {
+ case .bitcoin: "https://blocktank.synonym.to/fx/rates/btc"
+ case .signet: "https://bitkit.stag0.blocktank.to/fx/rates/btc"
+ case .testnet: "https://bitkit.stag0.blocktank.to/fx/rates/btc"
+ case .regtest: "https://bitkit.stag0.blocktank.to/fx/rates/btc"
+ }
}
static let fxRateRefreshInterval: TimeInterval = 2 * 60 // 2 minutes
@@ -217,45 +186,39 @@ enum Env {
.wakeToTimeout,
]
+ static var vssStoreIdPrefix: String {
+ "bitkit_v1_\(networkName(network))"
+ }
+
static var vssServerUrl: String {
switch network {
- case .bitcoin:
- fatalError("Bitcoin network not implemented")
- default:
- return "https://bitkit.stag0.blocktank.to/vss_rs_auth"
+ case .bitcoin: "https://bitkit.to/vss_rs_auth"
+ default: "https://bitkit.stag0.blocktank.to/vss_rs_auth"
}
}
- static var vssStoreIdPrefix: String {
+ static var lnurlAuthServerUrl: String {
switch network {
- case .bitcoin:
- fatalError("Bitcoin network not implemented")
- case .regtest:
- return "bitkit_v1_regtest"
- case .testnet:
- return "bitkit_v1_testnet"
- case .signet:
- return "bitkit_v1_signet"
+ case .bitcoin: "https://bitkit.to/lnurl_auth/auth"
+ default: "https://bitkit.stag0.blocktank.to/lnurl_auth/auth"
}
}
- static var lnurlAuthServerUrl: String {
+ static var blockExplorerUrl: String {
switch network {
- case .bitcoin:
- fatalError("LNURL-auth server not implemented for mainnet")
- default:
- return "https://bitkit.stag0.blocktank.to/lnurl_auth/auth"
+ case .bitcoin: "https://mempool.space"
+ case .signet: "https://mutinynet.com"
+ case .testnet: "https://mempool.space/testnet"
+ case .regtest: "https://mempool.bitkit.stag0.blocktank.to"
}
}
static var logDirectory: String {
- return appStorageUrl.appendingPathComponent("logs").path
- }
-
- static var ldkLogLevel: LDKNode.LogLevel {
- return .trace
+ appStorageUrl.appendingPathComponent("logs").path
}
+ static let dustLimit = 547
+ static let msatsPerSat: UInt64 = 1000
static let appStoreUrl = "https://apps.apple.com/app/bitkit-wallet/id6502440655"
static let playStoreUrl = "https://play.google.com/store/apps/details?id=to.bitkit"
static let githubUrl = "https://www.github.com/synonymdev/bitkit"
diff --git a/Bitkit/MainNavView.swift b/Bitkit/MainNavView.swift
index cf522206..5320ecf9 100644
--- a/Bitkit/MainNavView.swift
+++ b/Bitkit/MainNavView.swift
@@ -389,6 +389,7 @@ struct MainNavView: View {
// Dev settings
case .blocktankRegtest: BlocktankRegtestView()
+ case .ldkDebug: LdkDebugScreen()
case .orders: ChannelOrders()
case .logs: LogView()
}
diff --git a/Bitkit/Services/BackupService.swift b/Bitkit/Services/BackupService.swift
index d4949d1f..a229b8ba 100644
--- a/Bitkit/Services/BackupService.swift
+++ b/Bitkit/Services/BackupService.swift
@@ -85,7 +85,6 @@ class BackupService {
guard shouldStart == true else { return }
- try? await vssBackupClient.setup()
Logger.debug("Start observing backup statuses and data store changes", context: "BackupService")
startBackupStatusObservers()
startDataStoreListeners()
@@ -130,8 +129,6 @@ class BackupService {
}
do {
- try await vssBackupClient.setup()
-
let data = try await getBackupDataBytes(category: category)
let _ = try await vssBackupClient.putObject(key: category.rawValue, data: data)
diff --git a/Bitkit/Services/CoreService.swift b/Bitkit/Services/CoreService.swift
index 4c910d51..ce9c627f 100644
--- a/Bitkit/Services/CoreService.swift
+++ b/Bitkit/Services/CoreService.swift
@@ -241,11 +241,6 @@ class ActivityService {
func removeAll() async throws {
try await ServiceQueue.background(.core) {
- // Only allow removing on regtest for now
- guard Env.network == .regtest else {
- throw AppError(message: "Regtest only", debugMessage: nil)
- }
-
// Get all activities and delete them one by one
let activities = try getActivities(
filter: .all, txType: nil, tags: nil, search: nil, minDate: nil, maxDate: nil, limit: nil, sortDirection: nil
diff --git a/Bitkit/Services/LightningService.swift b/Bitkit/Services/LightningService.swift
index ee78eb7d..bf9fdd93 100644
--- a/Bitkit/Services/LightningService.swift
+++ b/Bitkit/Services/LightningService.swift
@@ -41,9 +41,11 @@ class LightningService {
Logger.debug("Using LDK storage path: \(ldkStoragePath)")
- config.trustedPeers0conf = Env.trustedLnPeers.map(\.nodeId)
+ let trustedPeersIds = Env.trustedLnPeers.map(\.nodeId)
+
+ config.trustedPeers0conf = trustedPeersIds
config.anchorChannelsConfig = .init(
- trustedPeersNoReserve: Env.trustedLnPeers.map(\.nodeId),
+ trustedPeersNoReserve: trustedPeersIds,
perChannelReserveSats: 1
)
config.includeUntrustedPendingInSpendable = true
@@ -571,6 +573,27 @@ class LightningService {
}
}
+ func logNetworkGraphInfo() async throws -> String {
+ guard let node else {
+ throw AppError(serviceError: .nodeNotSetup)
+ }
+
+ let nodeStatus = node.status()
+ let networkGraph = node.networkGraph()
+ let allNodes = networkGraph.listNodes()
+ let lastRgsSync = nodeStatus.latestRgsSnapshotTimestamp
+
+ var lastRgsSyncString = "Never"
+ if let lastRgsSync {
+ let dateFormatter = DateFormatter()
+ dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
+ dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
+ lastRgsSyncString = dateFormatter.string(from: Date(timeIntervalSince1970: TimeInterval(lastRgsSync)))
+ }
+
+ return "Nodes: \(allNodes.count), Last Synced: \(lastRgsSyncString)"
+ }
+
// MARK: Logging helpers
private func generateLogFilePath() -> String {
diff --git a/Bitkit/Utilities/AppReset.swift b/Bitkit/Utilities/AppReset.swift
index b4b1d5a2..021122a9 100644
--- a/Bitkit/Utilities/AppReset.swift
+++ b/Bitkit/Utilities/AppReset.swift
@@ -35,7 +35,9 @@ enum AppReset {
}
// Wipe logs
- try wipeLogs()
+ if Env.network == .regtest {
+ try wipeLogs()
+ }
// Recreate the entire app state tree to guarantee clean defaults for all @StateObject VMs.
// Avoid showing splash during when app is reset
diff --git a/Bitkit/ViewModels/NavigationViewModel.swift b/Bitkit/ViewModels/NavigationViewModel.swift
index ff70e4fc..37fdf469 100644
--- a/Bitkit/ViewModels/NavigationViewModel.swift
+++ b/Bitkit/ViewModels/NavigationViewModel.swift
@@ -90,6 +90,7 @@ enum Route: Hashable {
// Dev settings
case blocktankRegtest
+ case ldkDebug
case orders
case logs
}
diff --git a/Bitkit/Views/Settings/DevSettingsView.swift b/Bitkit/Views/Settings/DevSettingsView.swift
index a5859269..d6780b46 100644
--- a/Bitkit/Views/Settings/DevSettingsView.swift
+++ b/Bitkit/Views/Settings/DevSettingsView.swift
@@ -20,6 +20,10 @@ struct DevSettingsView: View {
}
}
+ NavigationLink(value: Route.ldkDebug) {
+ SettingsListLabel(title: "LDK")
+ }
+
NavigationLink(value: Route.orders) {
SettingsListLabel(title: "Orders")
}
@@ -56,23 +60,6 @@ struct DevSettingsView: View {
SettingsListLabel(title: "Show Logs")
}
- Button {
- Task {
- do {
- try await notificationManager.sendTestNotification()
- } catch {
- Logger.error(error, context: "failed to test push notification")
- app.toast(
- type: .error,
- title: "Error",
- description: "Failed to send test notification: \(error)"
- )
- }
- }
- } label: {
- SettingsListLabel(title: "Test Push Notification", rightIcon: nil)
- }
-
Button {
Task {
guard let zipURL = LogService.shared.zipLogs() else {
@@ -98,6 +85,23 @@ struct DevSettingsView: View {
SettingsListLabel(title: "Export Logs", rightIcon: nil)
}
+ Button {
+ Task {
+ do {
+ try await notificationManager.sendTestNotification()
+ } catch {
+ Logger.error(error, context: "failed to test push notification")
+ app.toast(
+ type: .error,
+ title: "Error",
+ description: "Failed to send test notification: \(error)"
+ )
+ }
+ }
+ } label: {
+ SettingsListLabel(title: "Test Push Notification", rightIcon: nil)
+ }
+
Button {
Task {
do {
diff --git a/Bitkit/Views/Settings/LdkDebugScreen.swift b/Bitkit/Views/Settings/LdkDebugScreen.swift
new file mode 100644
index 00000000..c8e144d2
--- /dev/null
+++ b/Bitkit/Views/Settings/LdkDebugScreen.swift
@@ -0,0 +1,114 @@
+import SwiftUI
+
+struct LdkDebugScreen: View {
+ @EnvironmentObject var app: AppViewModel
+ @EnvironmentObject var wallet: WalletViewModel
+
+ @State private var nodeUri: String = ""
+ @State private var showDeleteConfirmation = false
+ @State private var isRestartingNode = false
+
+ var body: some View {
+ VStack(alignment: .leading, spacing: 0) {
+ NavigationBar(title: "LDK Debug")
+ .padding(.bottom, 16)
+
+ ScrollView(showsIndicators: false) {
+ VStack(alignment: .leading, spacing: 32) {
+ // Add Peer
+ VStack(alignment: .leading, spacing: 8) {
+ CaptionMText("Add Peer")
+
+ TextField("039b8d4d...a8f3eae3@127.0.0.1:9735", text: $nodeUri)
+
+ HStack(spacing: 8) {
+ CustomButton(title: "Add Peer", size: .small) {
+ Task {
+ try await addPeer()
+ }
+ }
+ CustomButton(title: "Paste & Add", size: .small) {
+ Task {
+ try await pasteAndAddPeer()
+ }
+ }
+ }
+ }
+
+ // Network Graph Storage
+ VStack(alignment: .leading, spacing: 8) {
+ CaptionMText("Network Graph Storage")
+
+ HStack(spacing: 8) {
+ CustomButton(title: "Log Graph Info", size: .small) {
+ Task {
+ await logNetworkGraphInfo()
+ }
+ }
+ }
+ }
+
+ // Node
+ VStack(alignment: .leading, spacing: 8) {
+ CaptionMText("Node")
+
+ HStack(spacing: 8) {
+ CustomButton(title: "Restart", size: .small, isLoading: isRestartingNode) {
+ Task {
+ await restartNode()
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ .navigationBarHidden(true)
+ .padding(.horizontal, 16)
+ .bottomSafeAreaPadding()
+ }
+
+ func addPeer() async throws {
+ do {
+ let lnPeer = try LnPeer(connection: nodeUri)
+ try await wallet.connectPeer(lnPeer)
+ app.toast(type: .success, title: "Peer added", description: "Peer added successfully")
+ } catch {
+ Logger.error(error, context: "LdkDebugScreen")
+ app.toast(type: .error, title: "Error", description: "Failed to add peer: \(error.localizedDescription)")
+ }
+ }
+
+ func pasteAndAddPeer() async throws {
+ guard let pastedText = UIPasteboard.general.string?.trimmingCharacters(in: .whitespacesAndNewlines) else {
+ app.toast(type: .error, title: "Error", description: "Failed to paste text")
+ return
+ }
+ nodeUri = pastedText
+ try await addPeer()
+ }
+
+ func logNetworkGraphInfo() async {
+ do {
+ let lightningService = LightningService.shared
+ let info = try await lightningService.logNetworkGraphInfo()
+ app.toast(type: .info, title: "Network Graph Info", description: info)
+ } catch {
+ Logger.error("Failed to log network graph info: \(error)")
+ }
+ }
+
+ func restartNode() async {
+ do {
+ isRestartingNode = true
+ let lightningService = LightningService.shared
+ try await lightningService.restart()
+ app.toast(type: .success, title: "Node Restarted", description: "Node restarted successfully")
+ } catch {
+ Logger.error("Failed to restart node: \(error)")
+ app.toast(type: .error, title: "Error", description: "Failed to restart node: \(error.localizedDescription)")
+ }
+
+ isRestartingNode = false
+ }
+}
diff --git a/Bitkit/Views/Wallets/Activity/ActivityExplorerView.swift b/Bitkit/Views/Wallets/Activity/ActivityExplorerView.swift
index ac22ed00..c429ca81 100644
--- a/Bitkit/Views/Wallets/Activity/ActivityExplorerView.swift
+++ b/Bitkit/Views/Wallets/Activity/ActivityExplorerView.swift
@@ -41,12 +41,7 @@ struct ActivityExplorerView: View {
}
private func getBlockExplorerUrl(txId: String) -> URL? {
- let baseUrl =
- switch Env.network {
- case .testnet: "https://mempool.space/testnet"
- case .bitcoin, .regtest, .signet: "https://mempool.space"
- }
- return URL(string: "\(baseUrl)/tx/\(txId)")
+ return URL(string: "\(Env.blockExplorerUrl)/tx/\(txId)")
}
private func loadTransactionDetails() async {
diff --git a/BitkitNotification/BitkitNotification.entitlements b/BitkitNotification/BitkitNotification.entitlements
index a9b567fb..e52eec14 100644
--- a/BitkitNotification/BitkitNotification.entitlements
+++ b/BitkitNotification/BitkitNotification.entitlements
@@ -9,6 +9,9 @@
keychain-access-groups
$(AppIdentifierPrefix)to.bitkit
+ $(AppIdentifierPrefix)to.bitkit.signet
+ $(AppIdentifierPrefix)to.bitkit.testnet
+ $(AppIdentifierPrefix)to.bitkit.regtest