Swiftpack.co - bdgwallet/bdkmanager-swift as Swift Package

Swiftpack.co is a collection of thousands of indexed Swift packages. Search packages.
See all packages published by bdgwallet.
bdgwallet/bdkmanager-swift 0.0.21
BDKManager for iOS / Swift
⭐️ 1
🕓 1 week ago
iOS macOS
.package(url: "https://github.com/bdgwallet/bdkmanager-swift.git", from: "0.0.21")

BDK Manager for iOS / Swift

This package makes it easier to work with bdk-swift on iOS by providing good defaults, simple setup and modern SwiftUI compatible convenience functions and variables.

It is still a work in progress and not ready for production.

Installation

Add this github repository https://github.com/bdgwallet/bdkmanager-swift as a dependency in your Xcode project.
You can then import and use the BDKManager library in your Swift code.

import BDKManager

Setup

To initalise a BDKManager you need to tell it what bitcoin Network it should use, what SyncSource the wallet is going to connect to for blockchain data, and where the Database should store information. The two supported sync source types by BDK on iOS at the moment is Esplora and Electrum API servers. You can specify a custom URL to a private server, or if none is supplied it will default to the public Blockstream APIs.

let network = Network.testnet // .bitcoin, .testnet, .signet or .regtest
let syncSource = SyncSource(type: SyncSourceType.esplora, customUrl: nil) // .esplora or .electrum, optional customUrl
let database = Database(type: DatabaseType.memory, path: nil, treeName: nil) // .memory or .disk, optional path and tree parameters
        
bdkManager = BDKManager.init(network: network, syncSource: syncSource, database: database)   

Load wallet

To create a new extended private key, descriptor and load the wallet:

do {
    let extendedKeyInfo = try bdkManager.generateExtendedKey(wordCount: nil, password: nil) // optional password and wordCount (defaults to 12)
    let descriptorType = DescriptorType.singleKey_wpkh84 // .singleKey_wpkh84 is the only type defined so far
    let descriptor = bdkManager.createDescriptorFromXprv(descriptorType: DescriptorType.singleKey_wpkh84, xprv: extendedKeyInfo.xprv)
    bdkManager.loadWallet(descriptor: descriptor)
} catch let error {
    print(error)
}  

To load wallet from an existing descriptor:

let descriptor = "wpkh(tprv8ZgxMBicQKsPeSitUfdxhsVaf4BXAASVAbHypn2jnPcjmQZvqZYkeqx7EHQTWvdubTSDa5ben7zHC7sUsx4d8tbTvWdUtHzR8uhHg2CW7MT/*)"
bdkManager.loadWallet(descriptor: descriptor) 

Sync

The wallet can either be synced manually by calling sync(), or at regular intervals by using startSyncRegularly and stopSyncRegularly. On every sync, the @Published parameters .balance and .transactions are updated, which means they automatically trigger updates in SwiftUI.

bdkManager.sync() // Will sync once

bdkManager.startSyncRegularly(interval: 120) // Will sync every 120 seconds
bdkManager.stopSyncRegularly() // Will stop the regular sync

Example

A working SwiftUI example app is included in the repo. It has very basic functionality of showing the balance for a descriptor address. In this case the bdkManager is an @ObservedObject, which enables the WalletView to automatically update depending on bdkManager.syncState. The two files required:

WalletApp.swift

import SwiftUI
import BDKManager

@main
struct WalletApp: App {
    @ObservedObject var bdkManager: BDKManager
    
    init() {
        // Define BDKManager init options
        let network = Network.testnet // set bitcoin, testnet, signet or regtest
        let syncSource = SyncSource(type: SyncSourceType.esplora, customUrl: nil) // set esplora or electrum, can take customUrl
        let database = Database(type: DatabaseType.memory, path: nil, treeName: nil) // set memory or disk, optional path and tree parameters
        
        // Initialize a BDKManager instance
        bdkManager = BDKManager.init(network: network, syncSource: syncSource, database: database)
        
        // Load a singlekey wallet from a newly generated private key
        do {
            let extendedKeyInfo = try bdkManager.generateExtendedKey(wordCount: nil, password: nil)
            let descriptor = bdkManager.createDescriptorFromXprv(descriptorType: DescriptorType.singleKey_wpkh84, xprv: extendedKeyInfo.xprv)
            bdkManager.loadWallet(descriptor: descriptor)
        } catch let error {
            print(error)
        }
        
        // Or load a wallet from an existing descriptor
        //let descriptor = "wpkh(tprv8ZgxMBicQKsPeSitUfdxhsVaf4BXAASVAbHypn2jnPcjmQZvqZYkeqx7EHQTWvdubTSDa5ben7zHC7sUsx4d8tbTvWdUtHzR8uhHg2CW7MT/*)"
        //bdkManager.loadWallet(descriptor: descriptor)
    }
    
    var body: some Scene {
        WindowGroup {
            WalletView()
                .environmentObject(bdkManager)
        }
    }
}

WalletView.swift

import SwiftUI
import BDKManager

struct WalletView: View {
    @EnvironmentObject var bdkManager: BDKManager
    
    var body: some View {
        VStack (spacing: 50){
            Text("Hello, wallet!")
            switch bdkManager.syncState {
            case .synced:
                Text("Balance: \(bdkManager.balance)")
            case .syncing:
                Text("Balance: Syncing")
            default:
                Text("Balance: Not synced")
            }
            Text(bdkManager.wallet?.getNewAddress() ?? "-")
        }.onAppear {
            bdkManager.sync() // to sync once
            //bdkManager.startSyncRegularly(interval: 120) // to sync every 120 seconds
        }.onDisappear {
            //bdkManager.stopSyncRegularly() // if startSyncRegularly was used
        }
    }
}

Public functions

BDK Manager has the following public functions:

init(network: Network, syncSource: SyncSource, database: Database)
generateExtendedKey(wordCount: WordCount?, password: String?) throws -> ExtendedKeyInfo
createDescriptorFromXprv(descriptorType: DescriptorType, xprv: String) -> String
loadWallet(descriptor: String)
sync()
startSyncRegularly(interval: TimeInterval)
stopSyncRegularly()
sendBitcoin(recipient: String, amount: UInt64, feeRate: Float?) -> Transaction?

Since the wallet is a BDK Wallet, the corresponding functions are also available on .wallet:

getNewAddress()  -> String
getLastUnusedAddress()  -> String
getBalance() throws -> UInt64
sign( psbt: PartiallySignedBitcoinTransaction ) throws
getTransactions() throws -> [Transaction]
getNetwork()  -> Network
broadcast( psbt: PartiallySignedBitcoinTransaction ) throws -> Transaction

Public variables

BDK Manager has the following @Published public variables, meaning they can be observed and lead to updates in SwiftUI:

.wallet: Wallet?
.balance: UInt64
.transactions: [BitcoinDevKit.Transaction]
.walletState // .empty, .loading, .loaded, .failed
.syncState // .empty, .syncing, .synced, .failed

GitHub

link
Stars: 1
Last commit: 4 days ago
jonrohan Something's broken? Yell at me @ptrpavlik. Praise and feedback (and money) is also welcome.

Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics