diff --git a/Bitkit.xcodeproj/project.pbxproj b/Bitkit.xcodeproj/project.pbxproj index ac05ca57..cac379d6 100644 --- a/Bitkit.xcodeproj/project.pbxproj +++ b/Bitkit.xcodeproj/project.pbxproj @@ -14,7 +14,6 @@ 961058EA2C35793000E1F1D8 /* LnPeer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9637E6DE2C32ED7B004A92FC /* LnPeer.swift */; }; 961058EB2C35793000E1F1D8 /* WalletNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9637E6DC2C32EAA8004A92FC /* WalletNetwork.swift */; }; 961058EE2C35798C00E1F1D8 /* LDKNode in Frameworks */ = {isa = PBXBuildFile; productRef = 961058ED2C35798C00E1F1D8 /* LDKNode */; }; - 961058F02C35799400E1F1D8 /* BitcoinDevKit in Frameworks */ = {isa = PBXBuildFile; productRef = 961058EF2C35799400E1F1D8 /* BitcoinDevKit */; }; 961301882C50202A00878183 /* MigrationsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 961301872C50202A00878183 /* MigrationsService.swift */; }; 9613018C2C5022D700878183 /* SQLite in Frameworks */ = {isa = PBXBuildFile; productRef = 9613018B2C5022D700878183 /* SQLite */; }; 9613018E2C50288900878183 /* LdkMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9613018D2C50288900878183 /* LdkMigration.swift */; }; @@ -25,7 +24,6 @@ 962B92252C5A4F5D00B21057 /* ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 962B92242C5A4F5D00B21057 /* ViewModel.swift */; }; 9637E6D32C32CE79004A92FC /* Env.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9637E6D22C32CE79004A92FC /* Env.swift */; }; 9637E6D52C32D811004A92FC /* OnChainService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9637E6D42C32D811004A92FC /* OnChainService.swift */; }; - 9637E6D82C32D8A7004A92FC /* BitcoinDevKit in Frameworks */ = {isa = PBXBuildFile; productRef = 9637E6D72C32D8A7004A92FC /* BitcoinDevKit */; }; 9637E6DA2C32E573004A92FC /* OnChainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9637E6D92C32E573004A92FC /* OnChainViewModel.swift */; }; 9637E6DD2C32EAA8004A92FC /* WalletNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9637E6DC2C32EAA8004A92FC /* WalletNetwork.swift */; }; 9637E6DF2C32ED7B004A92FC /* LnPeer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9637E6DE2C32ED7B004A92FC /* LnPeer.swift */; }; @@ -47,6 +45,8 @@ 966DE6722C512C1E00A7B0EF /* seed.bin in Resources */ = {isa = PBXBuildFile; fileRef = 966DE6712C512C1E00A7B0EF /* seed.bin */; }; 966DE6742C512C9300A7B0EF /* HexBytes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 966DE6732C512C9300A7B0EF /* HexBytes.swift */; }; 966DE6752C512FD100A7B0EF /* HexBytes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 966DE6732C512C9300A7B0EF /* HexBytes.swift */; }; + 968A68082C6B6D1F00D4C7CD /* BitcoinDevKit in Frameworks */ = {isa = PBXBuildFile; productRef = 968A68072C6B6D1F00D4C7CD /* BitcoinDevKit */; }; + 968A680F2C6BA5EC00D4C7CD /* BitcoinDevKit in Frameworks */ = {isa = PBXBuildFile; productRef = 968A680E2C6BA5EC00D4C7CD /* BitcoinDevKit */; }; 96B129FD2C2EC05D00DD07B0 /* LDKNode in Frameworks */ = {isa = PBXBuildFile; productRef = 96B129FC2C2EC05D00DD07B0 /* LDKNode */; }; 96B12A002C2EC37B00DD07B0 /* LightningViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96B129FF2C2EC37B00DD07B0 /* LightningViewModel.swift */; }; 96B12A032C2EC65000DD07B0 /* LightningService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96B12A022C2EC65000DD07B0 /* LightningService.swift */; }; @@ -150,7 +150,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 961058F02C35799400E1F1D8 /* BitcoinDevKit in Frameworks */, 961058EE2C35798C00E1F1D8 /* LDKNode in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -159,9 +158,10 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 968A68082C6B6D1F00D4C7CD /* BitcoinDevKit in Frameworks */, 9613018C2C5022D700878183 /* SQLite in Frameworks */, - 9637E6D82C32D8A7004A92FC /* BitcoinDevKit in Frameworks */, 966DE6702C51210000A7B0EF /* LightningDevKit in Frameworks */, + 968A680F2C6BA5EC00D4C7CD /* BitcoinDevKit in Frameworks */, 96B129FD2C2EC05D00DD07B0 /* LDKNode in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -389,7 +389,6 @@ name = BitkitNotification; packageProductDependencies = ( 961058ED2C35798C00E1F1D8 /* LDKNode */, - 961058EF2C35799400E1F1D8 /* BitcoinDevKit */, ); productName = BitkitNotification; productReference = 961058DC2C355B5500E1F1D8 /* BitkitNotification.appex */; @@ -412,9 +411,10 @@ name = Bitkit; packageProductDependencies = ( 96B129FC2C2EC05D00DD07B0 /* LDKNode */, - 9637E6D72C32D8A7004A92FC /* BitcoinDevKit */, 9613018B2C5022D700878183 /* SQLite */, 966DE66F2C51210000A7B0EF /* LightningDevKit */, + 968A68072C6B6D1F00D4C7CD /* BitcoinDevKit */, + 968A680E2C6BA5EC00D4C7CD /* BitcoinDevKit */, ); productName = Bitkit; productReference = 96FE1F612C2DE6AA006D0C8B /* Bitkit.app */; @@ -493,9 +493,9 @@ mainGroup = 96FE1F582C2DE6AA006D0C8B; packageReferences = ( 96B129FB2C2EC05D00DD07B0 /* XCRemoteSwiftPackageReference "ldk-node" */, - 9637E6D62C32D8A7004A92FC /* XCRemoteSwiftPackageReference "bdk-swift" */, 961301892C50215500878183 /* XCRemoteSwiftPackageReference "SQLite.swift" */, 966DE66E2C51210000A7B0EF /* XCRemoteSwiftPackageReference "ldk-swift" */, + 968A680D2C6BA5EC00D4C7CD /* XCRemoteSwiftPackageReference "bdk-swift" */, ); productRefGroup = 96FE1F622C2DE6AA006D0C8B /* Products */; projectDirPath = ""; @@ -1042,20 +1042,20 @@ minimumVersion = 0.15.3; }; }; - 9637E6D62C32D8A7004A92FC /* XCRemoteSwiftPackageReference "bdk-swift" */ = { + 966DE66E2C51210000A7B0EF /* XCRemoteSwiftPackageReference "ldk-swift" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/bitcoindevkit/bdk-swift"; + repositoryURL = "https://github.com/lightningdevkit/ldk-swift/"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 0.31.1; + minimumVersion = 0.0.123; }; }; - 966DE66E2C51210000A7B0EF /* XCRemoteSwiftPackageReference "ldk-swift" */ = { + 968A680D2C6BA5EC00D4C7CD /* XCRemoteSwiftPackageReference "bdk-swift" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/lightningdevkit/ldk-swift/"; + repositoryURL = "https://github.com/bitcoindevkit/bdk-swift"; requirement = { - kind = upToNextMajorVersion; - minimumVersion = 0.0.123; + kind = exactVersion; + version = "1.0.0-alpha.11"; }; }; 96B129FB2C2EC05D00DD07B0 /* XCRemoteSwiftPackageReference "ldk-node" */ = { @@ -1074,26 +1074,25 @@ package = 96B129FB2C2EC05D00DD07B0 /* XCRemoteSwiftPackageReference "ldk-node" */; productName = LDKNode; }; - 961058EF2C35799400E1F1D8 /* BitcoinDevKit */ = { - isa = XCSwiftPackageProductDependency; - package = 9637E6D62C32D8A7004A92FC /* XCRemoteSwiftPackageReference "bdk-swift" */; - productName = BitcoinDevKit; - }; 9613018B2C5022D700878183 /* SQLite */ = { isa = XCSwiftPackageProductDependency; package = 961301892C50215500878183 /* XCRemoteSwiftPackageReference "SQLite.swift" */; productName = SQLite; }; - 9637E6D72C32D8A7004A92FC /* BitcoinDevKit */ = { - isa = XCSwiftPackageProductDependency; - package = 9637E6D62C32D8A7004A92FC /* XCRemoteSwiftPackageReference "bdk-swift" */; - productName = BitcoinDevKit; - }; 966DE66F2C51210000A7B0EF /* LightningDevKit */ = { isa = XCSwiftPackageProductDependency; package = 966DE66E2C51210000A7B0EF /* XCRemoteSwiftPackageReference "ldk-swift" */; productName = LightningDevKit; }; + 968A68072C6B6D1F00D4C7CD /* BitcoinDevKit */ = { + isa = XCSwiftPackageProductDependency; + productName = BitcoinDevKit; + }; + 968A680E2C6BA5EC00D4C7CD /* BitcoinDevKit */ = { + isa = XCSwiftPackageProductDependency; + package = 968A680D2C6BA5EC00D4C7CD /* XCRemoteSwiftPackageReference "bdk-swift" */; + productName = BitcoinDevKit; + }; 96B129FC2C2EC05D00DD07B0 /* LDKNode */ = { isa = XCSwiftPackageProductDependency; package = 96B129FB2C2EC05D00DD07B0 /* XCRemoteSwiftPackageReference "ldk-node" */; diff --git a/Bitkit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Bitkit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 0a255e6b..313aedfe 100644 --- a/Bitkit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Bitkit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,13 +1,13 @@ { - "originHash" : "b03b44bd686d6a1f548992eefdc3c205f03696d1af255697a0c62fecb4ff0cca", + "originHash" : "3f0f9872ecfe9595f1ab9fcef16e75c938d36c73b6b4f98e5c13be4ca1ca1706", "pins" : [ { "identity" : "bdk-swift", "kind" : "remoteSourceControl", "location" : "https://github.com/bitcoindevkit/bdk-swift", "state" : { - "revision" : "f2398109ebd8759322f601d9938779f3cdf99a12", - "version" : "0.31.1" + "revision" : "41392827e12a455685a2af8e6a0ae1d9e3549be5", + "version" : "1.0.0-alpha.11" } }, { diff --git a/Bitkit.xcodeproj/project.xcworkspace/xcuserdata/jason.xcuserdatad/UserInterfaceState.xcuserstate b/Bitkit.xcodeproj/project.xcworkspace/xcuserdata/jason.xcuserdatad/UserInterfaceState.xcuserstate index 34d487fb..f9932d4e 100644 Binary files a/Bitkit.xcodeproj/project.xcworkspace/xcuserdata/jason.xcuserdatad/UserInterfaceState.xcuserstate and b/Bitkit.xcodeproj/project.xcworkspace/xcuserdata/jason.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Bitkit.xcodeproj/xcuserdata/jason.xcuserdatad/xcschemes/xcschememanagement.plist b/Bitkit.xcodeproj/xcuserdata/jason.xcuserdatad/xcschemes/xcschememanagement.plist index fbe57dc5..e7890640 100644 --- a/Bitkit.xcodeproj/xcuserdata/jason.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Bitkit.xcodeproj/xcuserdata/jason.xcuserdatad/xcschemes/xcschememanagement.plist @@ -19,22 +19,43 @@ isShown orderHint - 3 + 4 SQLite (Playground) 2.xcscheme isShown orderHint - 4 + 5 - SQLite (Playground).xcscheme + SQLite (Playground) 3.xcscheme isShown orderHint 2 + SQLite (Playground) 4.xcscheme + + isShown + + orderHint + 6 + + SQLite (Playground) 5.xcscheme + + isShown + + orderHint + 7 + + SQLite (Playground).xcscheme + + isShown + + orderHint + 3 + SuppressBuildableAutocreation diff --git a/Bitkit/Constants/Env.swift b/Bitkit/Constants/Env.swift index e1e7ae57..4d6fdd48 100644 --- a/Bitkit/Constants/Env.swift +++ b/Bitkit/Constants/Env.swift @@ -32,6 +32,7 @@ struct Env { static let network: WalletNetwork = .regtest static let defaultWalletWordCount: WordCount = .words12 static let onchainWalletStopGap = UInt64(20) + static let esploraParallelRequests = UInt64(5) static var esploraServerUrl: String { switch network { case .regtest: @@ -107,7 +108,7 @@ struct Env { switch network { case .regtest: return [ - .init(nodeId: "02b61365f14c5070465e014485fa91cee5a131cf2a4b7cb37309fcd1cc53975238", address: "192.168.0.106:9735") +// .init(nodeId: "02b61365f14c5070465e014485fa91cee5a131cf2a4b7cb37309fcd1cc53975238", address: "192.168.0.106:9735") ] case .bitcoin: return [] diff --git a/Bitkit/Services/LightningService.swift b/Bitkit/Services/LightningService.swift index 3b985056..830d24ed 100644 --- a/Bitkit/Services/LightningService.swift +++ b/Bitkit/Services/LightningService.swift @@ -93,6 +93,7 @@ class LightningService { Logger.debug("Stopping node...") try await ServiceQueue.background(.ldk) { try node.stop() + self.node = nil } Logger.info("Node stopped") } diff --git a/Bitkit/Services/OnChainService.swift b/Bitkit/Services/OnChainService.swift index c5a82173..16e229dd 100644 --- a/Bitkit/Services/OnChainService.swift +++ b/Bitkit/Services/OnChainService.swift @@ -11,17 +11,10 @@ import BitcoinDevKit class OnChainService { private var wallet: Wallet? var currentWalletIndex: Int = 0 + private var hasSynced = false - private var blockchainConfig: BlockchainConfig { - let esploraConfig = EsploraConfig( - baseUrl: Env.esploraServerUrl, - proxy: nil, - concurrency: nil, - stopGap: Env.onchainWalletStopGap, - timeout: nil - ) - - return BlockchainConfig.esplora(config: esploraConfig) + private var esploraClient: EsploraClient { + EsploraClient(url: Env.esploraServerUrl) } static var shared = OnChainService() @@ -53,22 +46,19 @@ class OnChainService { keychain: .internal, network: Env.network.bdkNetwork ) - - //TODO save to keychain - + Logger.debug("Creating onchain wallet...") let bdkStorage = Env.bdkStorage(walletIndex: walletIndex) try FileManager.default.createDirectory(at: bdkStorage, withIntermediateDirectories: true, attributes: nil) - - let dbConfig = DatabaseConfig.sqlite(config: .init(path: bdkStorage.appendingPathComponent("db.sqlite").path)) - + let sqlitePath = bdkStorage.appendingPathComponent("db.sqlite").path + try await ServiceQueue.background(.bdk) { self.wallet = try Wallet( descriptor: descriptor, changeDescriptor: changeDescriptor, - network: Env.network.bdkNetwork, - databaseConfig: dbConfig + persistenceBackendPath: sqlitePath, + network: Env.network.bdkNetwork ) } @@ -107,30 +97,59 @@ class OnChainService { } return try await ServiceQueue.background(.bdk) { - let addressInfo = try wallet.getAddress(addressIndex: .new) + let addressInfo = try wallet.revealNextAddress(keychain: .external) return addressInfo.address.asString() } } - func sync() async throws { + /// Partial sync. Collects all revealed script pubkeys from the wallet keychain. + func syncWithRevealedSpks() async throws { guard let wallet else { throw AppError(serviceError: .onchainWalletNotInitialized) } Logger.debug("Syncing BDK...") + + try await ServiceQueue.background(.bdk) { + let request = wallet.startSyncWithRevealedSpks() + let update = try self.esploraClient.sync(syncRequest: request, parallelRequests: 5) + try wallet.applyUpdate(update: update) + + //TODO: persist wallet?? + } - let blockchain = try Blockchain(config: blockchainConfig) + hasSynced = true + Logger.info("BDK synced") + } + + /// Required on restore or manually from settings. Performs a full scan of the wallet. + func fullScan() async throws { + guard let wallet else { + throw AppError(serviceError: .onchainWalletNotInitialized) + } + + Logger.debug("Full on chain scan...") + try await ServiceQueue.background(.bdk) { - try wallet.sync(blockchain: blockchain, progress: nil) + let request = wallet.startFullScan() + let update = try self.esploraClient.fullScan( + fullScanRequest: request, + stopGap: Env.onchainWalletStopGap, + parallelRequests: Env.esploraParallelRequests + ) + try wallet.applyUpdate(update: update) + //TODO: persist wallet once BDK is updated to beta release } - Logger.info("BDK synced") + hasSynced = true + + Logger.info("Full scan complete") } } //MARK: UI Helpers (Published via OnChainViewModel) extension OnChainService { //TODO catch errors? - var balance: Balance? { try? wallet?.getBalance() } + var balance: Balance? { hasSynced ? wallet?.getBalance() : nil } } diff --git a/Bitkit/Services/ServiceQueue.swift b/Bitkit/Services/ServiceQueue.swift index ee372623..02a3c7fa 100644 --- a/Bitkit/Services/ServiceQueue.swift +++ b/Bitkit/Services/ServiceQueue.swift @@ -32,8 +32,9 @@ class ServiceQueue { } } - static func background(_ service: ServiceTypes, _ blocking: @escaping () throws -> T) async throws -> T { - try await withCheckedThrowingContinuation { continuation in + static func background(_ service: ServiceTypes, _ blocking: @escaping () throws -> T, functionName: String = #function) async throws -> T { + let startTime = CFAbsoluteTimeGetCurrent() + let result = try await withCheckedThrowingContinuation { continuation in service.queue.async { do { let res = try blocking() @@ -45,5 +46,10 @@ class ServiceQueue { } } } + + let timeElapsed = Double(round(100 * (CFAbsoluteTimeGetCurrent() - startTime)) / 100) + Logger.performance("\(functionName) took \(timeElapsed) seconds on \(service) queue") + + return result } } diff --git a/Bitkit/Utilities/Errors.swift b/Bitkit/Utilities/Errors.swift index 92edec0b..e0076150 100644 --- a/Bitkit/Utilities/Errors.swift +++ b/Bitkit/Utilities/Errors.swift @@ -49,11 +49,6 @@ struct AppError: LocalizedError { return } - if let bdkError = error as? BdkError { - self.init(bdkError: bdkError) - return - } - self.init(message: "Error", debugMessage: error.localizedDescription) } @@ -90,15 +85,15 @@ struct AppError: LocalizedError { Logger.error("\(message) [\(debugMessage ?? "")]", context: "service error") } - private init(bdkError: BdkError) { - message = "Bdk error" + private init(bdkError: Error) { + message = "Onchain wallet error" debugMessage = bdkError.localizedDescription //TODO support all message types in switch case -// switch bdkError as BdkError { -// case .Bip32(message: let bdkMessage): -// message = "BIP32 error" -// debugMessage = bdkMessage -// } + //CalculateFeeError + //CannotConnectError + //DescriptorError + //EsploraError + //PersistenceError Logger.error("\(message) [\(debugMessage ?? "")]", context: "BdkError") } diff --git a/Bitkit/Utilities/Logger.swift b/Bitkit/Utilities/Logger.swift index 5b0dd57a..a32647b9 100644 --- a/Bitkit/Utilities/Logger.swift +++ b/Bitkit/Utilities/Logger.swift @@ -31,6 +31,10 @@ class Logger { handle("🧪🧪🧪: \(message)", context: context, file: file, function: function, line: line) } + static func performance(_ message: Any, context: String = "", file: String = #file, function: String = #function, line: Int = #line) { + handle("PERF: \(message)", context: context, file: file, function: function, line: line) + } + private static func handle(_ message: Any, context: String = "", file: String = #file, function: String = #function, line: Int = #line) { let fileName = URL(fileURLWithPath: file).lastPathComponent let line = "\(message) \(context == "" ? "" : "- \(context) ")[\(fileName): \(function) line: \(line)]" diff --git a/Bitkit/Utilities/StartupHandler.swift b/Bitkit/Utilities/StartupHandler.swift index 77b15f40..e084b734 100644 --- a/Bitkit/Utilities/StartupHandler.swift +++ b/Bitkit/Utilities/StartupHandler.swift @@ -37,7 +37,7 @@ class StartupHandler { /// - Returns: The generated mnemonic static func createNewWallet(bip39Passphrase: String?, walletIndex: Int = 0) throws -> String { let mnemonic = Mnemonic(wordCount: Env.defaultWalletWordCount).asString() - + try Keychain.saveString(key: .bip39Mnemonic(index: walletIndex), str: mnemonic) if let bip39Passphrase { try Keychain.saveString(key: .bip39Passphrase(index: walletIndex), str: bip39Passphrase) diff --git a/Bitkit/ViewModels/OnChainViewModel.swift b/Bitkit/ViewModels/OnChainViewModel.swift index 0a817717..c59a0d30 100644 --- a/Bitkit/ViewModels/OnChainViewModel.swift +++ b/Bitkit/ViewModels/OnChainViewModel.swift @@ -41,11 +41,15 @@ class OnChainViewModel: ObservableObject { address = try await OnChainService.shared.getAddress() } - func sync() async throws { + func sync(full: Bool = false) async throws { isSyncing = true syncState() do { - try await OnChainService.shared.sync() + if full { + try await OnChainService.shared.fullScan() + } else { + try await OnChainService.shared.syncWithRevealedSpks() + } isSyncing = false syncState() } catch { diff --git a/Bitkit/Views/Onboarding/WelcomeView.swift b/Bitkit/Views/Onboarding/WelcomeView.swift index c31e437f..e72f6c1e 100644 --- a/Bitkit/Views/Onboarding/WelcomeView.swift +++ b/Bitkit/Views/Onboarding/WelcomeView.swift @@ -7,16 +7,20 @@ import SwiftUI -struct WelcomeView: View { +struct RestoreView: View { @StateObject var viewModel = ViewModel.shared - @State var bip39Passphrase: String? + + @State var bip39Mnemonic = "play toss explain entire until buddy sign promote prepare artist crystal auction" + @State var bip39Passphrase: String? = nil var body: some View { VStack { - Text("Welcome") + Text("Restore Wallet") .font(.largeTitle) - Form { + Form() { + TextField("BIP39 Mnemonic", text: $bip39Mnemonic) + TextField("BIP39 Passphrase", text: Binding( get: { bip39Passphrase ?? "" }, set: { bip39Passphrase = $0.isEmpty ? nil : $0 } @@ -24,6 +28,44 @@ struct WelcomeView: View { } HStack { + Button("Restore Wallet") { + do { + _ = try StartupHandler.restoreWallet(mnemonic: bip39Mnemonic, bip39Passphrase: bip39Passphrase) + //TODO: handle full sync here before revealing the UI so balances are pre populated + viewModel.setWalletExistsState() + } catch { + //TODO: show a error to user + Logger.error(error) + } + } + .padding() + } + .padding() + } + } +} + +struct WelcomeView: View { + @StateObject var viewModel = ViewModel.shared + @State var bip39Passphrase: String? + + @State var showRestore = false + + var body: some View { + VStack { + Text("Welcome") + .font(.largeTitle) + + Form { + Section("Optional passphrase") { + TextField("BIP39 Passphrase", text: Binding( + get: { bip39Passphrase ?? "" }, + set: { bip39Passphrase = $0.isEmpty ? nil : $0 } + )) + } + } + + VStack { Button("Create Wallet") { do { _ = try StartupHandler.createNewWallet(bip39Passphrase: bip39Passphrase) @@ -35,13 +77,16 @@ struct WelcomeView: View { } .padding() -// Button("Restore Wallet") { -// //TODO -// } -// .padding() + Button("Restore Wallet") { + showRestore = true + } + .padding() } .padding() } + .sheet(isPresented: $showRestore) { + RestoreView() + } } } diff --git a/Bitkit/Views/Wallets/HomeView.swift b/Bitkit/Views/Wallets/HomeView.swift index 40cde2a5..a1cb64e5 100644 --- a/Bitkit/Views/Wallets/HomeView.swift +++ b/Bitkit/Views/Wallets/HomeView.swift @@ -37,7 +37,8 @@ struct HomeView: View { } if let onchainBalance = onChainViewModel.balance { - Text("On Chain \(onchainBalance.total)") + Text("On Chain Pending \(onchainBalance.immature.toSat())") + Text("On Chain Total \(onchainBalance.total.toSat())") } } @@ -158,7 +159,7 @@ struct HomeView: View { .refreshable { do { try await withThrowingTaskGroup(of: Void.self) { group in - group.addTask { try await onChainViewModel.sync() } + group.addTask { try await onChainViewModel.sync(full: true) } group.addTask { try await lnViewModel.sync() } try await group.waitForAll() }