Skip to content

Commit 8e63438

Browse files
exploring bdk-tx with bdk_wallet
1 parent 59fdc6b commit 8e63438

File tree

3 files changed

+133
-2
lines changed

3 files changed

+133
-2
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ bdk_tx = { path = "." }
1919
bitcoin = { version = "0.32", features = ["rand-std"] }
2020
bdk_testenv = "0.11.1"
2121
bdk_bitcoind_rpc = "0.18.0"
22+
bdk_wallet = "1.2.0"
23+
bdk_esplora = { version = "0.20.1", features = ["blocking"] }
2224

2325
[features]
2426
default = ["std"]

tests/bdk_wallet.rs

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
use bdk_chain::spk_client::{
2+
FullScanRequestBuilder, FullScanResponse, SyncResponse,
3+
};
4+
use bdk_chain::KeychainIndexed;
5+
use bdk_esplora::esplora_client;
6+
use bdk_esplora::esplora_client::Builder;
7+
use bdk_esplora::EsploraExt;
8+
use bdk_testenv::{bitcoincore_rpc::RpcApi, TestEnv};
9+
use bdk_tx::{create_psbt, create_selection, CreatePsbtParams, CreateSelectionParams, InputCandidates, InputGroup, Output};
10+
use bdk_wallet::{AddressInfo, KeychainKind, LocalOutput, SignOptions};
11+
use bitcoin::address::NetworkChecked;
12+
use bitcoin::{Address, Amount, FeeRate, Network, OutPoint};
13+
use miniscript::descriptor::KeyMap;
14+
use miniscript::{Descriptor, DescriptorPublicKey};
15+
use std::collections::BTreeMap;
16+
use std::process::exit;
17+
use std::str::FromStr;
18+
use miniscript::plan::Assets;
19+
20+
#[test]
21+
fn bdk_wallet_simple_tx() -> anyhow::Result<()> {
22+
const STOP_GAP: usize = 20;
23+
const PARALLEL_REQUESTS: usize = 1;
24+
let secp = bitcoin::secp256k1::Secp256k1::new();
25+
26+
let descriptor_private: &str = "tr(tprv8ZgxMBicQKsPdNRGG6HuFapxQCFxsDDf7TDsV8tdUgZDdiiyA6dB2ssN4RSXyp52V3MRBm4KqAps3Txng59rNMUtUEtMPDphKkKDXmamd2T/86'/1'/0'/0/*)#usy7l3tt";
27+
let change_descriptor_private: &str = "tr(tprv8ZgxMBicQKsPdNRGG6HuFapxQCFxsDDf7TDsV8tdUgZDdiiyA6dB2ssN4RSXyp52V3MRBm4KqAps3Txng59rNMUtUEtMPDphKkKDXmamd2T/86'/1'/0'/1/*)#dyplzymn";
28+
29+
let (descriptor, _): (Descriptor<DescriptorPublicKey>, KeyMap) = Descriptor::parse_descriptor(&secp, "tr(tprv8ZgxMBicQKsPdNRGG6HuFapxQCFxsDDf7TDsV8tdUgZDdiiyA6dB2ssN4RSXyp52V3MRBm4KqAps3Txng59rNMUtUEtMPDphKkKDXmamd2T/86'/1'/0'/0/*)#usy7l3tt")?;
30+
let (change_descriptor, _): (Descriptor<DescriptorPublicKey>, KeyMap) = Descriptor::parse_descriptor(&secp, "tr(tprv8ZgxMBicQKsPdNRGG6HuFapxQCFxsDDf7TDsV8tdUgZDdiiyA6dB2ssN4RSXyp52V3MRBm4KqAps3Txng59rNMUtUEtMPDphKkKDXmamd2T/86'/1'/0'/1/*)#dyplzymn")?;
31+
32+
// Create the wallet
33+
let mut wallet = bdk_wallet::Wallet::create(descriptor_private, change_descriptor_private)
34+
.network(Network::Regtest)
35+
.create_wallet_no_persist()?;
36+
37+
let client: esplora_client::BlockingClient =
38+
Builder::new("http://127.0.0.1:3002").build_blocking();
39+
40+
println!("Syncing wallet...");
41+
let full_scan_request: FullScanRequestBuilder<KeychainKind> = wallet.start_full_scan();
42+
let update: FullScanResponse<KeychainKind> =
43+
client.full_scan(full_scan_request, STOP_GAP, PARALLEL_REQUESTS)?;
44+
45+
// Apply the update from the full scan to the wallet
46+
wallet.apply_update(update)?;
47+
48+
let balance = wallet.balance();
49+
println!("Wallet balance: {} sat", balance.total().to_sat());
50+
51+
if balance.total().to_sat() < 300000 {
52+
println!("Your wallet does not have sufficient balance for the following steps!");
53+
// Reveal a new address from your external keychain
54+
let address: AddressInfo = wallet.reveal_next_address(KeychainKind::External);
55+
println!(
56+
"Send coins to {} (address generated at index {})",
57+
address.address, address.index
58+
);
59+
exit(0)
60+
}
61+
62+
let local_outputs: Vec<LocalOutput> = wallet.list_unspent().collect();
63+
dbg!(&local_outputs.len());
64+
// dbg!(&local_outputs);
65+
let outpoints: Vec<KeychainIndexed<KeychainKind, OutPoint>> = local_outputs
66+
.into_iter()
67+
.map(|o| ((o.keychain, o.derivation_index), o.outpoint.clone()))
68+
.collect();
69+
70+
let mut descriptors_map = BTreeMap::new();
71+
descriptors_map.insert(KeychainKind::External, descriptor.clone());
72+
descriptors_map.insert(KeychainKind::Internal, change_descriptor.clone());
73+
74+
let input_candidates: Vec<InputGroup> = InputCandidates::new(
75+
&wallet.tx_graph(),
76+
&wallet.local_chain(),
77+
wallet.local_chain().tip().block_id(),
78+
outpoints,
79+
descriptors_map,
80+
Assets::new()
81+
)?.into_single_groups(|_| true);
82+
83+
let recipient_address: Address<NetworkChecked> =
84+
Address::from_str("bcrt1qe908k9zu8m4jgzdddgg0lkj73yctfqueg7pea9")?
85+
.require_network(Network::Regtest)?;
86+
87+
let (selection, metrics) = create_selection(CreateSelectionParams::new(
88+
input_candidates,
89+
change_descriptor.at_derivation_index(0)?,
90+
vec![Output::with_script(
91+
recipient_address.script_pubkey(),
92+
Amount::from_sat(200_000),
93+
)],
94+
FeeRate::from_sat_per_vb(5).unwrap(),
95+
))?;
96+
97+
dbg!(&selection);
98+
99+
let (mut psbt, _) = create_psbt(CreatePsbtParams::new(selection))?;
100+
let signed = wallet.sign(&mut psbt, SignOptions::default())?;
101+
assert!(signed);
102+
let tx = psbt.extract_tx()?;
103+
104+
client.broadcast(&tx)?;
105+
dbg!("tx broadcast: {}", tx.compute_txid());
106+
107+
println!("Syncing wallet again...");
108+
let sync_request = wallet.start_sync_with_revealed_spks();
109+
let update_2: SyncResponse = client.sync(sync_request, PARALLEL_REQUESTS)?;
110+
111+
wallet.apply_update(update_2)?;
112+
113+
let balance_2 = wallet.balance();
114+
println!("Wallet balance: {} sat", balance_2.total().to_sat());
115+
116+
Ok(())
117+
}

tests/synopsis.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
use bdk_bitcoind_rpc::Emitter;
2-
use bdk_chain::{bdk_core, Balance};
2+
use bdk_chain::spk_client::{
3+
FullScanRequestBuilder, FullScanResponse, SyncRequestBuilder, SyncResponse,
4+
};
5+
use bdk_chain::{bdk_core, Balance, KeychainIndexed};
6+
use bdk_esplora::esplora_client;
7+
use bdk_esplora::esplora_client::Builder;
8+
use bdk_esplora::EsploraExt;
39
use bdk_testenv::{bitcoincore_rpc::RpcApi, TestEnv};
410
use bdk_tx::{
511
create_psbt, create_selection, filter_unspendable_now, group_by_spk, CreatePsbtParams,
612
CreateSelectionParams, InputCandidates, InputGroup, Output, Signer,
713
};
8-
use bitcoin::{absolute, key::Secp256k1, Address, Amount, BlockHash, FeeRate};
14+
use bdk_wallet::{AddressInfo, KeychainKind, LocalOutput, SignOptions};
15+
use bitcoin::address::NetworkChecked;
16+
use bitcoin::{absolute, key::Secp256k1, Address, Amount, BlockHash, FeeRate, Network, OutPoint};
17+
use miniscript::descriptor::KeyMap;
918
use miniscript::{Descriptor, DescriptorPublicKey};
19+
use std::collections::BTreeMap;
20+
use std::process::exit;
21+
use std::str::FromStr;
1022

1123
const EXTERNAL: &str = "external";
1224
const INTERNAL: &str = "internal";

0 commit comments

Comments
 (0)