Skip to content
Merged
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
45 changes: 45 additions & 0 deletions bdk-ffi/src/tests/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,39 @@ fn test_create_wallet() {
assert_eq!(wallet.next_derivation_index(KeychainKind::External), 0);
}

#[test]
fn test_keychains() {
let wallet = build_wallet();

let keychains = wallet.keychains();

assert_eq!(keychains.len(), 2);

let external = keychains
.iter()
.find(|keychain| keychain.keychain == KeychainKind::External)
.unwrap();
let internal = keychains
.iter()
.find(|keychain| keychain.keychain == KeychainKind::Internal)
.unwrap();
let external_public_descriptor = external.public_descriptor.to_string();
let internal_public_descriptor = internal.public_descriptor.to_string();

assert_eq!(
external_public_descriptor,
wallet.public_descriptor(KeychainKind::External)
);
assert_eq!(
internal_public_descriptor,
wallet.public_descriptor(KeychainKind::Internal)
);
assert!(external.public_descriptor.has_wildcard());
assert!(internal.public_descriptor.has_wildcard());
assert!(!external_public_descriptor.contains("tprv"));
assert!(!internal_public_descriptor.contains("tprv"));
}

#[test]
fn test_reveal_next_address() {
let wallet = build_wallet();
Expand All @@ -69,6 +102,18 @@ fn test_create_single_wallet() {

assert_eq!(wallet.derivation_index(KeychainKind::External), None);

let keychains = wallet.keychains();

assert_eq!(keychains.len(), 1);
assert_eq!(keychains[0].keychain, KeychainKind::External);
let public_descriptor = keychains[0].public_descriptor.to_string();
assert_eq!(
public_descriptor,
wallet.public_descriptor(KeychainKind::External)
);
assert!(keychains[0].public_descriptor.has_wildcard());
assert!(!public_descriptor.contains("tprv"));

let address_info = wallet.reveal_next_address(KeychainKind::External);

assert_eq!(address_info.index, 0);
Expand Down
16 changes: 16 additions & 0 deletions bdk-ffi/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,22 @@ impl From<BdkAddressInfo> for AddressInfo {
}
}

/// A wallet keychain and its public descriptor.
#[uniffi::export(Display)]
#[derive(uniffi::Record)]
pub struct WalletKeychain {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Display trait is defined on line 221 but not actually exported to the bindings. We need to add #[uniffi::export(Display)].

In this case for Kotlin the WalletKeychain type is a data class and so gets a toString() implementation for free so we get a nice display, but it's not exactly the string you defined in the Display trait implementation on line 221, and I don't think all languages produce this sort of automated toString for simple data types like this one.

// Without exporting Display
[WalletKeychain(keychain=EXTERNAL, publicDescriptor=wpkh([9122d9e0/84'/1'/0']tpubDCYVtmaSaDzTxcgvoP5AHZNbZKZzrvoNH9KARep88vESc6MxRqAp4LmePc2eeGX6XUxBcdhAmkthWTDqygPz2wLAyHWisD299Lkdrj5egY6/0/*)#zpaanzgu), WalletKeychain(keychain=INTERNAL, publicDescriptor=wpkh([9122d9e0/84'/1'/0']tpubDCYVtmaSaDzTxcgvoP5AHZNbZKZzrvoNH9KARep88vESc6MxRqAp4LmePc2eeGX6XUxBcdhAmkthWTDqygPz2wLAyHWisD299Lkdrj5egY6/1/*)#n4cuwhcy)]

// After exporting Display
[External: wpkh([9122d9e0/84'/1'/0']tpubDCYVtmaSaDzTxcgvoP5AHZNbZKZzrvoNH9KARep88vESc6MxRqAp4LmePc2eeGX6XUxBcdhAmkthWTDqygPz2wLAyHWisD299Lkdrj5egY6/0/*)#zpaanzgu, Internal: wpkh([9122d9e0/84'/1'/0']tpubDCYVtmaSaDzTxcgvoP5AHZNbZKZzrvoNH9KARep88vESc6MxRqAp4LmePc2eeGX6XUxBcdhAmkthWTDqygPz2wLAyHWisD299Lkdrj5egY6/1/*)#n4cuwhcy]

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

really nice catch, making a mental note to make sure this doesnt get missed in future prs, fixing

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated code

/// Type of keychain.
pub keychain: KeychainKind,
/// Public descriptor for the keychain.
pub public_descriptor: Arc<Descriptor>,
}

impl Display for WalletKeychain {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}: {}", self.keychain, self.public_descriptor)
}
}

/// Balance, differentiated into various categories.
#[derive(uniffi::Record)]
pub struct Balance {
Expand Down
18 changes: 17 additions & 1 deletion bdk-ffi/src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ use crate::store::{PersistenceType, Persister};
use crate::types::{
AddressInfo, Balance, BlockId, CanonicalTx, ChangeSet, EvictedTx, FullScanRequestBuilder,
KeychainAndIndex, KeychainKind, LocalOutput, Policy, SentAndReceivedValues, SignOptions,
SyncRequestBuilder, UnconfirmedTx, Update, WalletEvent,
SyncRequestBuilder, UnconfirmedTx, Update, WalletEvent, WalletKeychain,
};

use bdk_wallet::bitcoin::Network;
use bdk_wallet::keys::KeyMap;
#[allow(deprecated)]
use bdk_wallet::signer::SignOptions as BdkSignOptions;
use bdk_wallet::{PersistedWallet, Wallet as BdkWallet};
Expand Down Expand Up @@ -424,6 +425,21 @@ impl Wallet {
self.get_wallet().network()
}

/// Iterator over all keychains in this wallet
pub fn keychains(&self) -> Vec<WalletKeychain> {
let wallet = self.get_wallet();
wallet
.keychains()
.map(|(keychain, descriptor)| WalletKeychain {
keychain,
public_descriptor: Arc::new(Descriptor {
extended_descriptor: descriptor.clone(),
key_map: KeyMap::default(),
}),
})
.collect()
}

/// Return the balance, separated into available, trusted-pending, untrusted-pending and
/// immature values.
pub fn balance(&self) -> Balance {
Expand Down
Loading