use alloc::boxed::Box;
use bdk_chain::keychain_txout::DEFAULT_LOOKAHEAD;
use bitcoin::{BlockHash, Network};
use miniscript::descriptor::KeyMap;
use crate::{
descriptor::{DescriptorError, ExtendedDescriptor, IntoWalletDescriptor},
utils::SecpCtx,
AsyncWalletPersister, CreateWithPersistError, KeychainKind, LoadWithPersistError, Wallet,
WalletPersister,
};
use super::{ChangeSet, LoadError, PersistedWallet};
type DescriptorToExtract = Box<
dyn FnOnce(&SecpCtx, Network) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError>
+ Send
+ 'static,
>;
fn make_descriptor_to_extract<D>(descriptor: D) -> DescriptorToExtract
where
D: IntoWalletDescriptor + Send + 'static,
{
Box::new(|secp, network| descriptor.into_wallet_descriptor(secp, network))
}
#[must_use]
pub struct CreateParams {
pub(crate) descriptor: DescriptorToExtract,
pub(crate) descriptor_keymap: KeyMap,
pub(crate) change_descriptor: Option<DescriptorToExtract>,
pub(crate) change_descriptor_keymap: KeyMap,
pub(crate) network: Network,
pub(crate) genesis_hash: Option<BlockHash>,
pub(crate) lookahead: u32,
}
impl CreateParams {
pub fn new_single<D: IntoWalletDescriptor + Send + 'static>(descriptor: D) -> Self {
Self {
descriptor: make_descriptor_to_extract(descriptor),
descriptor_keymap: KeyMap::default(),
change_descriptor: None,
change_descriptor_keymap: KeyMap::default(),
network: Network::Bitcoin,
genesis_hash: None,
lookahead: DEFAULT_LOOKAHEAD,
}
}
pub fn new<D: IntoWalletDescriptor + Send + 'static>(
descriptor: D,
change_descriptor: D,
) -> Self {
Self {
descriptor: make_descriptor_to_extract(descriptor),
descriptor_keymap: KeyMap::default(),
change_descriptor: Some(make_descriptor_to_extract(change_descriptor)),
change_descriptor_keymap: KeyMap::default(),
network: Network::Bitcoin,
genesis_hash: None,
lookahead: DEFAULT_LOOKAHEAD,
}
}
pub fn keymap(mut self, keychain: KeychainKind, keymap: KeyMap) -> Self {
match keychain {
KeychainKind::External => &mut self.descriptor_keymap,
KeychainKind::Internal => &mut self.change_descriptor_keymap,
}
.extend(keymap);
self
}
pub fn network(mut self, network: Network) -> Self {
self.network = network;
self
}
pub fn genesis_hash(mut self, genesis_hash: BlockHash) -> Self {
self.genesis_hash = Some(genesis_hash);
self
}
pub fn lookahead(mut self, lookahead: u32) -> Self {
self.lookahead = lookahead;
self
}
pub fn create_wallet<P>(
self,
persister: &mut P,
) -> Result<PersistedWallet<P>, CreateWithPersistError<P::Error>>
where
P: WalletPersister,
{
PersistedWallet::create(persister, self)
}
pub async fn create_wallet_async<P>(
self,
persister: &mut P,
) -> Result<PersistedWallet<P>, CreateWithPersistError<P::Error>>
where
P: AsyncWalletPersister,
{
PersistedWallet::create_async(persister, self).await
}
pub fn create_wallet_no_persist(self) -> Result<Wallet, DescriptorError> {
Wallet::create_with_params(self)
}
}
#[must_use]
pub struct LoadParams {
pub(crate) descriptor_keymap: KeyMap,
pub(crate) change_descriptor_keymap: KeyMap,
pub(crate) lookahead: u32,
pub(crate) check_network: Option<Network>,
pub(crate) check_genesis_hash: Option<BlockHash>,
pub(crate) check_descriptor: Option<Option<DescriptorToExtract>>,
pub(crate) check_change_descriptor: Option<Option<DescriptorToExtract>>,
pub(crate) extract_keys: bool,
}
impl LoadParams {
pub fn new() -> Self {
Self {
descriptor_keymap: KeyMap::default(),
change_descriptor_keymap: KeyMap::default(),
lookahead: DEFAULT_LOOKAHEAD,
check_network: None,
check_genesis_hash: None,
check_descriptor: None,
check_change_descriptor: None,
extract_keys: false,
}
}
pub fn keymap(mut self, keychain: KeychainKind, keymap: KeyMap) -> Self {
match keychain {
KeychainKind::External => &mut self.descriptor_keymap,
KeychainKind::Internal => &mut self.change_descriptor_keymap,
}
.extend(keymap);
self
}
pub fn descriptor<D>(mut self, keychain: KeychainKind, expected_descriptor: Option<D>) -> Self
where
D: IntoWalletDescriptor + Send + 'static,
{
let expected = expected_descriptor.map(|d| make_descriptor_to_extract(d));
match keychain {
KeychainKind::External => self.check_descriptor = Some(expected),
KeychainKind::Internal => self.check_change_descriptor = Some(expected),
}
self
}
pub fn check_network(mut self, network: Network) -> Self {
self.check_network = Some(network);
self
}
pub fn check_genesis_hash(mut self, genesis_hash: BlockHash) -> Self {
self.check_genesis_hash = Some(genesis_hash);
self
}
pub fn lookahead(mut self, lookahead: u32) -> Self {
self.lookahead = lookahead;
self
}
pub fn extract_keys(mut self) -> Self {
self.extract_keys = true;
self
}
pub fn load_wallet<P>(
self,
persister: &mut P,
) -> Result<Option<PersistedWallet<P>>, LoadWithPersistError<P::Error>>
where
P: WalletPersister,
{
PersistedWallet::load(persister, self)
}
pub async fn load_wallet_async<P>(
self,
persister: &mut P,
) -> Result<Option<PersistedWallet<P>>, LoadWithPersistError<P::Error>>
where
P: AsyncWalletPersister,
{
PersistedWallet::load_async(persister, self).await
}
pub fn load_wallet_no_persist(self, changeset: ChangeSet) -> Result<Option<Wallet>, LoadError> {
Wallet::load_with_params(changeset, self)
}
}
impl Default for LoadParams {
fn default() -> Self {
Self::new()
}
}