Use () to indicate a missing blockchain
So that: 1. There are no runtime errors 2. There less type annotations needed 3. Less traits and stuff to document
This commit is contained in:
parent
2e222c7ad9
commit
656c9c9da8
@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
- Remove `BlockchainMarker`, `OfflineClient` and `OfflineWallet` in favor of just using the unit
|
||||||
|
type to mark for a missing client.
|
||||||
|
|
||||||
## [v0.2.0] - [0.1.0-beta.1]
|
## [v0.2.0] - [0.1.0-beta.1]
|
||||||
|
|
||||||
### Project
|
### Project
|
||||||
|
10
README.md
10
README.md
@ -66,11 +66,10 @@ fn main() -> Result<(), bdk::Error> {
|
|||||||
### Generate a few addresses
|
### Generate a few addresses
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use bdk::{Wallet, OfflineWallet};
|
use bdk::{Wallet, database::MemoryDatabase};
|
||||||
use bdk::database::MemoryDatabase;
|
|
||||||
|
|
||||||
fn main() -> Result<(), bdk::Error> {
|
fn main() -> Result<(), bdk::Error> {
|
||||||
let wallet: OfflineWallet<_> = Wallet::new_offline(
|
let wallet = Wallet::new_offline(
|
||||||
"wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)",
|
"wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)",
|
||||||
Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)"),
|
Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)"),
|
||||||
bitcoin::Network::Testnet,
|
bitcoin::Network::Testnet,
|
||||||
@ -126,13 +125,12 @@ fn main() -> Result<(), bdk::Error> {
|
|||||||
### Sign a transaction
|
### Sign a transaction
|
||||||
|
|
||||||
```rust,no_run
|
```rust,no_run
|
||||||
use bdk::{Wallet, OfflineWallet};
|
use bdk::{Wallet, database::MemoryDatabase};
|
||||||
use bdk::database::MemoryDatabase;
|
|
||||||
|
|
||||||
use bitcoin::consensus::deserialize;
|
use bitcoin::consensus::deserialize;
|
||||||
|
|
||||||
fn main() -> Result<(), bdk::Error> {
|
fn main() -> Result<(), bdk::Error> {
|
||||||
let wallet: OfflineWallet<_> = Wallet::new_offline(
|
let wallet = Wallet::new_offline(
|
||||||
"wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/0/*)",
|
"wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/0/*)",
|
||||||
Some("wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/1/*)"),
|
Some("wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/1/*)"),
|
||||||
bitcoin::Network::Testnet,
|
bitcoin::Network::Testnet,
|
||||||
|
@ -29,7 +29,7 @@ use bdk::database::MemoryDatabase;
|
|||||||
use bdk::descriptor::HDKeyPaths;
|
use bdk::descriptor::HDKeyPaths;
|
||||||
use bdk::wallet::address_validator::{AddressValidator, AddressValidatorError};
|
use bdk::wallet::address_validator::{AddressValidator, AddressValidatorError};
|
||||||
use bdk::KeychainKind;
|
use bdk::KeychainKind;
|
||||||
use bdk::{OfflineWallet, Wallet};
|
use bdk::Wallet;
|
||||||
|
|
||||||
use bitcoin::hashes::hex::FromHex;
|
use bitcoin::hashes::hex::FromHex;
|
||||||
use bitcoin::util::bip32::Fingerprint;
|
use bitcoin::util::bip32::Fingerprint;
|
||||||
@ -59,7 +59,7 @@ impl AddressValidator for DummyValidator {
|
|||||||
|
|
||||||
fn main() -> Result<(), bdk::Error> {
|
fn main() -> Result<(), bdk::Error> {
|
||||||
let descriptor = "sh(and_v(v:pk(tpubDDpWvmUrPZrhSPmUzCMBHffvC3HyMAPnWDSAQNBTnj1iZeJa7BZQEttFiP4DS4GCcXQHezdXhn86Hj6LHX5EDstXPWrMaSneRWM8yUf6NFd/*),after(630000)))";
|
let descriptor = "sh(and_v(v:pk(tpubDDpWvmUrPZrhSPmUzCMBHffvC3HyMAPnWDSAQNBTnj1iZeJa7BZQEttFiP4DS4GCcXQHezdXhn86Hj6LHX5EDstXPWrMaSneRWM8yUf6NFd/*),after(630000)))";
|
||||||
let mut wallet: OfflineWallet<_> =
|
let mut wallet =
|
||||||
Wallet::new_offline(descriptor, None, Network::Regtest, MemoryDatabase::new())?;
|
Wallet::new_offline(descriptor, None, Network::Regtest, MemoryDatabase::new())?;
|
||||||
|
|
||||||
wallet.add_address_validator(Arc::new(DummyValidator));
|
wallet.add_address_validator(Arc::new(DummyValidator));
|
||||||
|
@ -40,7 +40,7 @@ use miniscript::policy::Concrete;
|
|||||||
use miniscript::Descriptor;
|
use miniscript::Descriptor;
|
||||||
|
|
||||||
use bdk::database::memory::MemoryDatabase;
|
use bdk::database::memory::MemoryDatabase;
|
||||||
use bdk::{KeychainKind, OfflineWallet, Wallet};
|
use bdk::{KeychainKind, Wallet};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
env_logger::init_from_env(
|
env_logger::init_from_env(
|
||||||
@ -98,8 +98,7 @@ fn main() {
|
|||||||
Some("regtest") => Network::Regtest,
|
Some("regtest") => Network::Regtest,
|
||||||
Some("testnet") | _ => Network::Testnet,
|
Some("testnet") | _ => Network::Testnet,
|
||||||
};
|
};
|
||||||
let wallet: OfflineWallet<_> =
|
let wallet = Wallet::new_offline(&format!("{}", descriptor), None, network, database).unwrap();
|
||||||
Wallet::new_offline(&format!("{}", descriptor), None, network, database).unwrap();
|
|
||||||
|
|
||||||
info!("... First address: {}", wallet.get_new_address().unwrap());
|
info!("... First address: {}", wallet.get_new_address().unwrap());
|
||||||
|
|
||||||
|
@ -79,29 +79,9 @@ pub enum Capability {
|
|||||||
AccurateFees,
|
AccurateFees,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Marker trait for a blockchain backend
|
|
||||||
///
|
|
||||||
/// This is a marker trait for blockchain types. It is automatically implemented for types that
|
|
||||||
/// implement [`Blockchain`], so as a user of the library you won't have to implement this
|
|
||||||
/// manually.
|
|
||||||
///
|
|
||||||
/// Users of the library will probably never have to implement this trait manually, but they
|
|
||||||
/// could still need to import it to define types and structs with generics;
|
|
||||||
/// Implementing only the marker trait is pointless, since [`OfflineBlockchain`]
|
|
||||||
/// already does that, and whenever [`Blockchain`] is implemented, the marker trait is also
|
|
||||||
/// automatically implemented by the library.
|
|
||||||
pub trait BlockchainMarker {}
|
|
||||||
|
|
||||||
/// The [`BlockchainMarker`] marker trait is automatically implemented for [`Blockchain`] types
|
|
||||||
impl<T: Blockchain> BlockchainMarker for T {}
|
|
||||||
|
|
||||||
/// Type that only implements [`BlockchainMarker`] and is always "offline"
|
|
||||||
pub struct OfflineBlockchain;
|
|
||||||
impl BlockchainMarker for OfflineBlockchain {}
|
|
||||||
|
|
||||||
/// Trait that defines the actions that must be supported by a blockchain backend
|
/// Trait that defines the actions that must be supported by a blockchain backend
|
||||||
#[maybe_async]
|
#[maybe_async]
|
||||||
pub trait Blockchain: BlockchainMarker {
|
pub trait Blockchain {
|
||||||
/// Return the set of [`Capability`] supported by this backend
|
/// Return the set of [`Capability`] supported by this backend
|
||||||
fn get_capabilities(&self) -> HashSet<Capability>;
|
fn get_capabilities(&self) -> HashSet<Capability>;
|
||||||
|
|
||||||
|
@ -29,20 +29,20 @@
|
|||||||
//!
|
//!
|
||||||
//! ## Example
|
//! ## Example
|
||||||
//!
|
//!
|
||||||
//! In this example, `wallet_memory` and `wallet_sled` have the same type of `Wallet<OfflineBlockchain, AnyDatabase>`.
|
//! In this example, `wallet_memory` and `wallet_sled` have the same type of `Wallet<(), AnyDatabase>`.
|
||||||
//!
|
//!
|
||||||
//! ```no_run
|
//! ```no_run
|
||||||
//! # use bitcoin::Network;
|
//! # use bitcoin::Network;
|
||||||
//! # use bdk::database::{AnyDatabase, MemoryDatabase};
|
//! # use bdk::database::{AnyDatabase, MemoryDatabase};
|
||||||
//! # use bdk::{Wallet, OfflineWallet};
|
//! # use bdk::{Wallet};
|
||||||
//! let memory = MemoryDatabase::default().into();
|
//! let memory = MemoryDatabase::default();
|
||||||
//! let wallet_memory: OfflineWallet<AnyDatabase> =
|
//! let wallet_memory =
|
||||||
//! Wallet::new_offline("...", None, Network::Testnet, memory)?;
|
//! Wallet::new_offline("...", None, Network::Testnet, memory)?;
|
||||||
//!
|
//!
|
||||||
//! # #[cfg(feature = "key-value-db")]
|
//! # #[cfg(feature = "key-value-db")]
|
||||||
//! # {
|
//! # {
|
||||||
//! let sled = sled::open("my-database")?.open_tree("default_tree")?.into();
|
//! let sled = sled::open("my-database")?.open_tree("default_tree")?;
|
||||||
//! let wallet_sled: OfflineWallet<AnyDatabase> =
|
//! let wallet_sled =
|
||||||
//! Wallet::new_offline("...", None, Network::Testnet, sled)?;
|
//! Wallet::new_offline("...", None, Network::Testnet, sled)?;
|
||||||
//! # }
|
//! # }
|
||||||
//! # Ok::<(), bdk::Error>(())
|
//! # Ok::<(), bdk::Error>(())
|
||||||
@ -54,10 +54,10 @@
|
|||||||
//! ```no_run
|
//! ```no_run
|
||||||
//! # use bitcoin::Network;
|
//! # use bitcoin::Network;
|
||||||
//! # use bdk::database::*;
|
//! # use bdk::database::*;
|
||||||
//! # use bdk::{Wallet, OfflineWallet};
|
//! # use bdk::{Wallet};
|
||||||
//! let config = serde_json::from_str("...")?;
|
//! let config = serde_json::from_str("...")?;
|
||||||
//! let database = AnyDatabase::from_config(&config)?;
|
//! let database = AnyDatabase::from_config(&config)?;
|
||||||
//! let wallet: OfflineWallet<_> = Wallet::new_offline("...", None, Network::Testnet, database)?;
|
//! let wallet = Wallet::new_offline("...", None, Network::Testnet, database)?;
|
||||||
//! # Ok::<(), bdk::Error>(())
|
//! # Ok::<(), bdk::Error>(())
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
@ -81,13 +81,13 @@ impl<T: DescriptorTemplate> ToWalletDescriptor for T {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use bdk::bitcoin::{PrivateKey, Network};
|
/// # use bdk::bitcoin::{PrivateKey, Network};
|
||||||
/// # use bdk::{Wallet, OfflineWallet};
|
/// # use bdk::{Wallet};
|
||||||
/// # use bdk::database::MemoryDatabase;
|
/// # use bdk::database::MemoryDatabase;
|
||||||
/// use bdk::template::P2PKH;
|
/// use bdk::template::P2PKH;
|
||||||
///
|
///
|
||||||
/// let key =
|
/// let key =
|
||||||
/// bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
|
/// bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
|
||||||
/// let wallet: OfflineWallet<_> = Wallet::new_offline(
|
/// let wallet = Wallet::new_offline(
|
||||||
/// P2PKH(key),
|
/// P2PKH(key),
|
||||||
/// None,
|
/// None,
|
||||||
/// Network::Testnet,
|
/// Network::Testnet,
|
||||||
@ -114,13 +114,13 @@ impl<K: ToDescriptorKey<Legacy>> DescriptorTemplate for P2PKH<K> {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use bdk::bitcoin::{PrivateKey, Network};
|
/// # use bdk::bitcoin::{PrivateKey, Network};
|
||||||
/// # use bdk::{Wallet, OfflineWallet};
|
/// # use bdk::{Wallet};
|
||||||
/// # use bdk::database::MemoryDatabase;
|
/// # use bdk::database::MemoryDatabase;
|
||||||
/// use bdk::template::P2WPKH_P2SH;
|
/// use bdk::template::P2WPKH_P2SH;
|
||||||
///
|
///
|
||||||
/// let key =
|
/// let key =
|
||||||
/// bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
|
/// bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
|
||||||
/// let wallet: OfflineWallet<_> = Wallet::new_offline(
|
/// let wallet = Wallet::new_offline(
|
||||||
/// P2WPKH_P2SH(key),
|
/// P2WPKH_P2SH(key),
|
||||||
/// None,
|
/// None,
|
||||||
/// Network::Testnet,
|
/// Network::Testnet,
|
||||||
@ -148,13 +148,13 @@ impl<K: ToDescriptorKey<Segwitv0>> DescriptorTemplate for P2WPKH_P2SH<K> {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use bdk::bitcoin::{PrivateKey, Network};
|
/// # use bdk::bitcoin::{PrivateKey, Network};
|
||||||
/// # use bdk::{Wallet, OfflineWallet};
|
/// # use bdk::{Wallet};
|
||||||
/// # use bdk::database::MemoryDatabase;
|
/// # use bdk::database::MemoryDatabase;
|
||||||
/// use bdk::template::P2WPKH;
|
/// use bdk::template::P2WPKH;
|
||||||
///
|
///
|
||||||
/// let key =
|
/// let key =
|
||||||
/// bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
|
/// bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
|
||||||
/// let wallet: OfflineWallet<_> = Wallet::new_offline(
|
/// let wallet = Wallet::new_offline(
|
||||||
/// P2WPKH(key),
|
/// P2WPKH(key),
|
||||||
/// None,
|
/// None,
|
||||||
/// Network::Testnet,
|
/// Network::Testnet,
|
||||||
@ -186,12 +186,12 @@ impl<K: ToDescriptorKey<Segwitv0>> DescriptorTemplate for P2WPKH<K> {
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use std::str::FromStr;
|
/// # use std::str::FromStr;
|
||||||
/// # use bdk::bitcoin::{PrivateKey, Network};
|
/// # use bdk::bitcoin::{PrivateKey, Network};
|
||||||
/// # use bdk::{Wallet, OfflineWallet, KeychainKind};
|
/// # use bdk::{Wallet, KeychainKind};
|
||||||
/// # use bdk::database::MemoryDatabase;
|
/// # use bdk::database::MemoryDatabase;
|
||||||
/// use bdk::template::BIP44;
|
/// use bdk::template::BIP44;
|
||||||
///
|
///
|
||||||
/// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
|
/// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
|
||||||
/// let wallet: OfflineWallet<_> = Wallet::new_offline(
|
/// let wallet = Wallet::new_offline(
|
||||||
/// BIP44(key.clone(), KeychainKind::External),
|
/// BIP44(key.clone(), KeychainKind::External),
|
||||||
/// Some(BIP44(key, KeychainKind::Internal)),
|
/// Some(BIP44(key, KeychainKind::Internal)),
|
||||||
/// Network::Testnet,
|
/// Network::Testnet,
|
||||||
@ -224,13 +224,13 @@ impl<K: DerivableKey<Legacy>> DescriptorTemplate for BIP44<K> {
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use std::str::FromStr;
|
/// # use std::str::FromStr;
|
||||||
/// # use bdk::bitcoin::{PrivateKey, Network};
|
/// # use bdk::bitcoin::{PrivateKey, Network};
|
||||||
/// # use bdk::{Wallet, OfflineWallet, KeychainKind};
|
/// # use bdk::{Wallet, KeychainKind};
|
||||||
/// # use bdk::database::MemoryDatabase;
|
/// # use bdk::database::MemoryDatabase;
|
||||||
/// use bdk::template::BIP44Public;
|
/// use bdk::template::BIP44Public;
|
||||||
///
|
///
|
||||||
/// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU")?;
|
/// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU")?;
|
||||||
/// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?;
|
/// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?;
|
||||||
/// let wallet: OfflineWallet<_> = Wallet::new_offline(
|
/// let wallet = Wallet::new_offline(
|
||||||
/// BIP44Public(key.clone(), fingerprint, KeychainKind::External),
|
/// BIP44Public(key.clone(), fingerprint, KeychainKind::External),
|
||||||
/// Some(BIP44Public(key, fingerprint, KeychainKind::Internal)),
|
/// Some(BIP44Public(key, fingerprint, KeychainKind::Internal)),
|
||||||
/// Network::Testnet,
|
/// Network::Testnet,
|
||||||
@ -260,12 +260,12 @@ impl<K: DerivableKey<Legacy>> DescriptorTemplate for BIP44Public<K> {
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use std::str::FromStr;
|
/// # use std::str::FromStr;
|
||||||
/// # use bdk::bitcoin::{PrivateKey, Network};
|
/// # use bdk::bitcoin::{PrivateKey, Network};
|
||||||
/// # use bdk::{Wallet, OfflineWallet, KeychainKind};
|
/// # use bdk::{Wallet, KeychainKind};
|
||||||
/// # use bdk::database::MemoryDatabase;
|
/// # use bdk::database::MemoryDatabase;
|
||||||
/// use bdk::template::BIP49;
|
/// use bdk::template::BIP49;
|
||||||
///
|
///
|
||||||
/// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
|
/// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
|
||||||
/// let wallet: OfflineWallet<_> = Wallet::new_offline(
|
/// let wallet = Wallet::new_offline(
|
||||||
/// BIP49(key.clone(), KeychainKind::External),
|
/// BIP49(key.clone(), KeychainKind::External),
|
||||||
/// Some(BIP49(key, KeychainKind::Internal)),
|
/// Some(BIP49(key, KeychainKind::Internal)),
|
||||||
/// Network::Testnet,
|
/// Network::Testnet,
|
||||||
@ -298,13 +298,13 @@ impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP49<K> {
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use std::str::FromStr;
|
/// # use std::str::FromStr;
|
||||||
/// # use bdk::bitcoin::{PrivateKey, Network};
|
/// # use bdk::bitcoin::{PrivateKey, Network};
|
||||||
/// # use bdk::{Wallet, OfflineWallet, KeychainKind};
|
/// # use bdk::{Wallet, KeychainKind};
|
||||||
/// # use bdk::database::MemoryDatabase;
|
/// # use bdk::database::MemoryDatabase;
|
||||||
/// use bdk::template::BIP49Public;
|
/// use bdk::template::BIP49Public;
|
||||||
///
|
///
|
||||||
/// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L")?;
|
/// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L")?;
|
||||||
/// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?;
|
/// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?;
|
||||||
/// let wallet: OfflineWallet<_> = Wallet::new_offline(
|
/// let wallet = Wallet::new_offline(
|
||||||
/// BIP49Public(key.clone(), fingerprint, KeychainKind::External),
|
/// BIP49Public(key.clone(), fingerprint, KeychainKind::External),
|
||||||
/// Some(BIP49Public(key, fingerprint, KeychainKind::Internal)),
|
/// Some(BIP49Public(key, fingerprint, KeychainKind::Internal)),
|
||||||
/// Network::Testnet,
|
/// Network::Testnet,
|
||||||
@ -334,12 +334,12 @@ impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP49Public<K> {
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use std::str::FromStr;
|
/// # use std::str::FromStr;
|
||||||
/// # use bdk::bitcoin::{PrivateKey, Network};
|
/// # use bdk::bitcoin::{PrivateKey, Network};
|
||||||
/// # use bdk::{Wallet, OfflineWallet, KeychainKind};
|
/// # use bdk::{Wallet, KeychainKind};
|
||||||
/// # use bdk::database::MemoryDatabase;
|
/// # use bdk::database::MemoryDatabase;
|
||||||
/// use bdk::template::BIP84;
|
/// use bdk::template::BIP84;
|
||||||
///
|
///
|
||||||
/// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
|
/// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
|
||||||
/// let wallet: OfflineWallet<_> = Wallet::new_offline(
|
/// let wallet = Wallet::new_offline(
|
||||||
/// BIP84(key.clone(), KeychainKind::External),
|
/// BIP84(key.clone(), KeychainKind::External),
|
||||||
/// Some(BIP84(key, KeychainKind::Internal)),
|
/// Some(BIP84(key, KeychainKind::Internal)),
|
||||||
/// Network::Testnet,
|
/// Network::Testnet,
|
||||||
@ -372,13 +372,13 @@ impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP84<K> {
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use std::str::FromStr;
|
/// # use std::str::FromStr;
|
||||||
/// # use bdk::bitcoin::{PrivateKey, Network};
|
/// # use bdk::bitcoin::{PrivateKey, Network};
|
||||||
/// # use bdk::{Wallet, OfflineWallet, KeychainKind};
|
/// # use bdk::{Wallet, KeychainKind};
|
||||||
/// # use bdk::database::MemoryDatabase;
|
/// # use bdk::database::MemoryDatabase;
|
||||||
/// use bdk::template::BIP84Public;
|
/// use bdk::template::BIP84Public;
|
||||||
///
|
///
|
||||||
/// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?;
|
/// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?;
|
||||||
/// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?;
|
/// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?;
|
||||||
/// let wallet: OfflineWallet<_> = Wallet::new_offline(
|
/// let wallet = Wallet::new_offline(
|
||||||
/// BIP84Public(key.clone(), fingerprint, KeychainKind::External),
|
/// BIP84Public(key.clone(), fingerprint, KeychainKind::External),
|
||||||
/// Some(BIP84Public(key, fingerprint, KeychainKind::Internal)),
|
/// Some(BIP84Public(key, fingerprint, KeychainKind::Internal)),
|
||||||
/// Network::Testnet,
|
/// Network::Testnet,
|
||||||
|
@ -89,11 +89,6 @@ pub enum Error {
|
|||||||
/// Signing error
|
/// Signing error
|
||||||
Signer(crate::wallet::signer::SignerError),
|
Signer(crate::wallet::signer::SignerError),
|
||||||
|
|
||||||
// Blockchain interface errors
|
|
||||||
/// Thrown when trying to call a method that requires a network connection, [`Wallet::sync`](crate::Wallet::sync) and [`Wallet::broadcast`](crate::Wallet::broadcast)
|
|
||||||
/// This error is thrown when creating the Client for the first time, while recovery attempts are tried
|
|
||||||
/// during the sync
|
|
||||||
OfflineClient,
|
|
||||||
/// Progress value must be between `0.0` (included) and `100.0` (included)
|
/// Progress value must be between `0.0` (included) and `100.0` (included)
|
||||||
InvalidProgressValue(f32),
|
InvalidProgressValue(f32),
|
||||||
/// Progress update error (maybe the channel has been closed)
|
/// Progress update error (maybe the channel has been closed)
|
||||||
|
10
src/lib.rs
10
src/lib.rs
@ -91,11 +91,11 @@
|
|||||||
//!
|
//!
|
||||||
//! ### Example
|
//! ### Example
|
||||||
//! ```
|
//! ```
|
||||||
//! use bdk::{Wallet, OfflineWallet};
|
//! use bdk::{Wallet};
|
||||||
//! use bdk::database::MemoryDatabase;
|
//! use bdk::database::MemoryDatabase;
|
||||||
//!
|
//!
|
||||||
//! fn main() -> Result<(), bdk::Error> {
|
//! fn main() -> Result<(), bdk::Error> {
|
||||||
//! let wallet: OfflineWallet<_> = Wallet::new_offline(
|
//! let wallet = Wallet::new_offline(
|
||||||
//! "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)",
|
//! "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)",
|
||||||
//! Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)"),
|
//! Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)"),
|
||||||
//! bitcoin::Network::Testnet,
|
//! bitcoin::Network::Testnet,
|
||||||
@ -155,13 +155,13 @@
|
|||||||
//! ### Example
|
//! ### Example
|
||||||
//! ```ignore
|
//! ```ignore
|
||||||
//! use base64::decode;
|
//! use base64::decode;
|
||||||
//! use bdk::{Wallet, OfflineWallet};
|
//! use bdk::{Wallet};
|
||||||
//! use bdk::database::MemoryDatabase;
|
//! use bdk::database::MemoryDatabase;
|
||||||
//!
|
//!
|
||||||
//! use bitcoin::consensus::deserialize;
|
//! use bitcoin::consensus::deserialize;
|
||||||
//!
|
//!
|
||||||
//! fn main() -> Result<(), bdk::Error> {
|
//! fn main() -> Result<(), bdk::Error> {
|
||||||
//! let wallet: OfflineWallet<_> = Wallet::new_offline(
|
//! let wallet = Wallet::new_offline(
|
||||||
//! "wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/0/*)",
|
//! "wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/0/*)",
|
||||||
//! Some("wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/1/*)"),
|
//! Some("wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/1/*)"),
|
||||||
//! bitcoin::Network::Testnet,
|
//! bitcoin::Network::Testnet,
|
||||||
@ -268,4 +268,4 @@ pub use types::*;
|
|||||||
pub use wallet::address_validator;
|
pub use wallet::address_validator;
|
||||||
pub use wallet::signer;
|
pub use wallet::signer;
|
||||||
pub use wallet::tx_builder::TxBuilder;
|
pub use wallet::tx_builder::TxBuilder;
|
||||||
pub use wallet::{OfflineWallet, Wallet};
|
pub use wallet::Wallet;
|
||||||
|
@ -66,7 +66,7 @@
|
|||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
|
//! let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
|
||||||
//! let mut wallet: OfflineWallet<_> = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
|
//! let mut wallet = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
|
||||||
//! wallet.add_address_validator(Arc::new(PrintAddressAndContinue));
|
//! wallet.add_address_validator(Arc::new(PrintAddressAndContinue));
|
||||||
//!
|
//!
|
||||||
//! let address = wallet.get_new_address()?;
|
//! let address = wallet.get_new_address()?;
|
||||||
|
@ -84,7 +84,7 @@
|
|||||||
//! }
|
//! }
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! # let wallet: OfflineWallet<_> = Wallet::new_offline("", None, Network::Testnet, bdk::database::MemoryDatabase::default())?;
|
//! # let wallet = Wallet::new_offline("", None, Network::Testnet, bdk::database::MemoryDatabase::default())?;
|
||||||
//! // create wallet, sync, ...
|
//! // create wallet, sync, ...
|
||||||
//!
|
//!
|
||||||
//! let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
|
//! let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
//! }"#;
|
//! }"#;
|
||||||
//!
|
//!
|
||||||
//! let import = WalletExport::from_str(import)?;
|
//! let import = WalletExport::from_str(import)?;
|
||||||
//! let wallet: OfflineWallet<_> = Wallet::new_offline(
|
//! let wallet = Wallet::new_offline(
|
||||||
//! &import.descriptor(),
|
//! &import.descriptor(),
|
||||||
//! import.change_descriptor().as_ref(),
|
//! import.change_descriptor().as_ref(),
|
||||||
//! Network::Testnet,
|
//! Network::Testnet,
|
||||||
@ -58,7 +58,7 @@
|
|||||||
//! # use bdk::database::*;
|
//! # use bdk::database::*;
|
||||||
//! # use bdk::wallet::export::*;
|
//! # use bdk::wallet::export::*;
|
||||||
//! # use bdk::*;
|
//! # use bdk::*;
|
||||||
//! let wallet: OfflineWallet<_> = Wallet::new_offline(
|
//! let wallet = Wallet::new_offline(
|
||||||
//! "wpkh([c258d2e4/84h/1h/0h]tpubDD3ynpHgJQW8VvWRzQ5WFDCrs4jqVFGHB3vLC3r49XHJSqP8bHKdK4AriuUKLccK68zfzowx7YhmDN8SiSkgCDENUFx9qVw65YyqM78vyVe/0/*)",
|
//! "wpkh([c258d2e4/84h/1h/0h]tpubDD3ynpHgJQW8VvWRzQ5WFDCrs4jqVFGHB3vLC3r49XHJSqP8bHKdK4AriuUKLccK68zfzowx7YhmDN8SiSkgCDENUFx9qVw65YyqM78vyVe/0/*)",
|
||||||
//! Some("wpkh([c258d2e4/84h/1h/0h]tpubDD3ynpHgJQW8VvWRzQ5WFDCrs4jqVFGHB3vLC3r49XHJSqP8bHKdK4AriuUKLccK68zfzowx7YhmDN8SiSkgCDENUFx9qVw65YyqM78vyVe/1/*)"),
|
//! Some("wpkh([c258d2e4/84h/1h/0h]tpubDD3ynpHgJQW8VvWRzQ5WFDCrs4jqVFGHB3vLC3r49XHJSqP8bHKdK4AriuUKLccK68zfzowx7YhmDN8SiSkgCDENUFx9qVw65YyqM78vyVe/1/*)"),
|
||||||
//! Network::Testnet,
|
//! Network::Testnet,
|
||||||
@ -78,7 +78,6 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use miniscript::{Descriptor, DescriptorPublicKey, ScriptContext, Terminal};
|
use miniscript::{Descriptor, DescriptorPublicKey, ScriptContext, Terminal};
|
||||||
|
|
||||||
use crate::blockchain::BlockchainMarker;
|
|
||||||
use crate::database::BatchDatabase;
|
use crate::database::BatchDatabase;
|
||||||
use crate::wallet::Wallet;
|
use crate::wallet::Wallet;
|
||||||
|
|
||||||
@ -120,7 +119,7 @@ impl WalletExport {
|
|||||||
///
|
///
|
||||||
/// If the database is empty or `include_blockheight` is false, the `blockheight` field
|
/// If the database is empty or `include_blockheight` is false, the `blockheight` field
|
||||||
/// returned will be `0`.
|
/// returned will be `0`.
|
||||||
pub fn export_wallet<B: BlockchainMarker, D: BatchDatabase>(
|
pub fn export_wallet<B, D: BatchDatabase>(
|
||||||
wallet: &Wallet<B, D>,
|
wallet: &Wallet<B, D>,
|
||||||
label: &str,
|
label: &str,
|
||||||
include_blockheight: bool,
|
include_blockheight: bool,
|
||||||
@ -208,7 +207,7 @@ mod test {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::database::{memory::MemoryDatabase, BatchOperations};
|
use crate::database::{memory::MemoryDatabase, BatchOperations};
|
||||||
use crate::types::TransactionDetails;
|
use crate::types::TransactionDetails;
|
||||||
use crate::wallet::{OfflineWallet, Wallet};
|
use crate::wallet::Wallet;
|
||||||
|
|
||||||
fn get_test_db() -> MemoryDatabase {
|
fn get_test_db() -> MemoryDatabase {
|
||||||
let mut db = MemoryDatabase::new();
|
let mut db = MemoryDatabase::new();
|
||||||
@ -234,7 +233,7 @@ mod test {
|
|||||||
let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)";
|
let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)";
|
||||||
let change_descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/1/*)";
|
let change_descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/1/*)";
|
||||||
|
|
||||||
let wallet: OfflineWallet<_> = Wallet::new_offline(
|
let wallet = Wallet::new_offline(
|
||||||
descriptor,
|
descriptor,
|
||||||
Some(change_descriptor),
|
Some(change_descriptor),
|
||||||
Network::Bitcoin,
|
Network::Bitcoin,
|
||||||
@ -258,7 +257,7 @@ mod test {
|
|||||||
|
|
||||||
let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)";
|
let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)";
|
||||||
|
|
||||||
let wallet: OfflineWallet<_> =
|
let wallet =
|
||||||
Wallet::new_offline(descriptor, None, Network::Bitcoin, get_test_db()).unwrap();
|
Wallet::new_offline(descriptor, None, Network::Bitcoin, get_test_db()).unwrap();
|
||||||
WalletExport::export_wallet(&wallet, "Test Label", true).unwrap();
|
WalletExport::export_wallet(&wallet, "Test Label", true).unwrap();
|
||||||
}
|
}
|
||||||
@ -272,7 +271,7 @@ mod test {
|
|||||||
let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)";
|
let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)";
|
||||||
let change_descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/50'/0'/1/*)";
|
let change_descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/50'/0'/1/*)";
|
||||||
|
|
||||||
let wallet: OfflineWallet<_> = Wallet::new_offline(
|
let wallet = Wallet::new_offline(
|
||||||
descriptor,
|
descriptor,
|
||||||
Some(change_descriptor),
|
Some(change_descriptor),
|
||||||
Network::Bitcoin,
|
Network::Bitcoin,
|
||||||
@ -295,7 +294,7 @@ mod test {
|
|||||||
[c98b1535/48'/0'/0'/2']tpubDCDi5W4sP6zSnzJeowy8rQDVhBdRARaPhK1axABi8V1661wEPeanpEXj4ZLAUEoikVtoWcyK26TKKJSecSfeKxwHCcRrge9k1ybuiL71z4a/1/*\
|
[c98b1535/48'/0'/0'/2']tpubDCDi5W4sP6zSnzJeowy8rQDVhBdRARaPhK1axABi8V1661wEPeanpEXj4ZLAUEoikVtoWcyK26TKKJSecSfeKxwHCcRrge9k1ybuiL71z4a/1/*\
|
||||||
))";
|
))";
|
||||||
|
|
||||||
let wallet: OfflineWallet<_> = Wallet::new_offline(
|
let wallet = Wallet::new_offline(
|
||||||
descriptor,
|
descriptor,
|
||||||
Some(change_descriptor),
|
Some(change_descriptor),
|
||||||
Network::Testnet,
|
Network::Testnet,
|
||||||
@ -315,7 +314,7 @@ mod test {
|
|||||||
let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)";
|
let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)";
|
||||||
let change_descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/1/*)";
|
let change_descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/1/*)";
|
||||||
|
|
||||||
let wallet: OfflineWallet<_> = Wallet::new_offline(
|
let wallet = Wallet::new_offline(
|
||||||
descriptor,
|
descriptor,
|
||||||
Some(change_descriptor),
|
Some(change_descriptor),
|
||||||
Network::Bitcoin,
|
Network::Bitcoin,
|
||||||
|
@ -61,7 +61,7 @@ use signer::{Signer, SignerId, SignerOrdering, SignersContainer};
|
|||||||
use tx_builder::{BumpFee, CreateTx, FeePolicy, TxBuilder, TxBuilderContext};
|
use tx_builder::{BumpFee, CreateTx, FeePolicy, TxBuilder, TxBuilderContext};
|
||||||
use utils::{check_nlocktime, check_nsequence_rbf, descriptor_to_pk_ctx, After, Older, SecpCtx};
|
use utils::{check_nlocktime, check_nsequence_rbf, descriptor_to_pk_ctx, After, Older, SecpCtx};
|
||||||
|
|
||||||
use crate::blockchain::{Blockchain, BlockchainMarker, OfflineBlockchain, Progress};
|
use crate::blockchain::{Blockchain, Progress};
|
||||||
use crate::database::{BatchDatabase, BatchOperations, DatabaseUtils};
|
use crate::database::{BatchDatabase, BatchOperations, DatabaseUtils};
|
||||||
use crate::descriptor::{
|
use crate::descriptor::{
|
||||||
get_checksum, DescriptorMeta, DescriptorScripts, ExtendedDescriptor, ExtractPolicy, Policy,
|
get_checksum, DescriptorMeta, DescriptorScripts, ExtendedDescriptor, ExtractPolicy, Policy,
|
||||||
@ -73,9 +73,6 @@ use crate::types::*;
|
|||||||
|
|
||||||
const CACHE_ADDR_BATCH_SIZE: u32 = 100;
|
const CACHE_ADDR_BATCH_SIZE: u32 = 100;
|
||||||
|
|
||||||
/// Type alias for a [`Wallet`] that uses [`OfflineBlockchain`]
|
|
||||||
pub type OfflineWallet<D> = Wallet<OfflineBlockchain, D>;
|
|
||||||
|
|
||||||
/// A Bitcoin wallet
|
/// A Bitcoin wallet
|
||||||
///
|
///
|
||||||
/// A wallet takes descriptors, a [`database`](trait@crate::database::Database) and a
|
/// A wallet takes descriptors, a [`database`](trait@crate::database::Database) and a
|
||||||
@ -84,7 +81,7 @@ pub type OfflineWallet<D> = Wallet<OfflineBlockchain, D>;
|
|||||||
/// [creating transactions](Wallet::create_tx), etc.
|
/// [creating transactions](Wallet::create_tx), etc.
|
||||||
///
|
///
|
||||||
/// A wallet can be either "online" if the [`blockchain`](crate::blockchain) type provided
|
/// A wallet can be either "online" if the [`blockchain`](crate::blockchain) type provided
|
||||||
/// implements [`Blockchain`], or "offline" [`OfflineBlockchain`] is used. Offline wallets only expose
|
/// implements [`Blockchain`], or "offline" if it is the unit type `()`. Offline wallets only expose
|
||||||
/// methods that don't need any interaction with the blockchain to work.
|
/// methods that don't need any interaction with the blockchain to work.
|
||||||
pub struct Wallet<B, D> {
|
pub struct Wallet<B, D> {
|
||||||
descriptor: ExtendedDescriptor,
|
descriptor: ExtendedDescriptor,
|
||||||
@ -99,24 +96,38 @@ pub struct Wallet<B, D> {
|
|||||||
|
|
||||||
current_height: Option<u32>,
|
current_height: Option<u32>,
|
||||||
|
|
||||||
client: Option<B>,
|
client: B,
|
||||||
database: RefCell<D>,
|
database: RefCell<D>,
|
||||||
|
|
||||||
secp: SecpCtx,
|
secp: SecpCtx,
|
||||||
}
|
}
|
||||||
|
|
||||||
// offline actions, always available
|
impl<D> Wallet<(), D>
|
||||||
impl<B, D> Wallet<B, D>
|
|
||||||
where
|
where
|
||||||
B: BlockchainMarker,
|
|
||||||
D: BatchDatabase,
|
D: BatchDatabase,
|
||||||
{
|
{
|
||||||
/// Create a new "offline" wallet
|
/// Create a new "offline" wallet
|
||||||
pub fn new_offline<E: ToWalletDescriptor>(
|
pub fn new_offline<E: ToWalletDescriptor>(
|
||||||
|
descriptor: E,
|
||||||
|
change_descriptor: Option<E>,
|
||||||
|
network: Network,
|
||||||
|
database: D,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
|
Self::_new(descriptor, change_descriptor, network, database, (), None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B, D> Wallet<B, D>
|
||||||
|
where
|
||||||
|
D: BatchDatabase,
|
||||||
|
{
|
||||||
|
fn _new<E: ToWalletDescriptor>(
|
||||||
descriptor: E,
|
descriptor: E,
|
||||||
change_descriptor: Option<E>,
|
change_descriptor: Option<E>,
|
||||||
network: Network,
|
network: Network,
|
||||||
mut database: D,
|
mut database: D,
|
||||||
|
client: B,
|
||||||
|
current_height: Option<u32>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let (descriptor, keymap) = descriptor.to_wallet_descriptor(network)?;
|
let (descriptor, keymap) = descriptor.to_wallet_descriptor(network)?;
|
||||||
database.check_descriptor_checksum(
|
database.check_descriptor_checksum(
|
||||||
@ -148,18 +159,20 @@ where
|
|||||||
signers,
|
signers,
|
||||||
change_signers,
|
change_signers,
|
||||||
address_validators: Vec::new(),
|
address_validators: Vec::new(),
|
||||||
|
|
||||||
network,
|
network,
|
||||||
|
current_height,
|
||||||
current_height: None,
|
client,
|
||||||
|
|
||||||
client: None,
|
|
||||||
database: RefCell::new(database),
|
database: RefCell::new(database),
|
||||||
|
|
||||||
secp: Secp256k1::new(),
|
secp: Secp256k1::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// offline actions, always available
|
||||||
|
impl<B, D> Wallet<B, D>
|
||||||
|
where
|
||||||
|
D: BatchDatabase,
|
||||||
|
{
|
||||||
/// Return a newly generated address using the external descriptor
|
/// Return a newly generated address using the external descriptor
|
||||||
pub fn get_new_address(&self) -> Result<Address, Error> {
|
pub fn get_new_address(&self) -> Result<Address, Error> {
|
||||||
let index = self.fetch_and_increment_index(KeychainKind::External)?;
|
let index = self.fetch_and_increment_index(KeychainKind::External)?;
|
||||||
@ -241,7 +254,7 @@ where
|
|||||||
/// # use bdk::*;
|
/// # use bdk::*;
|
||||||
/// # use bdk::database::*;
|
/// # use bdk::database::*;
|
||||||
/// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
|
/// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
|
||||||
/// # let wallet: OfflineWallet<_> = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
|
/// # let wallet = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
|
||||||
/// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
|
/// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
|
||||||
/// let (psbt, details) = wallet.create_tx(
|
/// let (psbt, details) = wallet.create_tx(
|
||||||
/// TxBuilder::with_recipients(vec![(to_address.script_pubkey(), 50_000)])
|
/// TxBuilder::with_recipients(vec![(to_address.script_pubkey(), 50_000)])
|
||||||
@ -556,7 +569,7 @@ where
|
|||||||
/// # use bdk::*;
|
/// # use bdk::*;
|
||||||
/// # use bdk::database::*;
|
/// # use bdk::database::*;
|
||||||
/// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
|
/// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
|
||||||
/// # let wallet: OfflineWallet<_> = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
|
/// # let wallet = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
|
||||||
/// let txid = Txid::from_str("faff0a466b70f5d5f92bd757a92c1371d4838bdd5bc53a06764e2488e51ce8f8").unwrap();
|
/// let txid = Txid::from_str("faff0a466b70f5d5f92bd757a92c1371d4838bdd5bc53a06764e2488e51ce8f8").unwrap();
|
||||||
/// let (psbt, details) = wallet.bump_fee(
|
/// let (psbt, details) = wallet.bump_fee(
|
||||||
/// &txid,
|
/// &txid,
|
||||||
@ -820,7 +833,7 @@ where
|
|||||||
/// # use bdk::*;
|
/// # use bdk::*;
|
||||||
/// # use bdk::database::*;
|
/// # use bdk::database::*;
|
||||||
/// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
|
/// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
|
||||||
/// # let wallet: OfflineWallet<_> = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
|
/// # let wallet = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
|
||||||
/// # let (psbt, _) = wallet.create_tx(TxBuilder::new())?;
|
/// # let (psbt, _) = wallet.create_tx(TxBuilder::new())?;
|
||||||
/// let (signed_psbt, finalized) = wallet.sign(psbt, None)?;
|
/// let (signed_psbt, finalized) = wallet.sign(psbt, None)?;
|
||||||
/// # Ok::<(), bdk::Error>(())
|
/// # Ok::<(), bdk::Error>(())
|
||||||
@ -1319,12 +1332,15 @@ where
|
|||||||
database: D,
|
database: D,
|
||||||
client: B,
|
client: B,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let mut wallet = Self::new_offline(descriptor, change_descriptor, network, database)?;
|
let current_height = Some(maybe_await!(client.get_height())? as u32);
|
||||||
|
Self::_new(
|
||||||
wallet.current_height = Some(maybe_await!(client.get_height())? as u32);
|
descriptor,
|
||||||
wallet.client = Some(client);
|
change_descriptor,
|
||||||
|
network,
|
||||||
Ok(wallet)
|
database,
|
||||||
|
client,
|
||||||
|
current_height,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sync the internal database with the blockchain
|
/// Sync the internal database with the blockchain
|
||||||
@ -1372,13 +1388,13 @@ where
|
|||||||
// TODO: what if i generate an address first and cache some addresses?
|
// TODO: what if i generate an address first and cache some addresses?
|
||||||
// TODO: we should sync if generating an address triggers a new batch to be stored
|
// TODO: we should sync if generating an address triggers a new batch to be stored
|
||||||
if run_setup {
|
if run_setup {
|
||||||
maybe_await!(self.client.as_ref().ok_or(Error::OfflineClient)?.setup(
|
maybe_await!(self.client.setup(
|
||||||
None,
|
None,
|
||||||
self.database.borrow_mut().deref_mut(),
|
self.database.borrow_mut().deref_mut(),
|
||||||
progress_update,
|
progress_update,
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
maybe_await!(self.client.as_ref().ok_or(Error::OfflineClient)?.sync(
|
maybe_await!(self.client.sync(
|
||||||
None,
|
None,
|
||||||
self.database.borrow_mut().deref_mut(),
|
self.database.borrow_mut().deref_mut(),
|
||||||
progress_update,
|
progress_update,
|
||||||
@ -1387,8 +1403,8 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return a reference to the internal blockchain client
|
/// Return a reference to the internal blockchain client
|
||||||
pub fn client(&self) -> Option<&B> {
|
pub fn client(&self) -> &B {
|
||||||
self.client.as_ref()
|
&self.client
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the Bitcoin network the wallet is using.
|
/// Get the Bitcoin network the wallet is using.
|
||||||
@ -1399,11 +1415,7 @@ where
|
|||||||
/// Broadcast a transaction to the network
|
/// Broadcast a transaction to the network
|
||||||
#[maybe_async]
|
#[maybe_async]
|
||||||
pub fn broadcast(&self, tx: Transaction) -> Result<Txid, Error> {
|
pub fn broadcast(&self, tx: Transaction) -> Result<Txid, Error> {
|
||||||
maybe_await!(self
|
maybe_await!(self.client.broadcast(&tx))?;
|
||||||
.client
|
|
||||||
.as_ref()
|
|
||||||
.ok_or(Error::OfflineClient)?
|
|
||||||
.broadcast(&tx))?;
|
|
||||||
|
|
||||||
Ok(tx.txid())
|
Ok(tx.txid())
|
||||||
}
|
}
|
||||||
@ -1424,7 +1436,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_cache_addresses_fixed() {
|
fn test_cache_addresses_fixed() {
|
||||||
let db = MemoryDatabase::new();
|
let db = MemoryDatabase::new();
|
||||||
let wallet: OfflineWallet<_> = Wallet::new_offline(
|
let wallet = Wallet::new_offline(
|
||||||
"wpkh(L5EZftvrYaSudiozVRzTqLcHLNDoVn7H5HSfM9BAN6tMJX8oTWz6)",
|
"wpkh(L5EZftvrYaSudiozVRzTqLcHLNDoVn7H5HSfM9BAN6tMJX8oTWz6)",
|
||||||
None,
|
None,
|
||||||
Network::Testnet,
|
Network::Testnet,
|
||||||
@ -1458,7 +1470,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_cache_addresses() {
|
fn test_cache_addresses() {
|
||||||
let db = MemoryDatabase::new();
|
let db = MemoryDatabase::new();
|
||||||
let wallet: OfflineWallet<_> = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)", None, Network::Testnet, db).unwrap();
|
let wallet = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)", None, Network::Testnet, db).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
wallet.get_new_address().unwrap().to_string(),
|
wallet.get_new_address().unwrap().to_string(),
|
||||||
@ -1486,7 +1498,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_cache_addresses_refill() {
|
fn test_cache_addresses_refill() {
|
||||||
let db = MemoryDatabase::new();
|
let db = MemoryDatabase::new();
|
||||||
let wallet: OfflineWallet<_> = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)", None, Network::Testnet, db).unwrap();
|
let wallet = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)", None, Network::Testnet, db).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
wallet.get_new_address().unwrap().to_string(),
|
wallet.get_new_address().unwrap().to_string(),
|
||||||
@ -1533,12 +1545,12 @@ mod test {
|
|||||||
pub(crate) fn get_funded_wallet(
|
pub(crate) fn get_funded_wallet(
|
||||||
descriptor: &str,
|
descriptor: &str,
|
||||||
) -> (
|
) -> (
|
||||||
OfflineWallet<MemoryDatabase>,
|
Wallet<(), MemoryDatabase>,
|
||||||
(String, Option<String>),
|
(String, Option<String>),
|
||||||
bitcoin::Txid,
|
bitcoin::Txid,
|
||||||
) {
|
) {
|
||||||
let descriptors = testutils!(@descriptors (descriptor));
|
let descriptors = testutils!(@descriptors (descriptor));
|
||||||
let wallet: OfflineWallet<_> = Wallet::new_offline(
|
let wallet = Wallet::new_offline(
|
||||||
&descriptors.0,
|
&descriptors.0,
|
||||||
None,
|
None,
|
||||||
Network::Regtest,
|
Network::Regtest,
|
||||||
|
@ -79,7 +79,7 @@
|
|||||||
//! let custom_signer = CustomSigner::connect();
|
//! let custom_signer = CustomSigner::connect();
|
||||||
//!
|
//!
|
||||||
//! let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
|
//! let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
|
||||||
//! let mut wallet: OfflineWallet<_> = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
|
//! let mut wallet = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
|
||||||
//! wallet.add_signer(
|
//! wallet.add_signer(
|
||||||
//! KeychainKind::External,
|
//! KeychainKind::External,
|
||||||
//! Fingerprint::from_str("e30f11b8").unwrap().into(),
|
//! Fingerprint::from_str("e30f11b8").unwrap().into(),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user