Need help with bdk?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

bitcoindevkit
267 Stars 62 Forks Other 721 Commits 78 Opened issues

Description

A modern, lightweight, descriptor-based wallet library written in Rust!

Services available

!
?

Need anything else?

Contributors list

BDK

A modern, lightweight, descriptor-based wallet library written in Rust!

Crate Info MIT or Apache-2.0 Licensed CI Status API Docs Rustc Version 1.46+ Chat on Discord

Project Homepage | Documentation

About

The

bdk
library aims to be the core building block for Bitcoin wallets of any kind.
  • It uses Miniscript to support descriptors with generalized conditions. This exact same library can be used to build single-sig wallets, multisigs, timelocked contracts and more.
  • It supports multiple blockchain backends and databases, allowing developers to choose exactly what's right for their projects.
  • It's built to be cross-platform: the core logic works on desktop, mobile, and even WebAssembly.
  • It's very easy to extend: developers can implement customized logic for blockchain backends, databases, signers, coin selection, and more, without having to fork and modify this library.

Examples

Sync the balance of a descriptor

use bdk::Wallet;
use bdk::database::MemoryDatabase;
use bdk::blockchain::{noop_progress, ElectrumBlockchain};

use bdk::electrum_client::Client;

fn main() -> Result { let client = Client::new("ssl://electrum.blockstream.info:60002")?; let wallet = Wallet::new( "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/)", Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/)"), bitcoin::Network::Testnet, MemoryDatabase::default(), ElectrumBlockchain::from(client) )?;

wallet.sync(noop_progress(), None)?;

println!("Descriptor balance: {} SAT", wallet.get_balance()?);

Ok(())

}

Generate a few addresses

use bdk::{Wallet, database::MemoryDatabase};
use bdk::wallet::AddressIndex::New;

fn main() -> Result { let wallet = Wallet::new_offline( "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/)", Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/)"), bitcoin::Network::Testnet, MemoryDatabase::default(), )?;

println!("Address #0: {}", wallet.get_address(New)?);
println!("Address #1: {}", wallet.get_address(New)?);
println!("Address #2: {}", wallet.get_address(New)?);

Ok(())

}

Create a transaction

use bdk::{FeeRate, Wallet};
use bdk::database::MemoryDatabase;
use bdk::blockchain::{noop_progress, ElectrumBlockchain};

use bdk::electrum_client::Client; use bdk::wallet::AddressIndex::New;

use bitcoin::consensus::serialize;

fn main() -> Result { let client = Client::new("ssl://electrum.blockstream.info:60002")?; let wallet = Wallet::new( "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/)", Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/)"), bitcoin::Network::Testnet, MemoryDatabase::default(), ElectrumBlockchain::from(client) )?;

wallet.sync(noop_progress(), None)?;

let send_to = wallet.get_address(New)?;
let (psbt, details) = {
    let mut builder = wallet.build_tx();
    builder
        .add_recipient(send_to.script_pubkey(), 50_000)
        .enable_rbf()
        .do_not_spend_change()
        .fee_rate(FeeRate::from_sat_per_vb(5.0));
    builder.finish()?
};

println!("Transaction details: {:#?}", details);
println!("Unsigned PSBT: {}", base64::encode(&serialize(&psbt)));

Ok(())

}

Sign a transaction

use bdk::{Wallet, SignOptions, database::MemoryDatabase};

use bitcoin::consensus::deserialize;

fn main() -> Result { let wallet = Wallet::new_offline( "wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/0/)", Some("wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/1/)"), bitcoin::Network::Testnet, MemoryDatabase::default(), )?;

let psbt = "...";
let mut psbt = deserialize(&base64::decode(psbt).unwrap())?;

let finalized = wallet.sign(&mut psbt, SignOptions::default())?;

Ok(())

}

Testing

Unit testing

cargo test

Integration testing

Integration testing require testing features, for example:

cargo test --features test-electrum

The other options are

test-esplora
or
test-rpc
. Note that
electrs
and
bitcoind
binaries are automatically downloaded (on mac and linux), to specify you already have installed binaries you must use
--no-default-features
and provide
BITCOIND_EXE
and
ELECTRS_EXE
as environment variables.

License

Licensed under either of

  • Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
  • MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.