From 0cfd63b3842ed82866e1fcbd0db454e22571df3e Mon Sep 17 00:00:00 2001 From: Matthew Date: Fri, 29 Sep 2023 15:13:23 -0500 Subject: [PATCH] add wallet type --- bdk-ffi/src/bdk.udl | 33 ++++++++++++++ bdk-ffi/src/lib.rs | 100 ++++++++++++++++++++++++++++++++++++++++++ bdk-ffi/src/wallet.rs | 53 +++++++++++++++++++++- 3 files changed, 185 insertions(+), 1 deletion(-) diff --git a/bdk-ffi/src/bdk.udl b/bdk-ffi/src/bdk.udl index afa29f81..6b24fedb 100644 --- a/bdk-ffi/src/bdk.udl +++ b/bdk-ffi/src/bdk.udl @@ -132,4 +132,37 @@ interface Descriptor { string as_string(); string as_string_private(); +}; + + +interface Wallet { + [Throws=BdkError] + constructor(Descriptor descriptor, Descriptor? change_descriptor, Network network, WalletType wallet_type); + + AddressInfo get_address(AddressIndex address_index); +}; + +enum WalletType { + "Memory", + "FlatFile", +}; + +interface Address { + [Throws=BdkError] + constructor(string address, Network network); + + string as_string(); +}; + +dictionary AddressInfo { + u32 index; + Address address; + KeychainKind keychain; +}; + +[Enum] +interface AddressIndex { + New(); + LastUnused(); + Peek(u32 index); }; \ No newline at end of file diff --git a/bdk-ffi/src/lib.rs b/bdk-ffi/src/lib.rs index 477391c6..6acbba2f 100644 --- a/bdk-ffi/src/lib.rs +++ b/bdk-ffi/src/lib.rs @@ -406,6 +406,106 @@ use crate::keys::DescriptorSecretKey; // inner: BdkAddress, // } // + +use std::sync::Arc; + +use bdk::bitcoin::Address as BdkAddress; +use bdk::wallet::AddressIndex as BdkAddressIndex; +use bdk::wallet::AddressInfo as BdkAddressInfo; +use bdk::bitcoin::address::{NetworkChecked, NetworkUnchecked}; +use crate::wallet::Wallet; +use crate::wallet::WalletType; +/// A derived address and the index it was found at. +pub struct AddressInfo { + /// Child index of this address. + pub index: u32, + /// Address. + pub address: Arc
, + /// Type of keychain. + pub keychain: KeychainKind, +} + + +impl From for AddressInfo { + fn from(address_info: BdkAddressInfo) -> Self { + AddressInfo { + index: address_info.index, + address: Arc::new(address_info.address.into()), + keychain: address_info.keychain, + } + } +} + +/// The address index selection strategy to use to derived an address from the wallet's external +/// descriptor. +pub enum AddressIndex { + /// Return a new address after incrementing the current descriptor index. + New, + /// Return the address for the current descriptor index if it has not been used in a received + /// transaction. Otherwise return a new address as with AddressIndex::New. + /// Use with caution, if the wallet has not yet detected an address has been used it could + /// return an already used address. This function is primarily meant for situations where the + /// caller is untrusted; for example when deriving donation addresses on-demand for a public + /// web page. + LastUnused, + /// Return the address for a specific descriptor index. Does not change the current descriptor + /// index used by `AddressIndex::New` and `AddressIndex::LastUsed`. + /// Use with caution, if an index is given that is less than the current descriptor index + /// then the returned address may have already been used. + Peek { index: u32 }, +} + +impl From for BdkAddressIndex { + fn from(address_index: AddressIndex) -> Self { + match address_index { + AddressIndex::New => BdkAddressIndex::New, + AddressIndex::LastUnused => BdkAddressIndex::LastUnused, + AddressIndex::Peek { index } => BdkAddressIndex::Peek(index), + } + } +} + +/// A Bitcoin address. +#[derive(Debug, PartialEq, Eq)] +pub struct Address { + inner: BdkAddress, +} + + +impl Address { + fn new( + address: String, + network: Network, + ) -> Result { + Ok(Address { + inner: address + .parse::>() + .unwrap() // TODO 7: Handle error correctly by rethrowing it as a BdkError + .require_network(network.into()) + .map_err(|e| BdkError::Generic(e.to_string()))?, + }) + } + fn to_qr_uri(&self) -> String { + self.inner.to_qr_uri() + } + + fn as_string(&self) -> String { + self.inner.to_string() + } +} + +impl From for Address { + fn from(address: BdkAddress) -> Self { + Address { inner: address } + } +} + +impl From
for BdkAddress { + fn from(address: Address) -> Self { + address.inner + } +} + // impl Address { // fn new(address: String) -> Result { // BdkAddress::from_str(address.as_str()) diff --git a/bdk-ffi/src/wallet.rs b/bdk-ffi/src/wallet.rs index 2151f570..f3bed13a 100644 --- a/bdk-ffi/src/wallet.rs +++ b/bdk-ffi/src/wallet.rs @@ -21,7 +21,6 @@ // RbfValue, Script, ScriptAmount, TransactionDetails, TxBuilderResult, // }; // -use crate::BdkError; // #[derive(Debug)] // pub(crate) struct Wallet { // pub(crate) inner_mutex: Mutex>, @@ -858,3 +857,55 @@ use crate::BdkError; // assert_matches!(is_mine_2, false); // } // } +use std::sync::{Arc, Mutex, MutexGuard}; +use bdk::Wallet as BdkWallet; +use crate::descriptor::Descriptor; +use crate::{AddressIndex, AddressInfo, Network}; +use bdk::wallet::AddressIndex as BdkAddressIndex; +use bdk::Error as BdkError; +pub enum WalletType { + Memory, + FlatFile, +} + +pub(crate) struct Wallet { + pub(crate) inner_mutex: Mutex, +} + +impl Wallet { + pub fn new( + descriptor: Arc, + change_descriptor: Option>, + network: Network, + wallet_type: WalletType, + ) -> Result { + let descriptor = descriptor.as_string_private(); + let change_descriptor = change_descriptor.map(|d| d.as_string_private()); + + match wallet_type { + WalletType::Memory => { + let wallet = BdkWallet::new_no_persist( + &descriptor, + change_descriptor.as_ref(), + network.into(), + )?; + Ok(Wallet { + inner_mutex: Mutex::new(wallet), + }) + } + WalletType::FlatFile => { + panic!("FlatFile wallet type not yet implemented") + } + } + } + + pub fn get_address(&self, address_index: AddressIndex) -> AddressInfo { + self.get_wallet().get_address(address_index.into()).into() + } + + // TODO 10: Do we need this mutex + pub(crate) fn get_wallet(&self) -> MutexGuard { + self.inner_mutex.lock().expect("wallet") + } + +} \ No newline at end of file