Convert to workspace
This commit is contained in:
1 parent
fdfc9b9ede
commit
8a6de3aa2d
39 files changed
+287
-365
No files matched your search
+8
-75
@@ -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"]
|
|
||||||
@@ -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.
|
|
||||||
@@ -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"]
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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.
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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")]
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,7 @@
|
|||||||
|
[package]
|
||||||
|
name = "electrum-wallet-example"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bdk = { path = "../../crates/bdk" }
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
}
|
||||||
@@ -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" }
|
||||||
@@ -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(())
|
|
||||||
}
|
|
||||||
Reference in new issue
Block a user