Skip to content

Commit a6160e2

Browse files
committed
docs: update documentation, examples, and templates for KeyRing API
The new example (electrum_v3) is just for testing purposes and should be removed from the final version of the commit.
1 parent 9e5eb92 commit a6160e2

9 files changed

Lines changed: 481 additions & 158 deletions

File tree

‎README.md‎

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ To persist `Wallet` state use a data storage crate that reads and writes [`Chang
7979

8080
```rust,no_run
8181
use bdk_wallet::rusqlite;
82-
use bdk_wallet::{KeychainKind, Wallet};
82+
use bdk_wallet::{KeyRing, KeychainKind, Wallet};
8383
8484
// Open or create a new SQLite database for wallet data.
8585
let db_path = "my_wallet.sqlite";
@@ -92,18 +92,20 @@ let change_descriptor = "wpkh(tprv8ZgxMBicQKsPdcAqYBpzAFwU5yxBUo88ggoBqu1qPcHUfS
9292
let mut wallet = match Wallet::load()
9393
.descriptor(KeychainKind::External, Some(descriptor))
9494
.descriptor(KeychainKind::Internal, Some(change_descriptor))
95-
.extract_keys()
9695
.check_network(network)
9796
.load_wallet(&mut conn)?
9897
{
9998
Some(wallet) => wallet,
100-
None => Wallet::create(descriptor, change_descriptor)
101-
.network(network)
102-
.create_wallet(&mut conn)?,
99+
None => {
100+
let mut keyring = KeyRing::new(network);
101+
keyring.add_descriptor(KeychainKind::External, descriptor)?;
102+
keyring.add_descriptor(KeychainKind::Internal, change_descriptor)?;
103+
keyring.into_params()?.create_wallet(&mut conn)?
104+
}
103105
};
104106
105107
// Get a new address to receive bitcoin!
106-
let address_info = wallet.reveal_next_address(KeychainKind::External);
108+
let address_info = wallet.reveal_next_address(KeychainKind::External).expect("keychain must exist");
107109
108110
// Persist new wallet state to database.
109111
wallet.persist(&mut conn)?;

‎examples/bitcoind_rpc.rs‎

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ use bdk_bitcoind_rpc::{
22
bitcoincore_rpc::{Auth, Client, RpcApi},
33
Emitter, MempoolEvent,
44
};
5-
use bdk_wallet::rusqlite::Connection;
65
use bdk_wallet::{
76
bitcoin::{Block, Network},
87
KeychainKind, Wallet,
98
};
9+
use bdk_wallet::{rusqlite::Connection, KeyRing};
1010
use clap::{self, Parser};
1111
use std::{
1212
path::PathBuf,
@@ -97,26 +97,31 @@ fn main() -> anyhow::Result<()> {
9797
let wallet_opt = Wallet::load()
9898
.descriptor(KeychainKind::External, Some(args.descriptor.clone()))
9999
.descriptor(KeychainKind::Internal, args.change_descriptor.clone())
100-
.extract_keys()
101100
.check_network(args.network)
102101
.load_wallet(&mut db)?;
103102
let mut wallet = match wallet_opt {
104103
Some(wallet) => wallet,
105-
None => match &args.change_descriptor {
106-
Some(change_desc) => Wallet::create(args.descriptor.clone(), change_desc.clone())
107-
.network(args.network)
108-
.create_wallet(&mut db)?,
109-
None => Wallet::create_single(args.descriptor.clone())
110-
.network(args.network)
111-
.create_wallet(&mut db)?,
112-
},
104+
None => {
105+
let mut keyring = KeyRing::new(args.network);
106+
keyring.add_descriptor(KeychainKind::External, args.descriptor.clone())?;
107+
match &args.change_descriptor {
108+
Some(change_desc) => {
109+
keyring.add_descriptor(KeychainKind::Internal, change_desc.clone())?;
110+
keyring.into_params()?.create_wallet(&mut db)?
111+
}
112+
None => keyring.into_params()?.create_wallet(&mut db)?,
113+
}
114+
}
113115
};
114116
println!(
115117
"Loaded wallet in {}s",
116118
start_load_wallet.elapsed().as_secs_f32()
117119
);
118120

119-
let address = wallet.reveal_next_address(KeychainKind::External).address;
121+
let address = wallet
122+
.reveal_next_address(KeychainKind::External)
123+
.expect("keychain must exist")
124+
.address;
120125
println!("Wallet address: {address}");
121126

122127
let balance = wallet.balance();

‎examples/compiler.rs‎

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use bitcoin::Network;
2121
use miniscript::policy::Concrete;
2222
use miniscript::Descriptor;
2323

24-
use bdk_wallet::{KeychainKind, Wallet};
24+
use bdk_wallet::{KeyRing, KeychainKind};
2525

2626
/// Miniscript policy is a high level abstraction of spending conditions. Defined in the
2727
/// rust-miniscript library here https://docs.rs/miniscript/7.0.0/miniscript/policy/index.html
@@ -56,23 +56,26 @@ fn main() -> Result<(), Box<dyn Error>> {
5656

5757
println!("Compiled into Descriptor: \n{descriptor}");
5858

59+
let mut keyring = KeyRing::new(Network::Regtest);
60+
keyring.add_descriptor(KeychainKind::External, descriptor)?;
61+
5962
// Create a new wallet from descriptors
60-
let mut wallet = Wallet::create_single(descriptor)
61-
.network(Network::Regtest)
62-
.create_wallet_no_persist()?;
63+
let mut wallet = keyring.into_params()?.create_wallet_no_persist()?;
6364

6465
println!(
6566
"First derived address from the descriptor: \n{}",
66-
wallet.next_unused_address(KeychainKind::External),
67+
wallet
68+
.next_unused_address(KeychainKind::External)
69+
.expect("keychain must exist"),
6770
);
6871

69-
// BDK also has it's own `Policy` structure to represent the spending condition in a more
70-
// human readable json format.
71-
let spending_policy = wallet.policies(KeychainKind::External)?;
72-
println!(
73-
"The BDK spending policy: \n{}",
74-
serde_json::to_string_pretty(&spending_policy)?
75-
);
72+
// // BDK also has it's own `Policy` structure to represent the spending condition in a more
73+
// // human readable json format.
74+
// let spending_policy = wallet.policies(KeychainKind::External)?;
75+
// println!(
76+
// "The BDK spending policy: \n{}",
77+
// serde_json::to_string_pretty(&spending_policy)?
78+
// );
7679

7780
Ok(())
7881
}

‎examples/electrum.rs‎

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ use bdk_wallet::bitcoin::Amount;
44
use bdk_wallet::bitcoin::FeeRate;
55
use bdk_wallet::bitcoin::Network;
66
use bdk_wallet::chain::collections::HashSet;
7+
use bdk_wallet::descriptor::IntoWalletDescriptor;
78
use bdk_wallet::psbt::PsbtUtils;
89
use bdk_wallet::rusqlite::Connection;
10+
use bdk_wallet::KeyRing;
911
use bdk_wallet::Wallet;
1012
use bdk_wallet::{KeychainKind, SignOptions};
1113
use std::io::Write;
@@ -27,17 +29,21 @@ fn main() -> Result<(), anyhow::Error> {
2729
let wallet_opt = Wallet::load()
2830
.descriptor(KeychainKind::External, Some(EXTERNAL_DESC))
2931
.descriptor(KeychainKind::Internal, Some(INTERNAL_DESC))
30-
.extract_keys()
3132
.check_network(NETWORK)
3233
.load_wallet(&mut db)?;
3334
let mut wallet = match wallet_opt {
3435
Some(wallet) => wallet,
35-
None => Wallet::create(EXTERNAL_DESC, INTERNAL_DESC)
36-
.network(NETWORK)
37-
.create_wallet(&mut db)?,
36+
None => {
37+
let mut keyring = KeyRing::new(NETWORK);
38+
keyring.add_descriptor(KeychainKind::External, EXTERNAL_DESC)?;
39+
keyring.add_descriptor(KeychainKind::Internal, INTERNAL_DESC)?;
40+
keyring.into_params()?.create_wallet(&mut db)?
41+
}
3842
};
3943

40-
let address = wallet.next_unused_address(KeychainKind::External);
44+
let address = wallet
45+
.next_unused_address(KeychainKind::External)
46+
.expect("keychain must exist");
4147
wallet.persist(&mut db)?;
4248
println!("Generated Address: {address}");
4349

@@ -89,7 +95,14 @@ fn main() -> Result<(), anyhow::Error> {
8995
tx_builder.fee_rate(target_fee_rate);
9096

9197
let mut psbt = tx_builder.finish()?;
92-
let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
98+
let finalized = wallet.sign_with_signers(
99+
&mut psbt,
100+
&[
101+
&get_signers(EXTERNAL_DESC, &wallet),
102+
&get_signers(INTERNAL_DESC, &wallet),
103+
],
104+
SignOptions::default(),
105+
)?;
93106
assert!(finalized);
94107
let original_fee = psbt.fee_amount().unwrap();
95108
let tx_feerate = psbt.fee_rate().unwrap();
@@ -124,7 +137,14 @@ fn main() -> Result<(), anyhow::Error> {
124137
let mut builder = wallet.build_fee_bump(txid).expect("failed to bump tx");
125138
builder.fee_rate(feerate);
126139
let mut bumped_psbt = builder.finish().unwrap();
127-
let finalize_btx = wallet.sign(&mut bumped_psbt, SignOptions::default())?;
140+
let finalize_btx = wallet.sign_with_signers(
141+
&mut bumped_psbt,
142+
&[
143+
&get_signers(EXTERNAL_DESC, &wallet),
144+
&get_signers(INTERNAL_DESC, &wallet),
145+
],
146+
SignOptions::default(),
147+
)?;
128148
assert!(finalize_btx);
129149
let new_fee = bumped_psbt.fee_amount().unwrap();
130150
let bumped_tx = bumped_psbt.extract_tx()?;
@@ -176,3 +196,15 @@ fn main() -> Result<(), anyhow::Error> {
176196

177197
Ok(())
178198
}
199+
200+
pub fn get_signers(
201+
desc: impl IntoWalletDescriptor,
202+
wallet: &Wallet<KeychainKind>,
203+
) -> bdk_wallet::signer::SignersContainer {
204+
use bdk_wallet::signer::SignersContainer;
205+
206+
let (descriptor, keymap) = desc
207+
.into_wallet_descriptor(wallet.secp_ctx(), wallet.network().into())
208+
.unwrap();
209+
SignersContainer::build(keymap, &descriptor, wallet.secp_ctx())
210+
}

0 commit comments

Comments
 (0)