Splitting key load / wallet creation so we can use keys in esplora client

This commit is contained in:
Dave Hrycyszyn
2024-06-24 17:20:52 +01:00
parent 5c03a77e56
commit 117915bded
4 changed files with 51 additions and 24 deletions

View File

@@ -1,8 +1,10 @@
use crate::{keys, utils}; use crate::{keys, utils};
use bdk::bitcoin::bip32::ExtendedPrivKey;
use bdk::bitcoin::psbt::PartiallySignedTransaction; use bdk::bitcoin::psbt::PartiallySignedTransaction;
use bdk::blockchain::Blockchain; use bdk::bitcoin::Network;
use bdk::database::MemoryDatabase; use bdk::database::MemoryDatabase;
use bdk::template::Bip84;
use bdk::wallet::AddressIndex::{self, New}; use bdk::wallet::AddressIndex::{self, New};
use bdk::wallet::AddressInfo; use bdk::wallet::AddressInfo;
use bdk::{blockchain::ElectrumBlockchain, electrum_client, SyncOptions}; use bdk::{blockchain::ElectrumBlockchain, electrum_client, SyncOptions};
@@ -11,8 +13,11 @@ use bdk::{FeeRate, SignOptions, TransactionDetails, Wallet};
pub async fn run() -> Result<(), anyhow::Error> { pub async fn run() -> Result<(), anyhow::Error> {
let dave = utils::home(&"dave".to_string()); let dave = utils::home(&"dave".to_string());
let sammy = utils::home(&"sammy".to_string()); let sammy = utils::home(&"sammy".to_string());
let dave_wallet = keys::bitcoin::load_from_file(&dave).unwrap(); let dave_keys = keys::bitcoin::load_from_file(&dave).unwrap();
let sammy_wallet = keys::bitcoin::load_from_file(&sammy).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 dave_address = dave_wallet.get_address(AddressIndex::Peek(0))?.to_string();
let sammy_address = sammy_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); println!("About to sign the transaction: {:?}", details);
dave_wallet.sign(&mut psbt, SignOptions::default())?; dave_wallet.sign(&mut psbt, SignOptions::default())?;
let signed_tx = psbt.extract_tx(); let _signed_tx = psbt.extract_tx();
println!("Broadcasting..."); // println!("Broadcasting...");
blockchain.broadcast(&signed_tx).expect("broadcast error"); // blockchain.broadcast(&signed_tx).expect("broadcast error");
println!("Transaction ID: {:?}", signed_tx.txid()); // println!("Transaction ID: {:?}", signed_tx.txid());
Ok(()) 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<ExtendedPrivKey>, Option<Bip84<ExtendedPrivKey>>),
) -> anyhow::Result<Wallet<MemoryDatabase>> {
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<MemoryDatabase>) { fn display_balance(wallet: &Wallet<MemoryDatabase>) {
println!( println!(
"Wallet balance for {} after syncing: {:?} sats on network {}", "Wallet balance for {} after syncing: {:?} sats on network {}",

View File

@@ -1,13 +1,12 @@
use bdk::{ use bdk::{
bitcoin::Network, bitcoin::{bip32::ExtendedPrivKey, Network},
database::MemoryDatabase,
keys::{ keys::{
bip39::{Language, Mnemonic, WordCount}, bip39::{Language, Mnemonic, WordCount},
DerivableKey, ExtendedKey, GeneratableKey, GeneratedKey, DerivableKey, ExtendedKey, GeneratableKey, GeneratedKey,
}, },
miniscript, miniscript,
template::Bip84, template::Bip84,
KeychainKind, Wallet, KeychainKind,
}; };
use std::{ 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 /// Creates a Signet Bitcoin descriptor wallet from a mnemonic
pub fn create_wallet(mnemonic_words: String) -> anyhow::Result<Wallet<MemoryDatabase>> { pub fn get(
mnemonic_words: String,
) -> anyhow::Result<(Bip84<ExtendedPrivKey>, Option<Bip84<ExtendedPrivKey>>)> {
let mnemonic = Mnemonic::parse(mnemonic_words).unwrap(); let mnemonic = Mnemonic::parse(mnemonic_words).unwrap();
// Generate the extended key // Generate the extended key
@@ -41,20 +42,17 @@ pub fn create_wallet(mnemonic_words: String) -> anyhow::Result<Wallet<MemoryData
// Get private key from the extended key // Get private key from the extended key
let xprv = xkey.into_xprv(Network::Signet).unwrap(); let xprv = xkey.into_xprv(Network::Signet).unwrap();
// Create a BDK wallet using BIP 84 descriptor ("m/84h/1h/0h/0" and "m/84h/1h/0h/1") let external_descriptor = Bip84(xprv, KeychainKind::External);
let wallet = Wallet::new( let internal_descriptor = Some(Bip84(xprv, KeychainKind::Internal));
Bip84(xprv, KeychainKind::External),
Some(Bip84(xprv, KeychainKind::Internal)),
Network::Testnet,
MemoryDatabase::default(),
)?;
Ok(wallet) Ok((external_descriptor, internal_descriptor))
} }
pub(crate) fn load_from_file(side_dir: &PathBuf) -> anyhow::Result<Wallet<MemoryDatabase>> { pub(crate) fn load_from_file(
side_dir: &PathBuf,
) -> anyhow::Result<(Bip84<ExtendedPrivKey>, Option<Bip84<ExtendedPrivKey>>)> {
let mnemonic_path = crate::utils::side_paths(side_dir.clone()).1; // TODO: this tuple stinks 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"); let mnemonic_words = fs::read_to_string(mnemonic_path).expect("couldn't read bitcoin key file");
println!("Creating wallet from mnemonic: {mnemonic_words}"); println!("Creating wallet from mnemonic: {mnemonic_words}");
create_wallet(mnemonic_words) get(mnemonic_words)
} }

View File

@@ -42,7 +42,8 @@ async fn setup(name: &String) -> SideNode {
// First, load up the keys and create a bft-crdt // First, load up the keys and create a bft-crdt
let side_dir = utils::home(name); let side_dir = utils::home(name);
let bft_crdt_keys = keys::bft_crdt::load_from_file(&side_dir); 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::<TransactionList>::new(&bft_crdt_keys); let crdt = BaseCrdt::<TransactionList>::new(&bft_crdt_keys);
// Channels for internal communication, and a tokio task for stdin input // Channels for internal communication, and a tokio task for stdin input

View File

@@ -2,7 +2,13 @@ use bft_json_crdt::{
json_crdt::{BaseCrdt, SignedOp}, json_crdt::{BaseCrdt, SignedOp},
keypair::make_keypair, 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; use tokio::sync::mpsc;
#[tokio::test] #[tokio::test]
@@ -36,7 +42,8 @@ async fn setup(_: &str) -> SideNode {
// First, load up the keys and create a bft-crdt // First, load up the keys and create a bft-crdt
let bft_crdt_keys = make_keypair(); let bft_crdt_keys = make_keypair();
let mnemonic_words = keys::bitcoin::make_mnemonic(); 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::<TransactionList>::new(&bft_crdt_keys); let crdt = BaseCrdt::<TransactionList>::new(&bft_crdt_keys);
// Channels for internal communication, and a tokio task for stdin input // Channels for internal communication, and a tokio task for stdin input