Last active
July 22, 2021 13:30
-
-
Save grunch/c0c4caeada1dbec51643a16629652f76 to your computer and use it in GitHub Desktop.
miniscript with bdk example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::str::FromStr; | |
use bitcoin::Address; | |
use bitcoin::util::psbt::PartiallySignedTransaction; | |
use bitcoin::consensus::{encode::serialize}; | |
use anyhow::{Result}; | |
use bdk::{Wallet, database::MemoryDatabase}; | |
use bdk::wallet::{coin_selection::DefaultCoinSelectionAlgorithm}; | |
use bdk::blockchain::{electrum, noop_progress}; | |
use bdk::electrum_client::Client; | |
use bdk::KeychainKind; | |
use bdk::SignOptions; | |
use std::collections::BTreeMap; | |
fn main() { | |
let descriptor = "wsh(or_d(pk([dc342821/87h/1h/0h]tprv8ZgxMBicQKsPedzjvU2gY32Vwbqbsn5tDjgGuNVPvFrJ8p8FzidHcrTMusCpbEVUPEqfJaS9fAnNLwoGsKhH13QzygmHLGR4PAzauA3Z1Ly/0/*),and_v(v:pk([a7bc5042/87h/1h/0h]tprv8ZgxMBicQKsPeGtmpVwHZdvzjYDiP27st4auCCVk3WG8KeS4PqUNxqns5S2gyaRtRGZmYmMY3GD3kgNk47HAueLFKA9NN963B3cLk6MN4qF/0/*),older(25920))))"; | |
// let change_descriptor = "wsh(or_d(pk([dc342821/87h/1h/0h]tprv8ZgxMBicQKsPedzjvU2gY32Vwbqbsn5tDjgGuNVPvFrJ8p8FzidHcrTMusCpbEVUPEqfJaS9fAnNLwoGsKhH13QzygmHLGR4PAzauA3Z1Ly/1/*),and_v(v:pk([a7bc5042/87h/1h/0h]tprv8ZgxMBicQKsPeGtmpVwHZdvzjYDiP27st4auCCVk3WG8KeS4PqUNxqns5S2gyaRtRGZmYmMY3GD3kgNk47HAueLFKA9NN963B3cLk6MN4qF/1/*),older(25920))))"; | |
let destination = "tb1qk3ux994n9fcstcegjkfy8zden8zxtwhqjkwvt2"; | |
let amount = 5000; | |
let response = execute(&descriptor, &destination, amount); | |
println!("{:?}", response); | |
} | |
fn execute(descriptor: &str, destination: &str, amount: u64) -> Result<()> { | |
// building the psbt | |
let wallet = create_wallet(&descriptor, None)?; | |
// let x = wallet.policies(KeychainKind::External).unwrap(); | |
// println!("{:?}", x); I got the id (qch8dkye) from here | |
let mut path = BTreeMap::new(); | |
path.insert("qch8dkye".to_string(), vec![0]); | |
// We parse the address and convert it to a script pubkey | |
let dest_script = Address::from_str(destination)?.script_pubkey(); | |
// Create a transaction builder TxBuilder | |
let mut tx_builder = wallet | |
.build_tx() | |
.coin_selection(DefaultCoinSelectionAlgorithm::default()); | |
// println!("{:?}", tx_builder); | |
// Add our script and the amount in sats to send | |
tx_builder | |
.add_recipient(dest_script, amount) | |
.policy_path(path, KeychainKind::External); | |
// "Finish" the builder which returns a tuple: | |
// A `PartiallySignedTransaction` which serializes as a psbt | |
// And `TransactionDetails` which has helpful info about the transaction we just built | |
let (psbt, details) = tx_builder.finish()?; | |
println!("{:#?}", details); | |
println!("================ PSBT ================"); | |
println!("{}", base64::encode(&serialize(&psbt))); | |
println!("================ PSBT ================"); | |
// here we broadcast | |
let mut psbt: PartiallySignedTransaction = psbt; | |
// Default options for finalizing the transaction | |
let sign_options = SignOptions::default(); | |
wallet.finalize_psbt(&mut psbt, sign_options)?; | |
// Get the transaction out of the PSBT so we can broadcast it | |
let tx = psbt.extract_tx(); | |
// Broadcast the transaction using our chosen backend, returning a `Txid` or an error | |
let txid = wallet.broadcast(tx)?; | |
println!("{:#?}", txid); | |
Ok(()) | |
} | |
fn create_wallet( | |
desc_string: &str, | |
change_desc: Option<&str>, | |
) -> Result<Wallet<electrum::ElectrumBlockchain, MemoryDatabase>> { | |
// Create a SSL-encrypted Electrum client | |
let client = Client::new("ssl://electrum.blockstream.info:60002")?; | |
// Create a BDK wallet | |
let wallet = Wallet::new( | |
// Our wallet descriptor | |
desc_string, | |
// Descriptor used for generating change addresses | |
change_desc, | |
// Which network we'll using. If you change this to `Bitcoin` things get real. | |
bitcoin::Network::Testnet, | |
// In-memory ephemeral database. There's also a default key value storage provided by BDK if you want persistence. | |
MemoryDatabase::default(), | |
// This wrapper implements the blockchain traits BDK needs for this specific client type | |
electrum::ElectrumBlockchain::from(client), | |
)?; | |
println!("Syncing..."); | |
// Important! We have to sync our wallet with the blockchain. | |
// Because our wallet is ephemeral we need to do this on each run, so I put it in `create_wallet` for convenience. | |
wallet.sync(noop_progress(), None)?; | |
Ok(wallet) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment