Convert to workspace
This commit is contained in:
parent
fdfc9b9ede
commit
8a6de3aa2d
83
Cargo.toml
83
Cargo.toml
@ -1,76 +1,9 @@
|
|||||||
[package]
|
[workspace]
|
||||||
name = "bdk"
|
members = [
|
||||||
version = "0.27.1"
|
"crates/bdk",
|
||||||
edition = "2018"
|
"example-crates/esplora-wallet",
|
||||||
authors = ["Alekos Filini <alekos.filini@gmail.com>", "Riccardo Casatta <riccardo@casatta.it>"]
|
"example-crates/electrum-wallet",
|
||||||
homepage = "https://bitcoindevkit.org"
|
]
|
||||||
repository = "https://github.com/bitcoindevkit/bdk"
|
|
||||||
documentation = "https://docs.rs/bdk"
|
|
||||||
description = "A modern, lightweight, descriptor-based wallet library"
|
|
||||||
keywords = ["bitcoin", "wallet", "descriptor", "psbt"]
|
|
||||||
readme = "README.md"
|
|
||||||
license = "MIT OR Apache-2.0"
|
|
||||||
# TODO: remove this when examples all work
|
|
||||||
autoexamples = false
|
|
||||||
|
|
||||||
[dependencies]
|
[workspace.package]
|
||||||
log = "^0.4"
|
authors = ["Bitcoin Dev Kit Developers"]
|
||||||
miniscript = { version = "9", features = ["serde"] }
|
|
||||||
bitcoin = { version = "0.29", features = ["serde", "base64", "rand"] }
|
|
||||||
serde = { version = "^1.0", features = ["derive"] }
|
|
||||||
serde_json = { version = "^1.0" }
|
|
||||||
bdk_chain = { version = "0.1", features = ["miniscript", "serde"] }
|
|
||||||
rand = "^0.8"
|
|
||||||
|
|
||||||
# Optional dependencies
|
|
||||||
hwi = { version = "0.5", optional = true, features = [ "use-miniscript"] }
|
|
||||||
bip39 = { version = "1.0.1", optional = true }
|
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
|
||||||
getrandom = "0.2"
|
|
||||||
js-sys = "0.3"
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["std"]
|
|
||||||
std = []
|
|
||||||
file-store = [ "std", "bdk_chain/file_store"]
|
|
||||||
compiler = ["miniscript/compiler"]
|
|
||||||
all-keys = ["keys-bip39"]
|
|
||||||
keys-bip39 = ["bip39"]
|
|
||||||
hardware-signer = ["hwi"]
|
|
||||||
|
|
||||||
# Debug/Test features
|
|
||||||
test-md-docs = []
|
|
||||||
test-hardware-signer = ["hardware-signer"]
|
|
||||||
|
|
||||||
# This feature is used to run `cargo check` in our CI targeting wasm. It's not recommended
|
|
||||||
# for libraries to explicitly include the "getrandom/js" feature, so we only do it when
|
|
||||||
# necessary for running our CI. See: https://docs.rs/getrandom/0.2.8/getrandom/#webassembly-support
|
|
||||||
dev-getrandom-wasm = ["getrandom/js"]
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
lazy_static = "1.4"
|
|
||||||
env_logger = "0.7"
|
|
||||||
# Move back to importing from rust-bitcoin once https://github.com/rust-bitcoin/rust-bitcoin/pull/1342 is released
|
|
||||||
base64 = "^0.13"
|
|
||||||
assert_matches = "1.5.0"
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "miniscriptc"
|
|
||||||
path = "examples/compiler.rs"
|
|
||||||
required-features = ["compiler"]
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "policy"
|
|
||||||
path = "examples/policy.rs"
|
|
||||||
required-features = ["std"]
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "mnemonic_to_descriptors"
|
|
||||||
path = "examples/mnemonic_to_descriptors.rs"
|
|
||||||
required-features = ["all-keys"]
|
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
|
||||||
all-features = true
|
|
||||||
# defines the configuration attribute `docsrs`
|
|
||||||
rustdoc-args = ["--cfg", "docsrs"]
|
|
||||||
|
193
README.md
193
README.md
@ -1,197 +1,18 @@
|
|||||||
<div align="center">
|
# The Bitcoin Dev Kit
|
||||||
<h1>BDK</h1>
|
|
||||||
|
|
||||||
<img src="./static/bdk.png" width="220" />
|
The `bdk` libraries aims to be the core building block for Bitcoin wallets of any kind.
|
||||||
|
|
||||||
<p>
|
The Bitcoin Dev Kit developers are in the process of releasing `v1.0` which is a fundamental
|
||||||
<strong>A modern, lightweight, descriptor-based wallet library written in Rust!</strong>
|
re-write of how the library works.
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
See for some background on this project: https://bitcoindevkit.org/blog/road-to-bdk-1/ (ignore the timeline 😁)
|
||||||
<a href="https://crates.io/crates/bdk"><img alt="Crate Info" src="https://img.shields.io/crates/v/bdk.svg"/></a>
|
|
||||||
<a href="https://github.com/bitcoindevkit/bdk/blob/master/LICENSE"><img alt="MIT or Apache-2.0 Licensed" src="https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg"/></a>
|
|
||||||
<a href="https://github.com/bitcoindevkit/bdk/actions?query=workflow%3ACI"><img alt="CI Status" src="https://github.com/bitcoindevkit/bdk/workflows/CI/badge.svg"></a>
|
|
||||||
<a href="https://coveralls.io/github/bitcoindevkit/bdk?branch=master"><img src="https://coveralls.io/repos/github/bitcoindevkit/bdk/badge.svg?branch=master"/></a>
|
|
||||||
<a href="https://docs.rs/bdk"><img alt="API Docs" src="https://img.shields.io/badge/docs.rs-bdk-green"/></a>
|
|
||||||
<a href="https://blog.rust-lang.org/2021/12/02/Rust-1.57.0.html"><img alt="Rustc Version 1.57.0+" src="https://img.shields.io/badge/rustc-1.57.0%2B-lightgrey.svg"/></a>
|
|
||||||
<a href="https://discord.gg/d7NkDKm"><img alt="Chat on Discord" src="https://img.shields.io/discord/753336465005608961?logo=discord"></a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h4>
|
For a release timeline see the [`bdk_core_staging`] repo where a lot of the component work is being done. The plan is that everything in the `bdk_core_staging` repo will be moved into the `crates` directory here.
|
||||||
<a href="https://bitcoindevkit.org">Project Homepage</a>
|
|
||||||
<span> | </span>
|
|
||||||
<a href="https://docs.rs/bdk">Documentation</a>
|
|
||||||
</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## About
|
|
||||||
|
|
||||||
The `bdk` library aims to be the core building block for Bitcoin wallets of any kind.
|
[`bdk_core_staging`]: https://github.com/LLFourn/bdk_core_staging
|
||||||
|
|
||||||
* It uses [Miniscript](https://github.com/rust-bitcoin/rust-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
|
|
||||||
|
|
||||||
```rust,no_run
|
|
||||||
use bdk::Wallet;
|
|
||||||
use bdk::blockchain::ElectrumBlockchain;
|
|
||||||
use bdk::SyncOptions;
|
|
||||||
use bdk::electrum_client::Client;
|
|
||||||
use bdk::bitcoin::Network;
|
|
||||||
|
|
||||||
fn main() -> Result<(), bdk::Error> {
|
|
||||||
let blockchain = ElectrumBlockchain::from(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/*)"),
|
|
||||||
Network::Testnet,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
wallet.sync(&blockchain, SyncOptions::default())?;
|
|
||||||
|
|
||||||
println!("Descriptor balance: {} SAT", wallet.get_balance()?);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Generate a few addresses
|
|
||||||
|
|
||||||
```rust
|
|
||||||
use bdk::Wallet;
|
|
||||||
use bdk::wallet::AddressIndex::New;
|
|
||||||
use bdk::bitcoin::Network;
|
|
||||||
|
|
||||||
fn main() -> Result<(), bdk::Error> {
|
|
||||||
let wallet = Wallet::new_no_persist(
|
|
||||||
"wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)",
|
|
||||||
Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)"),
|
|
||||||
Network::Testnet,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
```rust,no_run
|
|
||||||
use bdk::{FeeRate, Wallet, SyncOptions};
|
|
||||||
use bdk::blockchain::ElectrumBlockchain;
|
|
||||||
|
|
||||||
use bdk::electrum_client::Client;
|
|
||||||
use bdk::wallet::AddressIndex::New;
|
|
||||||
|
|
||||||
use base64;
|
|
||||||
use bdk::bitcoin::consensus::serialize;
|
|
||||||
use bdk::bitcoin::Network;
|
|
||||||
|
|
||||||
fn main() -> Result<(), bdk::Error> {
|
|
||||||
let blockchain = ElectrumBlockchain::from(Client::new("ssl://electrum.blockstream.info:60002")?);
|
|
||||||
let wallet = Wallet::new_no_persist(
|
|
||||||
"wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)",
|
|
||||||
Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)"),
|
|
||||||
Network::Testnet,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
wallet.sync(&blockchain, SyncOptions::default())?;
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
```rust,no_run
|
|
||||||
use bdk::{Wallet, SignOptions};
|
|
||||||
|
|
||||||
use base64;
|
|
||||||
use bdk::bitcoin::consensus::deserialize;
|
|
||||||
use bdk::bitcoin::Network;
|
|
||||||
|
|
||||||
fn main() -> Result<(), bdk::Error> {
|
|
||||||
let wallet = Wallet::new_no_persist(
|
|
||||||
"wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/0/*)",
|
|
||||||
Some("wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/1/*)"),
|
|
||||||
Network::Testnet,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let psbt = "...";
|
|
||||||
let mut psbt = deserialize(&base64::decode(psbt).unwrap())?;
|
|
||||||
|
|
||||||
let _finalized = wallet.sign(&mut psbt, SignOptions::default())?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
### Unit testing
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cargo test
|
|
||||||
```
|
|
||||||
|
|
||||||
### Integration testing
|
|
||||||
|
|
||||||
Integration testing require testing features, for example:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cargo test --features test-electrum
|
|
||||||
```
|
|
||||||
|
|
||||||
The other options are `test-esplora`, `test-rpc` or `test-rpc-legacy` which runs against an older version of Bitcoin Core.
|
|
||||||
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.
|
|
||||||
|
|
||||||
## Running under WASM
|
|
||||||
|
|
||||||
If you want to run this library under WASM you will probably have to add the following lines to you `Cargo.toml`:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[dependencies]
|
|
||||||
getrandom = { version = "0.2", features = ["js"] }
|
|
||||||
```
|
|
||||||
|
|
||||||
This enables the `rand` crate to work in environments where JavaScript is available. See [this link](https://docs.rs/getrandom/0.2.8/getrandom/#webassembly-support) to learn more.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
Licensed under either of
|
|
||||||
|
|
||||||
* Apache License, Version 2.0
|
|
||||||
([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||||
* MIT license
|
|
||||||
([LICENSE-MIT](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.
|
|
||||||
|
63
crates/bdk/Cargo.toml
Normal file
63
crates/bdk/Cargo.toml
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
[package]
|
||||||
|
name = "bdk"
|
||||||
|
homepage = "https://bitcoindevkit.org"
|
||||||
|
version = "1.0.0-alpha.0"
|
||||||
|
repository = "https://github.com/bitcoindevkit/bdk"
|
||||||
|
documentation = "https://docs.rs/bdk"
|
||||||
|
description = "A modern, lightweight, descriptor-based wallet library"
|
||||||
|
keywords = ["bitcoin", "wallet", "descriptor", "psbt"]
|
||||||
|
readme = "README.md"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
authors.workspace = true
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
log = "^0.4"
|
||||||
|
rand = "^0.8"
|
||||||
|
miniscript = { version = "9", features = ["serde"] }
|
||||||
|
bitcoin = { version = "0.29", features = ["serde", "base64", "rand"] }
|
||||||
|
serde = { version = "^1.0", features = ["derive"] }
|
||||||
|
serde_json = { version = "^1.0" }
|
||||||
|
bdk_chain = { version = "0.1", features = ["miniscript", "serde"] }
|
||||||
|
|
||||||
|
# Optional dependencies
|
||||||
|
hwi = { version = "0.5", optional = true, features = [ "use-miniscript"] }
|
||||||
|
bip39 = { version = "1.0.1", optional = true }
|
||||||
|
|
||||||
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
|
getrandom = "0.2"
|
||||||
|
js-sys = "0.3"
|
||||||
|
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["std"]
|
||||||
|
std = []
|
||||||
|
file-store = [ "std", "bdk_chain/file_store"]
|
||||||
|
compiler = ["miniscript/compiler"]
|
||||||
|
all-keys = ["keys-bip39"]
|
||||||
|
keys-bip39 = ["bip39"]
|
||||||
|
hardware-signer = ["hwi"]
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
lazy_static = "1.4"
|
||||||
|
env_logger = "0.7"
|
||||||
|
# Move back to importing from rust-bitcoin once https://github.com/rust-bitcoin/rust-bitcoin/pull/1342 is released
|
||||||
|
base64 = "^0.13"
|
||||||
|
assert_matches = "1.5.0"
|
||||||
|
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
all-features = true
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "mnemonic_to_descriptors"
|
||||||
|
path = "examples/mnemonic_to_descriptors.rs"
|
||||||
|
required-features = ["all-keys"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "miniscriptc"
|
||||||
|
path = "examples/compiler.rs"
|
||||||
|
required-features = ["compiler"]
|
186
crates/bdk/README.md
Normal file
186
crates/bdk/README.md
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
<div align="center">
|
||||||
|
<h1>BDK</h1>
|
||||||
|
|
||||||
|
<img src="./static/bdk.png" width="220" />
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<strong>A modern, lightweight, descriptor-based wallet library written in Rust!</strong>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a href="https://crates.io/crates/bdk"><img alt="Crate Info" src="https://img.shields.io/crates/v/bdk.svg"/></a>
|
||||||
|
<a href="https://github.com/bitcoindevkit/bdk/blob/master/LICENSE"><img alt="MIT or Apache-2.0 Licensed" src="https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg"/></a>
|
||||||
|
<a href="https://github.com/bitcoindevkit/bdk/actions?query=workflow%3ACI"><img alt="CI Status" src="https://github.com/bitcoindevkit/bdk/workflows/CI/badge.svg"></a>
|
||||||
|
<a href="https://coveralls.io/github/bitcoindevkit/bdk?branch=master"><img src="https://coveralls.io/repos/github/bitcoindevkit/bdk/badge.svg?branch=master"/></a>
|
||||||
|
<a href="https://docs.rs/bdk"><img alt="API Docs" src="https://img.shields.io/badge/docs.rs-bdk-green"/></a>
|
||||||
|
<a href="https://blog.rust-lang.org/2021/12/02/Rust-1.57.0.html"><img alt="Rustc Version 1.57.0+" src="https://img.shields.io/badge/rustc-1.57.0%2B-lightgrey.svg"/></a>
|
||||||
|
<a href="https://discord.gg/d7NkDKm"><img alt="Chat on Discord" src="https://img.shields.io/discord/753336465005608961?logo=discord"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h4>
|
||||||
|
<a href="https://bitcoindevkit.org">Project Homepage</a>
|
||||||
|
<span> | </span>
|
||||||
|
<a href="https://docs.rs/bdk">Documentation</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## About
|
||||||
|
|
||||||
|
The `bdk` library aims to be the core building block for Bitcoin wallets of any kind.
|
||||||
|
|
||||||
|
* It uses [Miniscript](https://github.com/rust-bitcoin/rust-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 -->
|
||||||
|
|
||||||
|
<!-- ```rust,no_run -->
|
||||||
|
<!-- use bdk::Wallet; -->
|
||||||
|
<!-- use bdk::blockchain::ElectrumBlockchain; -->
|
||||||
|
<!-- use bdk::SyncOptions; -->
|
||||||
|
<!-- use bdk::electrum_client::Client; -->
|
||||||
|
<!-- use bdk::bitcoin::Network; -->
|
||||||
|
|
||||||
|
<!-- fn main() -> Result<(), bdk::Error> { -->
|
||||||
|
<!-- let blockchain = ElectrumBlockchain::from(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/*)"), -->
|
||||||
|
<!-- Network::Testnet, -->
|
||||||
|
<!-- )?; -->
|
||||||
|
|
||||||
|
<!-- wallet.sync(&blockchain, SyncOptions::default())?; -->
|
||||||
|
|
||||||
|
<!-- println!("Descriptor balance: {} SAT", wallet.get_balance()?); -->
|
||||||
|
|
||||||
|
<!-- Ok(()) -->
|
||||||
|
<!-- } -->
|
||||||
|
<!-- ``` -->
|
||||||
|
|
||||||
|
<!-- ### Generate a few addresses -->
|
||||||
|
|
||||||
|
<!-- ```rust -->
|
||||||
|
<!-- use bdk::Wallet; -->
|
||||||
|
<!-- use bdk::wallet::AddressIndex::New; -->
|
||||||
|
<!-- use bdk::bitcoin::Network; -->
|
||||||
|
|
||||||
|
<!-- fn main() -> Result<(), bdk::Error> { -->
|
||||||
|
<!-- let wallet = Wallet::new_no_persist( -->
|
||||||
|
<!-- "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)", -->
|
||||||
|
<!-- Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)"), -->
|
||||||
|
<!-- Network::Testnet, -->
|
||||||
|
<!-- )?; -->
|
||||||
|
|
||||||
|
<!-- 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 -->
|
||||||
|
|
||||||
|
<!-- ```rust,no_run -->
|
||||||
|
<!-- use bdk::{FeeRate, Wallet, SyncOptions}; -->
|
||||||
|
<!-- use bdk::blockchain::ElectrumBlockchain; -->
|
||||||
|
|
||||||
|
<!-- use bdk::electrum_client::Client; -->
|
||||||
|
<!-- use bdk::wallet::AddressIndex::New; -->
|
||||||
|
|
||||||
|
<!-- use base64; -->
|
||||||
|
<!-- use bdk::bitcoin::consensus::serialize; -->
|
||||||
|
<!-- use bdk::bitcoin::Network; -->
|
||||||
|
|
||||||
|
<!-- fn main() -> Result<(), bdk::Error> { -->
|
||||||
|
<!-- let blockchain = ElectrumBlockchain::from(Client::new("ssl://electrum.blockstream.info:60002")?); -->
|
||||||
|
<!-- let wallet = Wallet::new_no_persist( -->
|
||||||
|
<!-- "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)", -->
|
||||||
|
<!-- Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)"), -->
|
||||||
|
<!-- Network::Testnet, -->
|
||||||
|
<!-- )?; -->
|
||||||
|
|
||||||
|
<!-- wallet.sync(&blockchain, SyncOptions::default())?; -->
|
||||||
|
|
||||||
|
<!-- 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 -->
|
||||||
|
|
||||||
|
<!-- ```rust,no_run -->
|
||||||
|
<!-- use bdk::{Wallet, SignOptions}; -->
|
||||||
|
|
||||||
|
<!-- use base64; -->
|
||||||
|
<!-- use bdk::bitcoin::consensus::deserialize; -->
|
||||||
|
<!-- use bdk::bitcoin::Network; -->
|
||||||
|
|
||||||
|
<!-- fn main() -> Result<(), bdk::Error> { -->
|
||||||
|
<!-- let wallet = Wallet::new_no_persist( -->
|
||||||
|
<!-- "wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/0/*)", -->
|
||||||
|
<!-- Some("wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/1/*)"), -->
|
||||||
|
<!-- Network::Testnet, -->
|
||||||
|
<!-- )?; -->
|
||||||
|
|
||||||
|
<!-- let psbt = "..."; -->
|
||||||
|
<!-- let mut psbt = deserialize(&base64::decode(psbt).unwrap())?; -->
|
||||||
|
|
||||||
|
<!-- let _finalized = wallet.sign(&mut psbt, SignOptions::default())?; -->
|
||||||
|
|
||||||
|
<!-- Ok(()) -->
|
||||||
|
<!-- } -->
|
||||||
|
<!-- ``` -->
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
### Unit testing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo test
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running under WASM
|
||||||
|
|
||||||
|
If you want to run this library under WASM you will probably have to add the following lines to you `Cargo.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
getrandom = { version = "0.2", features = ["js"] }
|
||||||
|
```
|
||||||
|
|
||||||
|
This enables the `rand` crate to work in environments where JavaScript is available. See [this link](https://docs.rs/getrandom/0.2.8/getrandom/#webassembly-support) to learn more.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Licensed under either of
|
||||||
|
|
||||||
|
* Apache License, Version 2.0
|
||||||
|
([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
* MIT license
|
||||||
|
([LICENSE-MIT](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.
|
@ -92,7 +92,6 @@
|
|||||||
//! * `all-keys`: all features for working with bitcoin keys
|
//! * `all-keys`: all features for working with bitcoin keys
|
||||||
//! * `async-interface`: async functions in bdk traits
|
//! * `async-interface`: async functions in bdk traits
|
||||||
//! * `keys-bip39`: [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) mnemonic codes for generating deterministic keys
|
//! * `keys-bip39`: [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) mnemonic codes for generating deterministic keys
|
||||||
//!
|
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
7
example-crates/electrum-wallet/Cargo.toml
Normal file
7
example-crates/electrum-wallet/Cargo.toml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[package]
|
||||||
|
name = "electrum-wallet-example"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bdk = { path = "../../crates/bdk" }
|
3
example-crates/electrum-wallet/src/main.rs
Normal file
3
example-crates/electrum-wallet/src/main.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
}
|
10
example-crates/esplora-wallet/Cargo.toml
Normal file
10
example-crates/esplora-wallet/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "bdk-esplora-wallet-example"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bdk = { path = "../../crates/bdk" }
|
3
example-crates/esplora-wallet/src/main.rs
Normal file
3
example-crates/esplora-wallet/src/main.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
}
|
@ -1,103 +0,0 @@
|
|||||||
use bdk::bitcoin::{Address, Network};
|
|
||||||
use bdk::blockchain::{Blockchain, ElectrumBlockchain};
|
|
||||||
use bdk::hwi::{types::HWIChain, HWIClient};
|
|
||||||
use bdk::miniscript::{Descriptor, DescriptorPublicKey};
|
|
||||||
use bdk::signer::SignerOrdering;
|
|
||||||
use bdk::wallet::{hardwaresigner::HWISigner, AddressIndex};
|
|
||||||
use bdk::{FeeRate, KeychainKind, SignOptions, SyncOptions, Wallet};
|
|
||||||
use electrum_client::Client;
|
|
||||||
use std::str::FromStr;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
// This example shows how to sync a wallet, create a transaction, sign it
|
|
||||||
// and broadcast it using an external hardware wallet.
|
|
||||||
// The hardware wallet must be connected to the computer and unlocked before
|
|
||||||
// running the example. Also, the `hwi` python package should be installed
|
|
||||||
// and available in the environment.
|
|
||||||
//
|
|
||||||
// To avoid loss of funds, consider using an hardware wallet simulator:
|
|
||||||
// * Coldcard: https://github.com/Coldcard/firmware
|
|
||||||
// * Ledger: https://github.com/LedgerHQ/speculos
|
|
||||||
// * Trezor: https://docs.trezor.io/trezor-firmware/core/emulator/index.html
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
println!("Hold tight, I'm connecting to your hardware wallet...");
|
|
||||||
|
|
||||||
// Listing all the available hardware wallet devices...
|
|
||||||
let mut devices = HWIClient::enumerate()?;
|
|
||||||
if devices.is_empty() {
|
|
||||||
panic!("No devices found. Either plug in a hardware wallet, or start a simulator.");
|
|
||||||
}
|
|
||||||
let first_device = devices.remove(0)?;
|
|
||||||
// ...and creating a client out of the first one
|
|
||||||
let client = HWIClient::get_client(&first_device, true, HWIChain::Test)?;
|
|
||||||
println!("Look what I found, a {}!", first_device.model);
|
|
||||||
|
|
||||||
// Getting the HW's public descriptors
|
|
||||||
let descriptors = client.get_descriptors::<Descriptor<DescriptorPublicKey>>(None)?;
|
|
||||||
println!(
|
|
||||||
"The hardware wallet's descriptor is: {}",
|
|
||||||
descriptors.receive[0]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Creating a custom signer from the device
|
|
||||||
let custom_signer = HWISigner::from_device(&first_device, HWIChain::Test)?;
|
|
||||||
let mut wallet = Wallet::new_no_persist(
|
|
||||||
descriptors.receive[0].clone(),
|
|
||||||
Some(descriptors.internal[0].clone()),
|
|
||||||
Network::Testnet,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Adding the hardware signer to the BDK wallet
|
|
||||||
wallet.add_signer(
|
|
||||||
KeychainKind::External,
|
|
||||||
SignerOrdering(200),
|
|
||||||
Arc::new(custom_signer),
|
|
||||||
);
|
|
||||||
|
|
||||||
// create client for Blockstream's testnet electrum server
|
|
||||||
let blockchain =
|
|
||||||
ElectrumBlockchain::from(Client::new("ssl://electrum.blockstream.info:60002")?);
|
|
||||||
|
|
||||||
println!("Syncing the wallet...");
|
|
||||||
wallet.sync(&blockchain, SyncOptions::default())?;
|
|
||||||
|
|
||||||
// get deposit address
|
|
||||||
let deposit_address = wallet.get_address(AddressIndex::New);
|
|
||||||
|
|
||||||
let balance = wallet.get_balance()?;
|
|
||||||
println!("Wallet balances in SATs: {}", balance);
|
|
||||||
|
|
||||||
if balance.get_total() < 10000 {
|
|
||||||
println!(
|
|
||||||
"Send some sats from the u01.net testnet faucet to address '{addr}'.\nFaucet URL: https://bitcoinfaucet.uo1.net/?to={addr}",
|
|
||||||
addr = deposit_address.address
|
|
||||||
);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let return_address = Address::from_str("tb1ql7w62elx9ucw4pj5lgw4l028hmuw80sndtntxt")?;
|
|
||||||
let (mut psbt, _details) = {
|
|
||||||
let mut builder = wallet.build_tx();
|
|
||||||
builder
|
|
||||||
.drain_wallet()
|
|
||||||
.drain_to(return_address.script_pubkey())
|
|
||||||
.enable_rbf()
|
|
||||||
.fee_rate(FeeRate::from_sat_per_vb(5.0));
|
|
||||||
builder.finish()?
|
|
||||||
};
|
|
||||||
|
|
||||||
// `sign` will call the hardware wallet asking for a signature
|
|
||||||
assert!(
|
|
||||||
wallet.sign(&mut psbt, SignOptions::default())?,
|
|
||||||
"The hardware wallet couldn't finalize the transaction :("
|
|
||||||
);
|
|
||||||
|
|
||||||
println!("Let's broadcast your tx...");
|
|
||||||
let raw_transaction = psbt.extract_tx();
|
|
||||||
let txid = raw_transaction.txid();
|
|
||||||
|
|
||||||
blockchain.broadcast(&raw_transaction)?;
|
|
||||||
println!("Transaction broadcasted! TXID: {txid}.\nExplorer URL: https://mempool.space/testnet/tx/{txid}", txid = txid);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user