From 117915bded38e31a69f286fd107ed63b2feec188 Mon Sep 17 00:00:00 2001 From: Dave Hrycyszyn Date: Mon, 24 Jun 2024 17:20:52 +0100 Subject: [PATCH] Splitting key load / wallet creation so we can use keys in esplora client --- side-node/src/clients/btc_electrum_client.rs | 35 ++++++++++++++++---- side-node/src/keys/bitcoin.rs | 26 +++++++-------- side-node/src/lib.rs | 3 +- side-node/tests/side_node.rs | 11 ++++-- 4 files changed, 51 insertions(+), 24 deletions(-) diff --git a/side-node/src/clients/btc_electrum_client.rs b/side-node/src/clients/btc_electrum_client.rs index faa14f8..c18541a 100644 --- a/side-node/src/clients/btc_electrum_client.rs +++ b/side-node/src/clients/btc_electrum_client.rs @@ -1,8 +1,10 @@ use crate::{keys, utils}; +use bdk::bitcoin::bip32::ExtendedPrivKey; use bdk::bitcoin::psbt::PartiallySignedTransaction; -use bdk::blockchain::Blockchain; +use bdk::bitcoin::Network; use bdk::database::MemoryDatabase; +use bdk::template::Bip84; use bdk::wallet::AddressIndex::{self, New}; use bdk::wallet::AddressInfo; use bdk::{blockchain::ElectrumBlockchain, electrum_client, SyncOptions}; @@ -11,8 +13,11 @@ use bdk::{FeeRate, SignOptions, TransactionDetails, Wallet}; pub async fn run() -> Result<(), anyhow::Error> { let dave = utils::home(&"dave".to_string()); let sammy = utils::home(&"sammy".to_string()); - let dave_wallet = keys::bitcoin::load_from_file(&dave).unwrap(); - let sammy_wallet = keys::bitcoin::load_from_file(&sammy).unwrap(); + let dave_keys = keys::bitcoin::load_from_file(&dave).unwrap(); + let sammy_keys = keys::bitcoin::load_from_file(&sammy).unwrap(); + + let dave_wallet = create_wallet(dave_keys)?; + let sammy_wallet = create_wallet(sammy_keys)?; let dave_address = dave_wallet.get_address(AddressIndex::Peek(0))?.to_string(); let sammy_address = sammy_wallet.get_address(AddressIndex::Peek(0))?.to_string(); @@ -36,14 +41,30 @@ pub async fn run() -> Result<(), anyhow::Error> { println!("About to sign the transaction: {:?}", details); dave_wallet.sign(&mut psbt, SignOptions::default())?; - let signed_tx = psbt.extract_tx(); + let _signed_tx = psbt.extract_tx(); - println!("Broadcasting..."); - blockchain.broadcast(&signed_tx).expect("broadcast error"); - println!("Transaction ID: {:?}", signed_tx.txid()); + // println!("Broadcasting..."); + // blockchain.broadcast(&signed_tx).expect("broadcast error"); + // println!("Transaction ID: {:?}", signed_tx.txid()); Ok(()) } +/// Create a BDK wallet using BIP 84 descriptor ("m/84h/1h/0h/0" and "m/84h/1h/0h/1") +pub fn create_wallet( + keys: (Bip84, Option>), +) -> anyhow::Result> { + let (external_descriptor, internal_descriptor) = keys; + + let wallet = Wallet::new( + external_descriptor, + internal_descriptor, + Network::Testnet, + MemoryDatabase::default(), + )?; + + Ok(wallet) +} + fn display_balance(wallet: &Wallet) { println!( "Wallet balance for {} after syncing: {:?} sats on network {}", diff --git a/side-node/src/keys/bitcoin.rs b/side-node/src/keys/bitcoin.rs index e5b9ee2..8b33719 100644 --- a/side-node/src/keys/bitcoin.rs +++ b/side-node/src/keys/bitcoin.rs @@ -1,13 +1,12 @@ use bdk::{ - bitcoin::Network, - database::MemoryDatabase, + bitcoin::{bip32::ExtendedPrivKey, Network}, keys::{ bip39::{Language, Mnemonic, WordCount}, DerivableKey, ExtendedKey, GeneratableKey, GeneratedKey, }, miniscript, template::Bip84, - KeychainKind, Wallet, + KeychainKind, }; use std::{ @@ -32,7 +31,9 @@ pub(crate) fn write(mnemonic_path: &PathBuf) -> Result<(), std::io::Error> { } /// Creates a Signet Bitcoin descriptor wallet from a mnemonic -pub fn create_wallet(mnemonic_words: String) -> anyhow::Result> { +pub fn get( + mnemonic_words: String, +) -> anyhow::Result<(Bip84, Option>)> { let mnemonic = Mnemonic::parse(mnemonic_words).unwrap(); // Generate the extended key @@ -41,20 +42,17 @@ pub fn create_wallet(mnemonic_words: String) -> anyhow::Result anyhow::Result> { +pub(crate) fn load_from_file( + side_dir: &PathBuf, +) -> anyhow::Result<(Bip84, Option>)> { let mnemonic_path = crate::utils::side_paths(side_dir.clone()).1; // TODO: this tuple stinks let mnemonic_words = fs::read_to_string(mnemonic_path).expect("couldn't read bitcoin key file"); println!("Creating wallet from mnemonic: {mnemonic_words}"); - create_wallet(mnemonic_words) + get(mnemonic_words) } diff --git a/side-node/src/lib.rs b/side-node/src/lib.rs index dea02c9..dba3920 100644 --- a/side-node/src/lib.rs +++ b/side-node/src/lib.rs @@ -42,7 +42,8 @@ async fn setup(name: &String) -> SideNode { // First, load up the keys and create a bft-crdt let side_dir = utils::home(name); let bft_crdt_keys = keys::bft_crdt::load_from_file(&side_dir); - let bitcoin_wallet = keys::bitcoin::load_from_file(&side_dir).unwrap(); + let bitcoin_keys = keys::bitcoin::load_from_file(&side_dir).unwrap(); + let bitcoin_wallet = clients::btc_electrum_client::create_wallet(bitcoin_keys).unwrap(); let crdt = BaseCrdt::::new(&bft_crdt_keys); // Channels for internal communication, and a tokio task for stdin input diff --git a/side-node/tests/side_node.rs b/side-node/tests/side_node.rs index b7478cf..a4547da 100644 --- a/side-node/tests/side_node.rs +++ b/side-node/tests/side_node.rs @@ -2,7 +2,13 @@ use bft_json_crdt::{ json_crdt::{BaseCrdt, SignedOp}, keypair::make_keypair, }; -use side_node::{clients::websocket::Client, crdt::TransactionList, keys, node::SideNode, utils}; +use side_node::{ + clients::{btc_electrum_client, websocket::Client}, + crdt::TransactionList, + keys, + node::SideNode, + utils, +}; use tokio::sync::mpsc; #[tokio::test] @@ -36,7 +42,8 @@ async fn setup(_: &str) -> SideNode { // First, load up the keys and create a bft-crdt let bft_crdt_keys = make_keypair(); let mnemonic_words = keys::bitcoin::make_mnemonic(); - let bitcoin_wallet = keys::bitcoin::create_wallet(mnemonic_words).unwrap(); + let bitcoin_keys = keys::bitcoin::get(mnemonic_words).unwrap(); + let bitcoin_wallet = btc_electrum_client::create_wallet(bitcoin_keys).unwrap(); let crdt = BaseCrdt::::new(&bft_crdt_keys); // Channels for internal communication, and a tokio task for stdin input