Skip to content

Commit 2a912c8

Browse files
committed
wip: working i think
1 parent 3317d2b commit 2a912c8

File tree

14 files changed

+675
-127
lines changed

14 files changed

+675
-127
lines changed

BDKSwiftExampleWallet.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
AE4984832A1BBBD7009951E2 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AE4984822A1BBBD7009951E2 /* Preview Assets.xcassets */; };
5555
AE49848D2A1BBBD8009951E2 /* BDKSwiftExampleWalletTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE49848C2A1BBBD8009951E2 /* BDKSwiftExampleWalletTests.swift */; };
5656
AE4984A62A1BBCB8009951E2 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = AE4984A52A1BBCB8009951E2 /* README.md */; };
57+
AE4D97572E3AFF2500E88A38 /* CbfClient+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE4D97562E3AFF2500E88A38 /* CbfClient+Extensions.swift */; };
5758
AE6715FA2A9A9220005C193F /* BDKSwiftExampleWalletPriceServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE6715F92A9A9220005C193F /* BDKSwiftExampleWalletPriceServiceTests.swift */; };
5859
AE6715FD2A9AC056005C193F /* PriceServiceError.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE6715FC2A9AC056005C193F /* PriceServiceError.swift */; };
5960
AE6715FF2A9AC066005C193F /* FeeServiceError.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE6715FE2A9AC066005C193F /* FeeServiceError.swift */; };
@@ -163,6 +164,7 @@
163164
AE4984882A1BBBD8009951E2 /* BDKSwiftExampleWalletTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BDKSwiftExampleWalletTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
164165
AE49848C2A1BBBD8009951E2 /* BDKSwiftExampleWalletTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BDKSwiftExampleWalletTests.swift; sourceTree = "<group>"; };
165166
AE4984A52A1BBCB8009951E2 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
167+
AE4D97562E3AFF2500E88A38 /* CbfClient+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CbfClient+Extensions.swift"; sourceTree = "<group>"; };
166168
AE6474732CE559E000A270C6 /* BDKSwiftExampleWallet.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = BDKSwiftExampleWallet.entitlements; sourceTree = "<group>"; };
167169
AE6715F92A9A9220005C193F /* BDKSwiftExampleWalletPriceServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BDKSwiftExampleWalletPriceServiceTests.swift; sourceTree = "<group>"; };
168170
AE6715FC2A9AC056005C193F /* PriceServiceError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceServiceError.swift; sourceTree = "<group>"; };
@@ -572,6 +574,7 @@
572574
isa = PBXGroup;
573575
children = (
574576
77EDA65A2E2A5B3800A5E3AD /* URL+Extensions.swift */,
577+
AE4D97562E3AFF2500E88A38 /* CbfClient+Extensions.swift */,
575578
AE97E74C2E315A8F000A407D /* AddressType+Extensions.swift */,
576579
77F0FDC82DA9A93700B30E4F /* Persister+Extensions.swift */,
577580
AEE6C74B2ABCB3E200442ADD /* Transaction+Extensions.swift */,
@@ -756,6 +759,7 @@
756759
AE73239B2DF9C00F00D9BAE2 /* TxId+Extensions.swift in Sources */,
757760
AE1390C72A7DB0AF0098127A /* KeyService.swift in Sources */,
758761
AED4CC0A2A1D297600CE1831 /* BDKService.swift in Sources */,
762+
AE4D97572E3AFF2500E88A38 /* CbfClient+Extensions.swift in Sources */,
759763
AED4CC102A1D522100CE1831 /* WalletView.swift in Sources */,
760764
AE7F67092A7451AA00CED561 /* Price.swift in Sources */,
761765
AE184EFC2BFE52C800374362 /* Amount+Extensions.swift in Sources */,
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
//
2+
// CbfClient+Extensions.swift
3+
// BDKSwiftExampleWallet
4+
//
5+
// Created by Matthew Ramsden on 7/30/25.
6+
//
7+
8+
import BitcoinDevKit
9+
import Foundation
10+
11+
extension CbfClient {
12+
static func createComponents(wallet: Wallet) -> (client: CbfClient, node: CbfNode) {
13+
do {
14+
let components = try CbfBuilder()
15+
.logLevel(logLevel: .debug)
16+
.scanType(scanType: .sync)
17+
.dataDir(dataDir: Constants.Config.Kyoto.dbPath)
18+
.peers(peers: Constants.Networks.Signet.Regular.kyotoPeers)
19+
.build(wallet: wallet)
20+
Task {
21+
do {
22+
try await components.node.run()
23+
} catch {
24+
// Kyoto: Failed to start node
25+
}
26+
}
27+
28+
components.client.startBackgroundMonitoring()
29+
30+
return (client: components.client, node: components.node)
31+
} catch {
32+
fatalError("Failed to create CBF components: \(error)")
33+
}
34+
}
35+
36+
func startBackgroundMonitoring() {
37+
Task {
38+
var isConnected = false
39+
while true {
40+
if let log = try? await self.nextLog() {
41+
// Parse specific sync stage messages
42+
if log.contains("Attempting to load headers from the database") {
43+
await MainActor.run {
44+
NotificationCenter.default.post(
45+
name: NSNotification.Name("KyotoProgressUpdate"),
46+
object: nil,
47+
userInfo: ["progress": Float(0.2)]
48+
)
49+
}
50+
} else if log.contains("]: headers") {
51+
await MainActor.run {
52+
NotificationCenter.default.post(
53+
name: NSNotification.Name("KyotoProgressUpdate"),
54+
object: nil,
55+
userInfo: ["progress": Float(0.4)]
56+
)
57+
}
58+
} else if log.contains("Chain updated") {
59+
let components = log.components(separatedBy: " ")
60+
if components.count >= 4,
61+
components[0] == "Chain" && components[1] == "updated",
62+
let height = UInt32(components[2])
63+
{
64+
await MainActor.run {
65+
NotificationCenter.default.post(
66+
name: NSNotification.Name("KyotoChainHeightUpdate"),
67+
object: nil,
68+
userInfo: ["height": height]
69+
)
70+
}
71+
}
72+
73+
if !isConnected {
74+
isConnected = true
75+
await MainActor.run {
76+
NotificationCenter.default.post(
77+
name: NSNotification.Name("KyotoConnectionUpdate"),
78+
object: nil,
79+
userInfo: ["connected": true]
80+
)
81+
}
82+
}
83+
}
84+
85+
if log.contains("Established an encrypted connection") && !isConnected {
86+
isConnected = true
87+
await MainActor.run {
88+
NotificationCenter.default.post(
89+
name: NSNotification.Name("KyotoConnectionUpdate"),
90+
object: nil,
91+
userInfo: ["connected": true]
92+
)
93+
}
94+
}
95+
96+
if log.contains("Need connections") && isConnected {
97+
isConnected = false
98+
await MainActor.run {
99+
NotificationCenter.default.post(
100+
name: NSNotification.Name("KyotoConnectionUpdate"),
101+
object: nil,
102+
userInfo: ["connected": false]
103+
)
104+
}
105+
}
106+
}
107+
try? await Task.sleep(nanoseconds: 100_000_000)
108+
}
109+
}
110+
111+
Task {
112+
var hasEstablishedConnection = false
113+
while true {
114+
if let info = try? await self.nextInfo() {
115+
switch info {
116+
case let .progress(progress):
117+
await MainActor.run {
118+
NotificationCenter.default.post(
119+
name: NSNotification.Name("KyotoProgressUpdate"),
120+
object: nil,
121+
userInfo: ["progress": progress]
122+
)
123+
}
124+
case let .newChainHeight(height):
125+
await MainActor.run {
126+
NotificationCenter.default.post(
127+
name: NSNotification.Name("KyotoChainHeightUpdate"),
128+
object: nil,
129+
userInfo: ["height": height]
130+
)
131+
132+
if !hasEstablishedConnection {
133+
hasEstablishedConnection = true
134+
NotificationCenter.default.post(
135+
name: NSNotification.Name("KyotoConnectionUpdate"),
136+
object: nil,
137+
userInfo: ["connected": true]
138+
)
139+
}
140+
}
141+
case .connectionsMet:
142+
await MainActor.run {
143+
hasEstablishedConnection = true
144+
NotificationCenter.default.post(
145+
name: NSNotification.Name("KyotoConnectionUpdate"),
146+
object: nil,
147+
userInfo: ["connected": true]
148+
)
149+
}
150+
default:
151+
break
152+
}
153+
}
154+
}
155+
}
156+
157+
Task {
158+
while true {
159+
if let warning = try? await self.nextWarning() {
160+
switch warning {
161+
case .needConnections:
162+
await MainActor.run {
163+
NotificationCenter.default.post(
164+
name: NSNotification.Name("KyotoConnectionUpdate"),
165+
object: nil,
166+
userInfo: ["connected": false]
167+
)
168+
}
169+
default:
170+
break
171+
}
172+
}
173+
}
174+
}
175+
}
176+
}

BDKSwiftExampleWallet/Resources/Localizable.xcstrings

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,9 @@
467467
}
468468
}
469469
}
470+
},
471+
"Block %u" : {
472+
470473
},
471474
"Build Transaction Error" : {
472475
"localizations" : {
@@ -483,6 +486,9 @@
483486
}
484487
}
485488
}
489+
},
490+
"Client" : {
491+
486492
},
487493
"Coldcard Verify Address" : {
488494

@@ -623,6 +629,9 @@
623629
}
624630
}
625631
}
632+
},
633+
"Esplora" : {
634+
626635
},
627636
"Esplora Server" : {
628637
"localizations" : {
@@ -733,6 +742,9 @@
733742
}
734743
}
735744
}
745+
},
746+
"Kyoto" : {
747+
736748
},
737749
"Navigation Title" : {
738750
"extractionState" : "stale",
@@ -1049,6 +1061,9 @@
10491061
}
10501062
}
10511063
}
1064+
},
1065+
"Select Client Type" : {
1066+
10521067
},
10531068
"Select Fee" : {
10541069
"localizations" : {

0 commit comments

Comments
 (0)