Skip to content

Commit 67a70a9

Browse files
committed
do xpubs too
1 parent 3a91a13 commit 67a70a9

File tree

3 files changed

+69
-17
lines changed

3 files changed

+69
-17
lines changed

BDKSwiftExampleWallet/Service/BDK Service/BDKService.swift

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,52 @@ private class BDKService {
195195
self.wallet = wallet
196196
}
197197

198+
func createWallet(xpub: String?) throws {
199+
let documentsDirectoryURL = URL.documentsDirectory
200+
let walletDataDirectoryURL = documentsDirectoryURL.appendingPathComponent("wallet_data")
201+
202+
if FileManager.default.fileExists(atPath: walletDataDirectoryURL.path) {
203+
try FileManager.default.removeItem(at: walletDataDirectoryURL)
204+
} else {
205+
}
206+
207+
let baseUrl =
208+
try keyClient.getEsploraURL() ?? Constants.Config.EsploraServerURLNetwork.Signet.mutiny
209+
210+
guard let xpubString = xpub, !xpubString.isEmpty else {
211+
throw WalletError.walletNotFound
212+
}
213+
214+
let descriptorString = "tr(\(xpubString)/0/*)"
215+
let changeDescriptorString = "tr(\(xpubString)/1/*)"
216+
let descriptor = try Descriptor(descriptor: descriptorString, network: network)
217+
let changeDescriptor = try Descriptor(descriptor: changeDescriptorString, network: network)
218+
219+
let backupInfo = BackupInfo(
220+
mnemonic: "",
221+
descriptor: descriptor.toStringWithSecret(),
222+
changeDescriptor: changeDescriptor.toStringWithSecret()
223+
)
224+
225+
try keyClient.saveBackupInfo(backupInfo)
226+
try keyClient.saveNetwork(self.network.description)
227+
try keyClient.saveEsploraURL(baseUrl)
228+
229+
try FileManager.default.ensureDirectoryExists(at: walletDataDirectoryURL)
230+
try FileManager.default.removeOldFlatFileIfNeeded(at: documentsDirectoryURL)
231+
let persistenceBackendPath = walletDataDirectoryURL.appendingPathComponent("wallet.sqlite")
232+
.path
233+
let connection = try Connection(path: persistenceBackendPath)
234+
self.connection = connection
235+
let wallet = try Wallet(
236+
descriptor: descriptor,
237+
changeDescriptor: changeDescriptor,
238+
network: network,
239+
connection: connection
240+
)
241+
self.wallet = wallet
242+
}
243+
198244
private func loadWallet(descriptor: Descriptor, changeDescriptor: Descriptor) throws {
199245
let documentsDirectoryURL = URL.documentsDirectory
200246
let walletDataDirectoryURL = documentsDirectoryURL.appendingPathComponent("wallet_data")
@@ -362,6 +408,7 @@ struct BDKClient {
362408
let deleteWallet: () throws -> Void
363409
let createWalletFromSeed: (String?) throws -> Void
364410
let createWalletFromDescriptor: (String?) throws -> Void
411+
let createWalletFromXPub: (String?) throws -> Void
365412
let getBalance: () throws -> Balance
366413
let transactions: () throws -> [CanonicalTx]
367414
let listUnspent: () throws -> [LocalOutput]
@@ -390,6 +437,9 @@ extension BDKClient {
390437
createWalletFromDescriptor: { descriptor in
391438
try BDKService.shared.createWallet(descriptor: descriptor)
392439
},
440+
createWalletFromXPub: { xpub in
441+
try BDKService.shared.createWallet(xpub: xpub)
442+
},
393443
getBalance: { try BDKService.shared.getBalance() },
394444
transactions: { try BDKService.shared.transactions() },
395445
listUnspent: { try BDKService.shared.listUnspent() },
@@ -440,6 +490,7 @@ extension BDKClient {
440490
deleteWallet: {},
441491
createWalletFromSeed: { _ in },
442492
createWalletFromDescriptor: { _ in },
493+
createWalletFromXPub: { _ in },
443494
getBalance: { .mock },
444495
transactions: {
445496
return [

BDKSwiftExampleWallet/View Model/OnboardingViewModel.swift

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@ import SwiftUI
1515
class OnboardingViewModel: ObservableObject {
1616
let bdkClient: BDKClient
1717

18+
@AppStorage("isOnboarding") var isOnboarding: Bool?
19+
@Published var createWithPersistError: CreateWithPersistError?
1820
var isDescriptor: Bool {
1921
words.hasPrefix("tr(") || words.hasPrefix("wpkh(") || words.hasPrefix("wsh(")
2022
|| words.hasPrefix("sh(")
2123
}
22-
23-
@AppStorage("isOnboarding") var isOnboarding: Bool?
24-
@Published var createWithPersistError: CreateWithPersistError?
24+
var isXPub: Bool {
25+
words.hasPrefix("xpub") || words.hasPrefix("tpub")
26+
}
2527
@Published var networkColor = Color.gray
2628
@Published var onboardingViewError: AppError?
2729
@Published var selectedNetwork: Network = .signet {
@@ -36,12 +38,14 @@ class OnboardingViewModel: ObservableObject {
3638
bdkClient.updateEsploraURL(selectedURL)
3739
}
3840
}
39-
@Published var words: String = "" {
40-
didSet {
41-
updateWordArray()
41+
@Published var words: String = ""
42+
var wordArray: [String] {
43+
if words.hasPrefix("xpub") || words.hasPrefix("tpub") {
44+
return []
4245
}
46+
let trimmedWords = words.trimmingCharacters(in: .whitespacesAndNewlines)
47+
return trimmedWords.components(separatedBy: " ")
4348
}
44-
@Published var wordArray: [String] = []
4549
var availableURLs: [String] {
4650
switch selectedNetwork {
4751
case .bitcoin:
@@ -79,6 +83,8 @@ class OnboardingViewModel: ObservableObject {
7983
do {
8084
if isDescriptor {
8185
try bdkClient.createWalletFromDescriptor(words)
86+
} else if isXPub {
87+
try bdkClient.createWalletFromXPub(words)
8288
} else {
8389
try bdkClient.createWalletFromSeed(words)
8490
}
@@ -95,9 +101,4 @@ class OnboardingViewModel: ObservableObject {
95101
}
96102
}
97103
}
98-
99-
private func updateWordArray() {
100-
let trimmedWords = words.trimmingCharacters(in: .whitespacesAndNewlines)
101-
wordArray = trimmedWords.split(separator: " ").map { String($0) }
102-
}
103104
}

BDKSwiftExampleWallet/View/OnboardingView.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ struct OnboardingView: View {
2727
HStack {
2828
Spacer()
2929
Button {
30-
if viewModel.wordArray.isEmpty {
30+
if viewModel.words.isEmpty {
3131
if let clipboardContent = UIPasteboard.general.string {
3232
viewModel.words = clipboardContent
3333
}
@@ -36,13 +36,13 @@ struct OnboardingView: View {
3636
}
3737
} label: {
3838
Image(
39-
systemName: viewModel.wordArray.isEmpty
39+
systemName: viewModel.words.isEmpty
4040
? "arrow.down.square" : "clear"
4141
)
4242
.contentTransition(.symbolEffect(.replace))
4343
}
4444
.tint(
45-
viewModel.wordArray.isEmpty ? .secondary : .primary
45+
viewModel.words.isEmpty ? .secondary : .primary
4646
)
4747
.font(.title)
4848
.padding()
@@ -108,8 +108,8 @@ struct OnboardingView: View {
108108
.pickerStyle(.automatic)
109109
.tint(.primary)
110110

111-
if viewModel.wordArray != [] {
112-
if viewModel.isDescriptor {
111+
if !viewModel.words.isEmpty {
112+
if viewModel.isDescriptor || viewModel.isXPub {
113113
Text(viewModel.words)
114114
.font(.system(.caption, design: .monospaced))
115115
.lineLimit(1)

0 commit comments

Comments
 (0)