Skip to content

Instantly share code, notes, and snippets.

@grunch
Last active July 22, 2021 13:30
Show Gist options
  • Save grunch/c0c4caeada1dbec51643a16629652f76 to your computer and use it in GitHub Desktop.
Save grunch/c0c4caeada1dbec51643a16629652f76 to your computer and use it in GitHub Desktop.
miniscript with bdk example
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