Skip to content

Commit d6a96fa

Browse files
committed
feat: add example with esplora async and redb
1 parent 837f024 commit d6a96fa

2 files changed

Lines changed: 106 additions & 0 deletions

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "example_wallet_esplora_async_redb"
3+
version = "0.1.0"
4+
edition = "2024"
5+
authors.workspace = true
6+
7+
[dependencies]
8+
bdk_wallet = { version = "2.0.0" }
9+
bdk_esplora = { version = "0.22.0", features = ["async-https", "tokio"] }
10+
tokio = { version = "1.38.1", features = ["rt", "rt-multi-thread", "macros"] }
11+
anyhow = "1"
12+
bdk_redb = { git = "https://github.com/110CodingP/bdk_redb" }
13+
14+
[lints]
15+
workspace = true
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
use std::{collections::BTreeSet, io::Write};
2+
use bdk_redb::Store;
3+
4+
use anyhow::Ok;
5+
use bdk_esplora::{esplora_client, EsploraAsyncExt};
6+
use bdk_wallet::{
7+
bitcoin::{Amount, Network},
8+
KeychainKind, SignOptions, Wallet,
9+
};
10+
11+
const SEND_AMOUNT: Amount = Amount::from_sat(5000);
12+
const STOP_GAP: usize = 5;
13+
const PARALLEL_REQUESTS: usize = 5;
14+
15+
const DB_PATH: &str = "bdk-example-esplora-async.db";
16+
const NETWORK: Network = Network::Signet;
17+
const EXTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
18+
const INTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
19+
const ESPLORA_URL: &str = "http://signet.bitcoindevkit.net";
20+
21+
#[tokio::main]
22+
async fn main() -> Result<(), anyhow::Error> {
23+
let mut store = Store::new(DB_PATH, "wallet_1".to_string())?;
24+
25+
let wallet_opt = Wallet::load()
26+
.descriptor(KeychainKind::External, Some(EXTERNAL_DESC))
27+
.descriptor(KeychainKind::Internal, Some(INTERNAL_DESC))
28+
.extract_keys()
29+
.check_network(NETWORK)
30+
.load_wallet(&mut store)?;
31+
let mut wallet = match wallet_opt {
32+
Some(wallet) => wallet,
33+
None => Wallet::create(EXTERNAL_DESC, INTERNAL_DESC)
34+
.network(NETWORK)
35+
.create_wallet(&mut store)?,
36+
};
37+
38+
let address = wallet.next_unused_address(KeychainKind::External);
39+
wallet.persist(&mut store)?;
40+
println!("Next unused address: ({}) {}", address.index, address);
41+
42+
let balance = wallet.balance();
43+
println!("Wallet balance before syncing: {}", balance.total());
44+
45+
print!("Syncing...");
46+
let client = esplora_client::Builder::new(ESPLORA_URL).build_async()?;
47+
48+
let request = wallet.start_full_scan().inspect({
49+
let mut stdout = std::io::stdout();
50+
let mut once = BTreeSet::<KeychainKind>::new();
51+
move |keychain, spk_i, _| {
52+
if once.insert(keychain) {
53+
print!("\nScanning keychain [{:?}]", keychain);
54+
}
55+
print!(" {:<3}", spk_i);
56+
stdout.flush().expect("must flush")
57+
}
58+
});
59+
60+
let update = client
61+
.full_scan(request, STOP_GAP, PARALLEL_REQUESTS)
62+
.await?;
63+
64+
wallet.apply_update(update)?;
65+
wallet.persist(&mut store)?;
66+
println!();
67+
68+
let balance = wallet.balance();
69+
println!("Wallet balance after syncing: {}", balance.total());
70+
71+
if balance.total() < SEND_AMOUNT {
72+
println!(
73+
"Please send at least {} to the receiving address",
74+
SEND_AMOUNT
75+
);
76+
std::process::exit(0);
77+
}
78+
79+
let mut tx_builder = wallet.build_tx();
80+
tx_builder.add_recipient(address.script_pubkey(), SEND_AMOUNT);
81+
82+
let mut psbt = tx_builder.finish()?;
83+
let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
84+
assert!(finalized);
85+
86+
let tx = psbt.extract_tx()?;
87+
client.broadcast(&tx).await?;
88+
println!("Tx broadcasted! Txid: {}", tx.compute_txid());
89+
90+
Ok(())
91+
}

0 commit comments

Comments
 (0)