Skip to content

Commit 4d4d8db

Browse files
feat: expose Wallet::create_single method
1 parent adca42a commit 4d4d8db

File tree

3 files changed

+72
-0
lines changed

3 files changed

+72
-0
lines changed

bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/CreatingWalletTest.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,16 @@ class CreatingWalletTest {
4242
)
4343
}
4444

45+
// Create a wallet with a single descriptor.
46+
@Test
47+
fun createWalletWithSingleDescriptor() {
48+
Wallet.createSingle(
49+
descriptor = BIP86_DESCRIPTOR,
50+
network = Network.TESTNET,
51+
persister = conn
52+
)
53+
}
54+
4555
// Create a wallet with a public multipath descriptor.
4656
@Test
4757
fun createWalletWithMultipathDescriptor() {

bdk-android/lib/src/androidTest/kotlin/org/bitcoindevkit/WalletTest.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,24 @@ class WalletTest {
4545
actual = wallet.balance().total.toSat()
4646
)
4747
}
48+
49+
// Single-descriptor wallets return an address on the external keychain even if a change descriptor is not provided
50+
// and the wallet.revealNextAddress(KeychainKind.INTERNAL) or wallet.peekAddress(KeychainKind.EXTERNAL, 0u) APIs are
51+
// used.
52+
@Test
53+
fun singleDescriptorWalletCanCreateAddresses() {
54+
val wallet: Wallet = Wallet.createSingle(
55+
descriptor = BIP84_DESCRIPTOR,
56+
network = Network.TESTNET,
57+
persister = conn
58+
)
59+
val address1 = wallet.peekAddress(KeychainKind.EXTERNAL, 0u)
60+
val address2 = wallet.peekAddress(KeychainKind.INTERNAL, 0u)
61+
62+
assertEquals(
63+
expected = address1.address,
64+
actual = address2.address,
65+
"Addresses should be the same"
66+
)
67+
}
4868
}

bdk-ffi/src/wallet.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,48 @@ impl Wallet {
6767
})
6868
}
6969

70+
/// Build a new single descriptor `Wallet`.
71+
///
72+
/// If you have previously created a wallet, use `Wallet::load` instead.
73+
///
74+
/// # Note
75+
///
76+
/// Only use this method when creating a wallet designed to be used with a single
77+
/// descriptor and keychain. Otherwise the recommended way to construct a new wallet is
78+
/// by using `Wallet::new`. It's worth noting that not all features are available
79+
/// with single descriptor wallets, for example setting a `change_policy` on `TxBuilder`
80+
/// and related methods such as `do_not_spend_change`. This is because all payments are
81+
/// received on the external keychain (including change), and without a change keychain
82+
/// BDK lacks enough information to distinguish between change and outside payments.
83+
///
84+
/// Additionally because this wallet has no internal (change) keychain, all methods that
85+
/// require a `KeychainKind` as input, e.g. `reveal_next_address` should only be called
86+
/// using the `External` variant. In most cases passing `Internal` is treated as the
87+
/// equivalent of `External` but this behavior must not be relied on.
88+
#[uniffi::constructor(default(lookahead = 25))]
89+
pub fn create_single(
90+
descriptor: Arc<Descriptor>,
91+
network: Network,
92+
persister: Arc<Persister>,
93+
lookahead: u32,
94+
) -> Result<Self, CreateWithPersistError> {
95+
let descriptor = descriptor.to_string_with_secret();
96+
let mut persist_lock = persister.inner.lock().unwrap();
97+
let deref = persist_lock.deref_mut();
98+
99+
let wallet: PersistedWallet<PersistenceType> = BdkWallet::create_single(descriptor)
100+
.network(network)
101+
.lookahead(lookahead)
102+
.create_wallet(deref)
103+
.map_err(|e| CreateWithPersistError::Persist {
104+
error_message: e.to_string(),
105+
})?;
106+
107+
Ok(Wallet {
108+
inner_mutex: Mutex::new(wallet),
109+
})
110+
}
111+
70112
/// Build a new `Wallet` from a two-path descriptor.
71113
///
72114
/// This function parses a multipath descriptor with exactly 2 paths and creates a wallet using the existing receive and change wallet creation logic.

0 commit comments

Comments
 (0)