]> Untitled Git - bdk/commitdiff
Add `wallet_electrum` example
author志宇 <hello@evanlinjin.me>
Tue, 7 Mar 2023 23:01:01 +0000 (12:01 +1300)
committer志宇 <hello@evanlinjin.me>
Tue, 7 Mar 2023 23:01:01 +0000 (12:01 +1300)
crates/bdk/src/wallet/mod.rs
example-crates/wallet_electrum/Cargo.toml
example-crates/wallet_electrum/src/main.rs

index 41a579194d6788ee8ee9aacc12919f9662d4d188..053bf8a661888b30bb7a8cfeafea38fd6086bd5f 100644 (file)
@@ -1711,6 +1711,28 @@ impl<D> Wallet<D> {
     pub fn staged(&self) -> &ChangeSet {
         self.persist.staged()
     }
+
+    /// Get a reference to the inner [`TxGraph`](bdk_chain::tx_graph::TxGraph).
+    pub fn as_graph(&self) -> &bdk_chain::tx_graph::TxGraph {
+        self.keychain_tracker.graph()
+    }
+
+    /// Get a reference to the inner [`ChainGraph`](bdk_chain::chain_graph::ChainGraph).
+    pub fn as_chain_graph(&self) -> &bdk_chain::chain_graph::ChainGraph<ConfirmationTime> {
+        self.keychain_tracker.chain_graph()
+    }
+}
+
+impl<D> AsRef<bdk_chain::tx_graph::TxGraph> for Wallet<D> {
+    fn as_ref(&self) -> &bdk_chain::tx_graph::TxGraph {
+        self.keychain_tracker.graph()
+    }
+}
+
+impl<D> AsRef<bdk_chain::chain_graph::ChainGraph<ConfirmationTime>> for Wallet<D> {
+    fn as_ref(&self) -> &bdk_chain::chain_graph::ChainGraph<ConfirmationTime> {
+        self.keychain_tracker.chain_graph()
+    }
 }
 
 /// Deterministically generate a unique name given the descriptors defining the wallet
index 0415d227a86b8c8ba39c9a5168a74df6050e1a36..da84e85f10bc380284cc0becfcd9fbfcd37ede7f 100644 (file)
@@ -5,3 +5,5 @@ edition = "2021"
 
 [dependencies]
 bdk = { path = "../../crates/bdk" }
+bdk_electrum = { path = "../../crates/electrum" }
+bdk_file_store = { path = "../../crates/file_store" }
index e7a11a969c037e00a796aafeff6258501ec15e9a..dabd66da9d0e94cee36f334b02aba143a7c4c5f6 100644 (file)
@@ -1,3 +1,83 @@
-fn main() {
+use std::str::FromStr;
+
+use bdk::{
+    bitcoin::{Address, Network},
+    SignOptions, Wallet,
+};
+use bdk_electrum::{
+    electrum_client::{self, ElectrumApi},
+    ElectrumExt,
+};
+use bdk_file_store::KeychainStore;
+
+const SEND_AMOUNT: u64 = 5000;
+const STOP_GAP: usize = 50;
+const BATCH_SIZE: usize = 5;
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
     println!("Hello, world!");
+
+    let db_path = std::env::temp_dir().join("bdk-electrum-example");
+    let db = KeychainStore::new_from_path(db_path)?;
+    let external_descriptor = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/0'/0'/0/*)";
+    let internal_descriptor = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/0'/0'/1/*)";
+
+    let mut wallet = Wallet::new(
+        external_descriptor,
+        Some(internal_descriptor),
+        db,
+        Network::Testnet,
+    )?;
+
+    let address = wallet.get_address(bdk::wallet::AddressIndex::New);
+    println!("Generated Address: {}", address);
+
+    let balance = wallet.get_balance();
+    println!("Wallet balance before syncing: {} sats", balance.total());
+
+    println!("Syncing...");
+    // Scanning the chain...
+    let electrum_url = "ssl://electrum.blockstream.info:60002";
+    let client = electrum_client::Client::new(electrum_url)?;
+    let local_chain = wallet.checkpoints();
+    let spks = wallet.spks_of_all_keychains();
+    let electrum_update = client
+        .scan(
+            local_chain,
+            spks,
+            core::iter::empty(),
+            core::iter::empty(),
+            STOP_GAP,
+            BATCH_SIZE,
+        )?
+        .into_confirmation_time_update(&client)?;
+    let new_txs = client.batch_transaction_get(electrum_update.missing_full_txs(&wallet))?;
+    let update = electrum_update.into_keychain_scan(new_txs, &wallet)?;
+    wallet.apply_update(update)?;
+    wallet.commit()?;
+
+    let balance = wallet.get_balance();
+    println!("Wallet balance after syncing: {} sats", balance.total());
+
+    if balance.total() == 0 {
+        println!("Please send some coins to the receiving address");
+        std::process::exit(0);
+    }
+
+    let faucet_address = Address::from_str("mkHS9ne12qx9pS9VojpwU5xtRd4T7X7ZUt")?;
+
+    let mut tx_builder = wallet.build_tx();
+    tx_builder
+        .add_recipient(faucet_address.script_pubkey(), SEND_AMOUNT)
+        .enable_rbf();
+
+    let (mut psbt, _) = tx_builder.finish()?;
+    let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
+    assert!(finalized);
+
+    let tx = psbt.extract_tx();
+    client.transaction_broadcast(&tx)?;
+    println!("Tx broadcasted! Txid: {}", tx.txid());
+
+    Ok(())
 }