Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -266,14 +266,14 @@ class SPVClient: @unchecked Sendable {
func destroy() {
dash_spv_ffi_client_destroy(client)
dash_spv_ffi_config_destroy(config)

client = nil
config = nil
}

// MARK: - Synchronization

func startSync() async throws {
func startSync() throws {
let result = dash_spv_ffi_client_run(
client
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ func print(_ items: Any..., separator: String = " ", terminator: String = "\n")
Swift.print(output, terminator: terminator)
}

// DESIGN NOTE: This class feels like something that should be in the example app,
// DESIGN NOTE: This class feels like something that should be in the example app,
// we, as sdk developers, provide the tools and ffi wrappers, but how to
// use them depends on the sdk user, for example, by implementing the SPV event
// use them depends on the sdk user, for example, by implementing the SPV event
// handlers, the user can decide what to do with the events, but if we implement them in the sdk
// we are taking that decision for them, and maybe not all users want the same thing
@MainActor
Expand All @@ -96,26 +96,21 @@ public class WalletService: ObservableObject {
@Published public var masternodesEnabled = true
@Published public var lastSyncError: Error?
@Published var network: AppNetwork

// Internal properties
private var modelContainer: ModelContainer

// SPV Client and Wallet wrappers
private var spvClient: SPVClient
public private(set) var walletManager: CoreWalletManager

public init(modelContainer: ModelContainer, network: AppNetwork) {
self.modelContainer = modelContainer
self.network = network

LoggingPreferences.configure()

let dataDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("SPV").appendingPathComponent(network.rawValue).path

// Ensure the data directory exists before initializing the SPV client
if let dataDir = dataDir {
try? FileManager.default.createDirectory(atPath: dataDir, withIntermediateDirectories: true)
}
let dataDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("SPV").appendingPathComponent(network.rawValue).path

// For simplicity, lets unwrap the error. This can only fail due to
// IO errors when working with the internal storage system, I don't
Expand All @@ -125,33 +120,28 @@ public class WalletService: ObservableObject {
dataDir: dataDir,
startHeight: 0,
)

self.spvClient = spvClient

// Create the SDK wallet manager by reusing the SPV client's shared manager
// TODO: Investigate this error
self.walletManager = try! CoreWalletManager(spvClient: spvClient, modelContainer: modelContainer)

spvClient.setProgressUpdateEventHandler(SPVProgressUpdateEventHandlerImpl(walletService: self))
spvClient.setSyncEventsHandler(SPVSyncEventsHandlerImpl(walletService: self))
spvClient.setNetworkEventsHandler(SPVNetworkEventsHandlerImpl(walletService: self))
spvClient.setWalletEventsHandler(SPVWalletEventsHandlerImpl(walletService: self))
}

deinit {
spvClient.stopSync()
spvClient.destroy()
}

private func initializeNewSPVClient() {
SDKLogger.log("Initializing SPV Client for \(self.self.network.rawValue)...", minimumLevel: .medium)

let dataDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("SPV").appendingPathComponent(self.network.rawValue).path

// Ensure the data directory exists before initializing the SPV client
if let dataDir = dataDir {
try? FileManager.default.createDirectory(atPath: dataDir, withIntermediateDirectories: true)
}
let dataDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("SPV").appendingPathComponent(self.network.rawValue).path

// This ensures no memory leaks when creating a new client
// and unlocks the storage in case we are about to use the same (we probably are)
Expand All @@ -165,23 +155,23 @@ public class WalletService: ObservableObject {
dataDir: dataDir,
startHeight: 0,
)

self.spvClient.setProgressUpdateEventHandler(SPVProgressUpdateEventHandlerImpl(walletService: self))
self.spvClient.setSyncEventsHandler(SPVSyncEventsHandlerImpl(walletService: self))
self.spvClient.setNetworkEventsHandler(SPVNetworkEventsHandlerImpl(walletService: self))
self.spvClient.setWalletEventsHandler(SPVWalletEventsHandlerImpl(walletService: self))

try! self.spvClient.setMasternodeSyncEnabled(self.masternodesEnabled)

SDKLogger.log("✅ SPV Client initialized successfully for \(self.network.rawValue) (deferred start)", minimumLevel: .medium)

// Create the SDK wallet manager by reusing the SPV client's shared manager
// TODO: Investigate this error
self.walletManager = try! CoreWalletManager(spvClient: self.spvClient, modelContainer: self.modelContainer)

SDKLogger.log("✅ WalletManager wrapper initialized successfully", minimumLevel: .medium)
}

// MARK: - Trusted Mode / Masternode Sync
public func setMasternodesEnabled(_ enabled: Bool) {
masternodesEnabled = enabled
Expand All @@ -198,11 +188,11 @@ public class WalletService: ObservableObject {

// MARK: - Sync Management

public func startSync() async {
public func startSync() {
lastSyncError = nil

do {
try await spvClient.startSync()
try spvClient.startSync()
} catch {
self.lastSyncError = error
print("❌ Sync failed: \(error)")
Expand All @@ -213,7 +203,7 @@ public class WalletService: ObservableObject {
// pausing and resuming is not supported so, the trick is the following,
// stop the old client and create a new one in its initial state xd
spvClient.stopSync()

self.initializeNewSPVClient()
}

Expand Down Expand Up @@ -246,17 +236,17 @@ public class WalletService: ObservableObject {

public func switchNetwork(to network: AppNetwork) async {
guard network != self.network else { return }

print("=== WalletService.switchNetwork START ===")
print("Switching from \(self.network.rawValue) to \(network.rawValue)")

self.network = network

self.stopSync()

print("=== WalletService.switchNetwork END ===")
}

// MARK: - SPV Event Handlers implementations

internal final class SPVProgressUpdateEventHandlerImpl: SPVProgressUpdateEventHandler, Sendable {
Expand Down Expand Up @@ -339,7 +329,7 @@ public class WalletService: ObservableObject {
_ amount: Int64,
_ addresses: [String]
) {}

func onBalanceUpdated(
_ walletId: String,
_ spendable: UInt64,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,9 +325,7 @@ var body: some View {
}

private func startSync() {
Task {
await walletService.startSync()
}
walletService.startSync()
}

private func pauseSync() {
Expand Down
Loading