Skip to content

Commit ef8a2ab

Browse files
feat: add RPC wallet example
1 parent e327ff1 commit ef8a2ab

File tree

2 files changed

+104
-2
lines changed

2 files changed

+104
-2
lines changed

example-crates/wallet_rpc/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ edition = "2021"
66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

88
[dependencies]
9+
bdk = { path = "../../crates/bdk" }
10+
bdk_file_store = { path = "../../crates/file_store" }
11+
bdk_bitcoind_rpc = { path = "../../crates/bitcoind_rpc" }

example-crates/wallet_rpc/src/main.rs

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,102 @@
1-
fn main() {
2-
println!("Hello, world!");
1+
use bdk::{
2+
bitcoin::{Address, Network},
3+
wallet::{AddressIndex, ChangeSet, Wallet},
4+
SignOptions,
5+
};
6+
use bdk_bitcoind_rpc::{
7+
bitcoincore_rpc::{Auth, Client, RpcApi},
8+
Emitter,
9+
};
10+
use bdk_file_store::Store;
11+
use std::str::FromStr;
12+
13+
const DB_MAGIC: &str = "bdk-rpc-wallet-example";
14+
const FALLBACK_HEIGHT: u32 = 2532323;
15+
const SEND_AMOUNT: u64 = 5000;
16+
const LOOKAHEAD: u32 = 20;
17+
const RPC_USER: &str = "bitcoin";
18+
const RPC_PASS: &str = "password";
19+
const RPC_URL: &str = "127.0.0.1:18332";
20+
21+
fn main() -> Result<(), Box<dyn std::error::Error>> {
22+
let db_path = std::env::temp_dir().join("bdk-rpc-example");
23+
let db = Store::<bdk::wallet::ChangeSet>::new_from_path(DB_MAGIC.as_bytes(), db_path)?;
24+
25+
let external_descriptor = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
26+
let internal_descriptor = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
27+
28+
let mut wallet = Wallet::new(
29+
external_descriptor,
30+
Some(internal_descriptor),
31+
db,
32+
Network::Testnet,
33+
)?;
34+
35+
let address = wallet.get_address(AddressIndex::New);
36+
println!("Generated Address: {}", address);
37+
38+
let balance = wallet.get_balance();
39+
println!("Wallet balance before syncing: {} sats", balance.total());
40+
41+
let rpc_client = Client::new(
42+
RPC_URL,
43+
Auth::UserPass(RPC_USER.to_string(), RPC_PASS.to_string()),
44+
)?;
45+
46+
println!(
47+
"Connected to Bitcoin Core RPC at {:?}",
48+
rpc_client.get_blockchain_info().unwrap()
49+
);
50+
51+
wallet.set_lookahead_for_all(LOOKAHEAD);
52+
53+
let chain_tip = wallet.latest_checkpoint();
54+
let mut emitter = match chain_tip {
55+
Some(cp) => Emitter::from_checkpoint(&rpc_client, cp),
56+
None => Emitter::from_height(&rpc_client, FALLBACK_HEIGHT),
57+
};
58+
59+
while let Some((height, block)) = emitter.next_block()? {
60+
println!("Applying block {} at height {}", block.block_hash(), height);
61+
let wallet_changeset = wallet.apply_block_relevant(block, height)?;
62+
wallet.stage(wallet_changeset);
63+
wallet.commit()?;
64+
}
65+
66+
let unconfirmed_txs = emitter.mempool()?;
67+
let mempool_changeset = wallet
68+
.batch_insert_relevant_unconfirmed(unconfirmed_txs.iter().map(|(tx, time)| (tx, *time)));
69+
println!("Applying unconfirmed transactions: {:?}", mempool_changeset);
70+
let wallet_changeset = ChangeSet::from(mempool_changeset);
71+
wallet.stage(wallet_changeset);
72+
wallet.commit()?;
73+
74+
let balance = wallet.get_balance();
75+
println!("Wallet balance after syncing: {} sats", balance.total());
76+
77+
if balance.total() < SEND_AMOUNT {
78+
println!(
79+
"Please send at least {} sats to the receiving address",
80+
SEND_AMOUNT
81+
);
82+
std::process::exit(0);
83+
}
84+
85+
let faucet_address = Address::from_str("tb1qw2c3lxufxqe2x9s4rdzh65tpf4d7fssjgh8nv6")?
86+
.require_network(Network::Testnet)?;
87+
88+
let mut tx_builder = wallet.build_tx();
89+
tx_builder
90+
.add_recipient(faucet_address.script_pubkey(), SEND_AMOUNT)
91+
.enable_rbf();
92+
93+
let mut psbt = tx_builder.finish()?;
94+
let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
95+
assert!(finalized);
96+
97+
let tx = psbt.extract_tx();
98+
rpc_client.send_raw_transaction(&tx)?;
99+
println!("Tx broadcasted! Txid: {}", tx.txid());
100+
101+
Ok(())
3102
}

0 commit comments

Comments
 (0)