diff --git a/Cargo.toml b/Cargo.toml index 2143718741..9549e4235c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,76 +1,9 @@ -[package] -name = "bdk" -version = "0.27.0" -edition = "2018" -authors = ["Alekos Filini ", "Riccardo Casatta "] -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] -log = "^0.4" -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"] +[workspace] +members = [ + "crates/bdk", + "example-crates/esplora-wallet", + "example-crates/electrum-wallet", +] + +[workspace.package] +authors = ["Bitcoin Dev Kit Developers"] diff --git a/README.md b/README.md index 95ce43153f..b34a26fe59 100644 --- a/README.md +++ b/README.md @@ -1,197 +1,18 @@ -
-

BDK

+# The Bitcoin Dev Kit - +The `bdk` libraries aims to be the core building block for Bitcoin wallets of any kind. -

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

+The Bitcoin Dev Kit developers are in the process of releasing `v1.0` which is a fundamental +re-write of how the library works. -

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

+See for some background on this project: https://bitcoindevkit.org/blog/road-to-bdk-1/ (ignore the timeline 😁) -

- Project Homepage - | - Documentation -

-
+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. -## 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. diff --git a/crates/bdk/Cargo.toml b/crates/bdk/Cargo.toml new file mode 100644 index 0000000000..9031ff8520 --- /dev/null +++ b/crates/bdk/Cargo.toml @@ -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"] diff --git a/LICENSE b/crates/bdk/LICENSE similarity index 100% rename from LICENSE rename to crates/bdk/LICENSE diff --git a/LICENSE-APACHE b/crates/bdk/LICENSE-APACHE similarity index 100% rename from LICENSE-APACHE rename to crates/bdk/LICENSE-APACHE diff --git a/LICENSE-MIT b/crates/bdk/LICENSE-MIT similarity index 100% rename from LICENSE-MIT rename to crates/bdk/LICENSE-MIT diff --git a/crates/bdk/README.md b/crates/bdk/README.md new file mode 100644 index 0000000000..9531f1cde6 --- /dev/null +++ b/crates/bdk/README.md @@ -0,0 +1,186 @@ +
+

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.57.0+ + 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](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. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +## 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. diff --git a/examples/compiler.rs b/crates/bdk/examples/compiler.rs similarity index 100% rename from examples/compiler.rs rename to crates/bdk/examples/compiler.rs diff --git a/examples/mnemonic_to_descriptors.rs b/crates/bdk/examples/mnemonic_to_descriptors.rs similarity index 100% rename from examples/mnemonic_to_descriptors.rs rename to crates/bdk/examples/mnemonic_to_descriptors.rs diff --git a/examples/policy.rs b/crates/bdk/examples/policy.rs similarity index 100% rename from examples/policy.rs rename to crates/bdk/examples/policy.rs diff --git a/src/descriptor/checksum.rs b/crates/bdk/src/descriptor/checksum.rs similarity index 100% rename from src/descriptor/checksum.rs rename to crates/bdk/src/descriptor/checksum.rs diff --git a/src/descriptor/dsl.rs b/crates/bdk/src/descriptor/dsl.rs similarity index 100% rename from src/descriptor/dsl.rs rename to crates/bdk/src/descriptor/dsl.rs diff --git a/src/descriptor/error.rs b/crates/bdk/src/descriptor/error.rs similarity index 100% rename from src/descriptor/error.rs rename to crates/bdk/src/descriptor/error.rs diff --git a/src/descriptor/mod.rs b/crates/bdk/src/descriptor/mod.rs similarity index 100% rename from src/descriptor/mod.rs rename to crates/bdk/src/descriptor/mod.rs diff --git a/src/descriptor/policy.rs b/crates/bdk/src/descriptor/policy.rs similarity index 100% rename from src/descriptor/policy.rs rename to crates/bdk/src/descriptor/policy.rs diff --git a/src/descriptor/template.rs b/crates/bdk/src/descriptor/template.rs similarity index 100% rename from src/descriptor/template.rs rename to crates/bdk/src/descriptor/template.rs diff --git a/src/doctest.rs b/crates/bdk/src/doctest.rs similarity index 100% rename from src/doctest.rs rename to crates/bdk/src/doctest.rs diff --git a/src/error.rs b/crates/bdk/src/error.rs similarity index 100% rename from src/error.rs rename to crates/bdk/src/error.rs diff --git a/src/keys/bip39.rs b/crates/bdk/src/keys/bip39.rs similarity index 100% rename from src/keys/bip39.rs rename to crates/bdk/src/keys/bip39.rs diff --git a/src/keys/mod.rs b/crates/bdk/src/keys/mod.rs similarity index 100% rename from src/keys/mod.rs rename to crates/bdk/src/keys/mod.rs diff --git a/src/lib.rs b/crates/bdk/src/lib.rs similarity index 99% rename from src/lib.rs rename to crates/bdk/src/lib.rs index f4d73caafe..1d56f64d9c 100644 --- a/src/lib.rs +++ b/crates/bdk/src/lib.rs @@ -93,6 +93,7 @@ //! * `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 //! +//! #![no_std] #[cfg(feature = "std")] diff --git a/src/psbt/mod.rs b/crates/bdk/src/psbt/mod.rs similarity index 100% rename from src/psbt/mod.rs rename to crates/bdk/src/psbt/mod.rs diff --git a/src/types.rs b/crates/bdk/src/types.rs similarity index 100% rename from src/types.rs rename to crates/bdk/src/types.rs diff --git a/src/wallet/coin_selection.rs b/crates/bdk/src/wallet/coin_selection.rs similarity index 100% rename from src/wallet/coin_selection.rs rename to crates/bdk/src/wallet/coin_selection.rs diff --git a/src/wallet/export.rs b/crates/bdk/src/wallet/export.rs similarity index 100% rename from src/wallet/export.rs rename to crates/bdk/src/wallet/export.rs diff --git a/src/wallet/hardwaresigner.rs b/crates/bdk/src/wallet/hardwaresigner.rs similarity index 100% rename from src/wallet/hardwaresigner.rs rename to crates/bdk/src/wallet/hardwaresigner.rs diff --git a/src/wallet/mod.rs b/crates/bdk/src/wallet/mod.rs similarity index 100% rename from src/wallet/mod.rs rename to crates/bdk/src/wallet/mod.rs diff --git a/src/wallet/persist.rs b/crates/bdk/src/wallet/persist.rs similarity index 100% rename from src/wallet/persist.rs rename to crates/bdk/src/wallet/persist.rs diff --git a/src/wallet/signer.rs b/crates/bdk/src/wallet/signer.rs similarity index 100% rename from src/wallet/signer.rs rename to crates/bdk/src/wallet/signer.rs diff --git a/src/wallet/tx_builder.rs b/crates/bdk/src/wallet/tx_builder.rs similarity index 100% rename from src/wallet/tx_builder.rs rename to crates/bdk/src/wallet/tx_builder.rs diff --git a/src/wallet/utils.rs b/crates/bdk/src/wallet/utils.rs similarity index 100% rename from src/wallet/utils.rs rename to crates/bdk/src/wallet/utils.rs diff --git a/tests/common.rs b/crates/bdk/tests/common.rs similarity index 100% rename from tests/common.rs rename to crates/bdk/tests/common.rs diff --git a/tests/psbt.rs b/crates/bdk/tests/psbt.rs similarity index 100% rename from tests/psbt.rs rename to crates/bdk/tests/psbt.rs diff --git a/tests/wallet.rs b/crates/bdk/tests/wallet.rs similarity index 100% rename from tests/wallet.rs rename to crates/bdk/tests/wallet.rs diff --git a/example-crates/electrum-wallet/Cargo.toml b/example-crates/electrum-wallet/Cargo.toml new file mode 100644 index 0000000000..5e230054a1 --- /dev/null +++ b/example-crates/electrum-wallet/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "electrum-wallet-example" +version = "0.1.0" +edition = "2021" + +[dependencies] +bdk = { path = "../../crates/bdk" } diff --git a/example-crates/electrum-wallet/src/main.rs b/example-crates/electrum-wallet/src/main.rs new file mode 100644 index 0000000000..e7a11a969c --- /dev/null +++ b/example-crates/electrum-wallet/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/example-crates/esplora-wallet/Cargo.toml b/example-crates/esplora-wallet/Cargo.toml new file mode 100644 index 0000000000..944f09b300 --- /dev/null +++ b/example-crates/esplora-wallet/Cargo.toml @@ -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" } diff --git a/example-crates/esplora-wallet/src/main.rs b/example-crates/esplora-wallet/src/main.rs new file mode 100644 index 0000000000..e7a11a969c --- /dev/null +++ b/example-crates/esplora-wallet/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/examples/hardware_signer.rs b/examples/hardware_signer.rs deleted file mode 100644 index afaf194848..0000000000 --- a/examples/hardware_signer.rs +++ /dev/null @@ -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> { - 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::>(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(()) -}