2022-09-01 13:05:35 -04:00
use bdk ::bitcoin ::blockdata ::script ::Script as BdkScript ;
2022-03-15 20:11:33 -05:00
use bdk ::bitcoin ::hashes ::hex ::ToHex ;
2021-10-21 14:35:40 +05:30
use bdk ::bitcoin ::secp256k1 ::Secp256k1 ;
2022-08-09 14:27:19 +05:30
use bdk ::bitcoin ::util ::bip32 ::DerivationPath as BdkDerivationPath ;
2022-09-01 13:05:35 -04:00
use bdk ::bitcoin ::util ::psbt ::serialize ::Serialize ;
2021-10-16 16:42:35 +05:30
use bdk ::bitcoin ::util ::psbt ::PartiallySignedTransaction ;
2022-11-01 14:15:41 -04:00
use bdk ::bitcoin ::Sequence ;
2022-09-01 13:05:35 -04:00
use bdk ::bitcoin ::{ Address as BdkAddress , Network , OutPoint as BdkOutPoint , Txid } ;
2021-10-15 00:43:17 +05:30
use bdk ::blockchain ::any ::{ AnyBlockchain , AnyBlockchainConfig } ;
2022-08-17 16:43:17 -04:00
use bdk ::blockchain ::GetBlockHash ;
use bdk ::blockchain ::GetHeight ;
2021-10-15 00:43:17 +05:30
use bdk ::blockchain ::{
electrum ::ElectrumBlockchainConfig , esplora ::EsploraBlockchainConfig , ConfigurableBlockchain ,
} ;
2022-04-20 23:15:14 -07:00
use bdk ::blockchain ::{ Blockchain as BdkBlockchain , Progress as BdkProgress } ;
2022-03-11 22:45:37 -06:00
use bdk ::database ::any ::{ AnyDatabase , SledDbConfiguration , SqliteDbConfiguration } ;
2021-10-14 04:23:17 +05:30
use bdk ::database ::{ AnyDatabaseConfig , ConfigurableDatabase } ;
2022-08-09 14:39:15 +05:30
use bdk ::descriptor ::DescriptorXKey ;
2022-10-28 10:19:57 +05:30
use bdk ::keys ::bip39 ::{ Language , Mnemonic as BdkMnemonic , WordCount } ;
2022-08-09 14:39:15 +05:30
use bdk ::keys ::{
DerivableKey , DescriptorPublicKey as BdkDescriptorPublicKey ,
DescriptorSecretKey as BdkDescriptorSecretKey , ExtendedKey , GeneratableKey , GeneratedKey ,
} ;
2021-10-21 14:35:40 +05:30
use bdk ::miniscript ::BareCtx ;
2022-06-09 13:28:23 +02:00
use bdk ::wallet ::tx_builder ::ChangeSpendPolicy ;
2022-06-10 08:41:10 -03:00
use bdk ::wallet ::AddressIndex as BdkAddressIndex ;
use bdk ::wallet ::AddressInfo as BdkAddressInfo ;
2022-04-20 23:15:14 -07:00
use bdk ::{
2022-10-21 09:19:00 -04:00
Balance as BdkBalance , BlockTime , Error as BdkError , FeeRate , KeychainKind , SignOptions ,
2022-09-01 14:04:36 -04:00
SyncOptions as BdkSyncOptions , Wallet as BdkWallet ,
2022-04-20 23:15:14 -07:00
} ;
2022-06-09 13:28:23 +02:00
use std ::collections ::HashSet ;
2022-07-21 17:00:21 +02:00
use std ::convert ::{ From , TryFrom } ;
2022-04-20 23:15:14 -07:00
use std ::fmt ;
use std ::ops ::Deref ;
2021-10-16 16:42:35 +05:30
use std ::str ::FromStr ;
2022-03-25 17:24:21 +00:00
use std ::sync ::{ Arc , Mutex , MutexGuard } ;
2021-10-11 23:04:18 -07:00
2021-10-14 10:58:16 -07:00
uniffi_macros ::include_scaffolding! ( " bdk " ) ;
2022-09-01 13:05:35 -04:00
/// A output script and an amount of satoshis.
pub struct ScriptAmount {
pub script : Arc < Script > ,
2022-08-29 06:58:46 -07:00
pub amount : u64 ,
}
2022-08-29 15:47:37 -04:00
/// A derived address and the index it was found at.
2022-04-19 14:30:12 -04:00
pub struct AddressInfo {
2022-08-29 15:47:37 -04:00
/// Child index of this address
2022-04-08 14:20:28 -04:00
pub index : u32 ,
2022-08-29 15:47:37 -04:00
/// Address
2022-04-08 14:20:28 -04:00
pub address : String ,
}
2022-05-16 12:07:11 -04:00
impl From < BdkAddressInfo > for AddressInfo {
2022-04-19 14:30:12 -04:00
fn from ( x : bdk ::wallet ::AddressInfo ) -> AddressInfo {
AddressInfo {
index : x . index ,
2022-06-10 08:41:10 -03:00
address : x . address . to_string ( ) ,
2022-04-19 14:30:12 -04:00
}
}
}
2022-08-29 15:47:37 -04:00
/// The address index selection strategy to use to derived an address from the wallet's external
/// descriptor.
2022-04-19 14:30:12 -04:00
pub enum AddressIndex {
2022-08-29 15:47:37 -04:00
/// Return a new address after incrementing the current descriptor index.
2022-04-19 14:30:12 -04:00
New ,
2022-08-29 15:47:37 -04:00
/// 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.
2022-04-19 14:30:12 -04:00
LastUnused ,
}
2022-05-16 12:07:11 -04:00
impl From < AddressIndex > for BdkAddressIndex {
fn from ( x : AddressIndex ) -> BdkAddressIndex {
2022-04-19 14:30:12 -04:00
match x {
2022-05-16 12:07:11 -04:00
AddressIndex ::New = > BdkAddressIndex ::New ,
2022-06-10 08:41:10 -03:00
AddressIndex ::LastUnused = > BdkAddressIndex ::LastUnused ,
2022-04-19 14:30:12 -04:00
}
}
}
2022-08-29 15:47:37 -04:00
/// Type that can contain any of the database configurations defined by the library
/// This allows storing a single configuration that can be loaded into an AnyDatabaseConfig
/// instance. Wallets that plan to offer users the ability to switch blockchain backend at runtime
/// will find this particularly useful.
2021-10-14 04:23:17 +05:30
pub enum DatabaseConfig {
2022-08-29 15:47:37 -04:00
/// Memory database has no config
2022-03-01 16:14:21 -05:00
Memory ,
2022-08-29 15:47:37 -04:00
/// Simple key-value embedded database based on sled
2021-10-15 00:43:17 +05:30
Sled { config : SledDbConfiguration } ,
2022-08-29 15:47:37 -04:00
/// Sqlite embedded database using rusqlite
2022-03-11 22:45:37 -06:00
Sqlite { config : SqliteDbConfiguration } ,
2021-10-15 00:43:17 +05:30
}
2022-08-29 15:47:37 -04:00
/// Configuration for an ElectrumBlockchain
2021-10-15 00:43:17 +05:30
pub struct ElectrumConfig {
2022-08-29 15:47:37 -04:00
/// URL of the Electrum server (such as ElectrumX, Esplora, BWT) may start with ssl:// or tcp:// and include a port
/// e.g. ssl://electrum.blockstream.info:60002
2021-10-15 00:43:17 +05:30
pub url : String ,
2022-08-29 15:47:37 -04:00
/// URL of the socks5 proxy server or a Tor service
2021-10-15 00:43:17 +05:30
pub socks5 : Option < String > ,
2022-08-29 15:47:37 -04:00
/// Request retry count
2021-10-15 00:43:17 +05:30
pub retry : u8 ,
2022-08-29 15:47:37 -04:00
/// Request timeout (seconds)
2021-10-15 00:43:17 +05:30
pub timeout : Option < u8 > ,
2022-08-29 15:47:37 -04:00
/// Stop searching addresses for transactions after finding an unused gap of this length
2021-10-15 00:43:17 +05:30
pub stop_gap : u64 ,
}
2022-08-29 15:47:37 -04:00
/// Configuration for an EsploraBlockchain
2021-10-15 00:43:17 +05:30
pub struct EsploraConfig {
2022-08-29 15:47:37 -04:00
/// Base URL of the esplora service
/// e.g. https://blockstream.info/api/
2021-10-15 00:43:17 +05:30
pub base_url : String ,
2022-08-29 15:47:37 -04:00
/// Optional URL of the proxy to use to make requests to the Esplora server
/// The string should be formatted as: <protocol>://<user>:<password>@host:<port>.
/// Note that the format of this value and the supported protocols change slightly between the
/// sync version of esplora (using ureq) and the async version (using reqwest). For more
/// details check with the documentation of the two crates. Both of them are compiled with
/// the socks feature enabled.
/// The proxy is ignored when targeting wasm32.
2021-10-15 00:43:17 +05:30
pub proxy : Option < String > ,
2022-08-29 15:47:37 -04:00
/// Number of parallel requests sent to the esplora service (default: 4)
2022-04-20 23:15:14 -07:00
pub concurrency : Option < u8 > ,
2022-08-29 15:47:37 -04:00
/// Stop searching addresses for transactions after finding an unused gap of this length.
2021-10-15 00:43:17 +05:30
pub stop_gap : u64 ,
2022-08-29 15:47:37 -04:00
/// Socket timeout.
2022-04-20 23:15:14 -07:00
pub timeout : Option < u64 > ,
2021-10-15 00:43:17 +05:30
}
2022-08-29 15:47:37 -04:00
/// Type that can contain any of the blockchain configurations defined by the library.
2021-10-15 00:43:17 +05:30
pub enum BlockchainConfig {
2022-08-29 15:47:37 -04:00
/// Electrum client
2021-10-15 00:43:17 +05:30
Electrum { config : ElectrumConfig } ,
2022-08-29 15:47:37 -04:00
/// Esplora client
2021-10-15 00:43:17 +05:30
Esplora { config : EsploraConfig } ,
2021-10-14 04:23:17 +05:30
}
2022-08-29 15:47:37 -04:00
/// A wallet transaction
2021-10-17 02:28:26 +05:30
#[ derive(Debug, Clone, PartialEq, Eq, Default) ]
2021-10-18 15:48:30 +05:30
pub struct TransactionDetails {
2022-08-29 15:47:37 -04:00
/// Transaction id.
pub txid : String ,
/// Received value (sats)
/// Sum of owned outputs of this transaction.
2021-10-17 02:28:26 +05:30
pub received : u64 ,
2022-08-29 15:47:37 -04:00
/// Sent value (sats)
/// Sum of owned inputs of this transaction.
2021-10-17 02:28:26 +05:30
pub sent : u64 ,
2022-09-01 14:04:36 -04:00
/// Fee value (sats) if confirmed.
2022-08-29 15:47:37 -04:00
/// The availability of the fee depends on the backend. It's never None with an Electrum
/// Server backend, but it could be None with a Bitcoin RPC node without txindex that receive
/// funds while offline.
pub fee : Option < u64 > ,
2022-09-05 11:02:29 -07:00
/// If the transaction is confirmed, contains height and timestamp of the block containing the
/// transaction, unconfirmed transaction contains `None`.
pub confirmation_time : Option < BlockTime > ,
2021-10-18 15:48:30 +05:30
}
2021-11-05 01:13:45 +05:30
impl From < & bdk ::TransactionDetails > for TransactionDetails {
fn from ( x : & bdk ::TransactionDetails ) -> TransactionDetails {
TransactionDetails {
2022-04-20 06:13:49 +05:30
fee : x . fee ,
2021-11-12 12:29:53 -05:00
txid : x . txid . to_string ( ) ,
2021-11-05 01:08:50 +05:30
received : x . received ,
sent : x . sent ,
2022-09-05 11:02:29 -07:00
confirmation_time : x . confirmation_time . clone ( ) ,
2021-11-05 01:08:50 +05:30
}
2021-11-05 00:43:55 +05:30
}
}
2022-04-20 23:15:14 -07:00
struct Blockchain {
blockchain_mutex : Mutex < AnyBlockchain > ,
}
impl Blockchain {
2022-10-21 09:19:00 -04:00
fn new ( blockchain_config : BlockchainConfig ) -> Result < Self , BdkError > {
2022-04-20 23:15:14 -07:00
let any_blockchain_config = match blockchain_config {
BlockchainConfig ::Electrum { config } = > {
AnyBlockchainConfig ::Electrum ( ElectrumBlockchainConfig {
retry : config . retry ,
socks5 : config . socks5 ,
timeout : config . timeout ,
url : config . url ,
stop_gap : usize ::try_from ( config . stop_gap ) . unwrap ( ) ,
} )
}
BlockchainConfig ::Esplora { config } = > {
AnyBlockchainConfig ::Esplora ( EsploraBlockchainConfig {
base_url : config . base_url ,
proxy : config . proxy ,
concurrency : config . concurrency ,
stop_gap : usize ::try_from ( config . stop_gap ) . unwrap ( ) ,
timeout : config . timeout ,
} )
}
} ;
let blockchain = AnyBlockchain ::from_config ( & any_blockchain_config ) ? ;
Ok ( Self {
blockchain_mutex : Mutex ::new ( blockchain ) ,
} )
}
fn get_blockchain ( & self ) -> MutexGuard < AnyBlockchain > {
self . blockchain_mutex . lock ( ) . expect ( " blockchain " )
}
2022-10-17 16:14:55 -05:00
fn broadcast ( & self , psbt : & PartiallySignedTransaction ) -> Result < ( ) , BdkError > {
2022-04-20 23:15:14 -07:00
let tx = psbt . internal . lock ( ) . unwrap ( ) . clone ( ) . extract_tx ( ) ;
2022-04-22 14:10:00 -07:00
self . get_blockchain ( ) . broadcast ( & tx )
2022-04-20 23:15:14 -07:00
}
2022-08-17 16:43:17 -04:00
2022-10-21 09:19:00 -04:00
fn get_height ( & self ) -> Result < u32 , BdkError > {
2022-08-17 16:43:17 -04:00
self . get_blockchain ( ) . get_height ( )
}
2022-10-21 09:19:00 -04:00
fn get_block_hash ( & self , height : u32 ) -> Result < String , BdkError > {
2022-08-17 16:43:17 -04:00
self . get_blockchain ( )
. get_block_hash ( u64 ::from ( height ) )
. map ( | hash | hash . to_string ( ) )
}
2022-04-20 23:15:14 -07:00
}
2022-01-24 20:32:49 +00:00
struct Wallet {
2022-04-20 23:15:14 -07:00
wallet_mutex : Mutex < BdkWallet < AnyDatabase > > ,
2021-10-15 00:43:17 +05:30
}
2022-08-29 15:47:37 -04:00
/// A reference to a transaction output.
2022-06-09 13:28:23 +02:00
#[ derive(Clone, Debug, PartialEq, Eq, Hash) ]
2022-06-08 15:02:29 +02:00
pub struct OutPoint {
2022-08-29 15:47:37 -04:00
/// The referenced transaction's txid.
2022-06-08 15:02:29 +02:00
txid : String ,
2022-08-29 15:47:37 -04:00
/// The index of the referenced output in its transaction's vout.
2022-06-08 15:02:29 +02:00
vout : u32 ,
}
2022-06-09 13:28:23 +02:00
impl From < & OutPoint > for BdkOutPoint {
fn from ( x : & OutPoint ) -> BdkOutPoint {
BdkOutPoint {
txid : Txid ::from_str ( & x . txid ) . unwrap ( ) ,
vout : x . vout ,
}
}
}
2022-09-01 14:04:36 -04:00
pub struct Balance {
// All coinbase outputs not yet matured
pub immature : u64 ,
/// Unconfirmed UTXOs generated by a wallet tx
pub trusted_pending : u64 ,
/// Unconfirmed UTXOs received from an external wallet
pub untrusted_pending : u64 ,
/// Confirmed and immediately spendable balance
pub confirmed : u64 ,
/// Get sum of trusted_pending and confirmed coins
pub spendable : u64 ,
/// Get the whole balance visible to the wallet
pub total : u64 ,
}
impl From < BdkBalance > for Balance {
fn from ( bdk_balance : BdkBalance ) -> Self {
Balance {
immature : bdk_balance . immature ,
trusted_pending : bdk_balance . trusted_pending ,
untrusted_pending : bdk_balance . untrusted_pending ,
confirmed : bdk_balance . confirmed ,
spendable : bdk_balance . get_spendable ( ) ,
total : bdk_balance . get_total ( ) ,
}
}
}
2022-08-29 15:47:37 -04:00
/// A transaction output, which defines new coins to be created from old ones.
2022-06-08 15:02:29 +02:00
pub struct TxOut {
2022-08-29 15:47:37 -04:00
/// The value of the output, in satoshis.
2022-06-08 15:02:29 +02:00
value : u64 ,
2022-08-29 15:47:37 -04:00
/// The address of the output.
2022-06-08 15:02:29 +02:00
address : String ,
}
pub struct LocalUtxo {
outpoint : OutPoint ,
txout : TxOut ,
keychain : KeychainKind ,
2022-06-18 15:38:39 +02:00
is_spent : bool ,
2022-06-08 15:02:29 +02:00
}
2022-06-22 14:48:56 -03:00
// This trait is used to convert the bdk TxOut type with field `script_pubkey: Script`
// into the bdk-ffi TxOut type which has a field `address: String` instead
2022-06-18 15:38:39 +02:00
trait NetworkLocalUtxo {
2022-06-08 15:02:29 +02:00
fn from_utxo ( x : & bdk ::LocalUtxo , network : Network ) -> LocalUtxo ;
}
impl NetworkLocalUtxo for LocalUtxo {
fn from_utxo ( x : & bdk ::LocalUtxo , network : Network ) -> LocalUtxo {
LocalUtxo {
outpoint : OutPoint {
txid : x . outpoint . txid . to_string ( ) ,
vout : x . outpoint . vout ,
} ,
txout : TxOut {
value : x . txout . value ,
2022-09-01 13:05:35 -04:00
address : BdkAddress ::from_script ( & x . txout . script_pubkey , network )
2022-09-29 08:37:51 -04:00
. unwrap ( )
. to_string ( ) ,
2022-06-08 15:02:29 +02:00
} ,
2022-06-18 15:38:39 +02:00
keychain : x . keychain ,
is_spent : x . is_spent ,
2022-06-08 15:02:29 +02:00
}
}
}
2022-08-29 15:47:37 -04:00
/// Trait that logs at level INFO every update received (if any).
2022-04-20 23:15:14 -07:00
pub trait Progress : Send + Sync + 'static {
2022-08-29 15:47:37 -04:00
/// Send a new progress update. The progress value should be in the range 0.0 - 100.0, and the message value is an
/// optional text message that can be displayed to the user.
2021-10-15 01:54:32 +05:30
fn update ( & self , progress : f32 , message : Option < String > ) ;
}
2022-04-20 23:15:14 -07:00
struct ProgressHolder {
progress : Box < dyn Progress > ,
2021-10-15 01:54:32 +05:30
}
2022-04-20 23:15:14 -07:00
impl BdkProgress for ProgressHolder {
2022-10-21 09:19:00 -04:00
fn update ( & self , progress : f32 , message : Option < String > ) -> Result < ( ) , BdkError > {
2022-04-20 23:15:14 -07:00
self . progress . update ( progress , message ) ;
2021-10-15 01:54:32 +05:30
Ok ( ( ) )
}
}
2022-04-20 23:15:14 -07:00
impl fmt ::Debug for ProgressHolder {
fn fmt ( & self , f : & mut fmt ::Formatter < '_ > ) -> fmt ::Result {
f . debug_struct ( " ProgressHolder " ) . finish_non_exhaustive ( )
}
}
2022-03-25 17:37:25 +00:00
#[ derive(Debug) ]
2022-10-17 16:14:55 -05:00
pub struct PartiallySignedTransaction {
internal : Mutex < BdkPartiallySignedTransaction > ,
2021-10-16 16:42:35 +05:30
}
2022-10-17 16:14:55 -05:00
impl PartiallySignedTransaction {
2022-10-21 09:19:00 -04:00
fn new ( psbt_base64 : String ) -> Result < Self , BdkError > {
2022-10-17 16:14:55 -05:00
let psbt : BdkPartiallySignedTransaction = BdkPartiallySignedTransaction ::from_str ( & psbt_base64 ) ? ;
Ok ( PartiallySignedTransaction {
2022-02-24 11:48:19 -08:00
internal : Mutex ::new ( psbt ) ,
} )
}
2022-03-25 17:39:25 +00:00
fn serialize ( & self ) -> String {
2022-02-24 11:48:19 -08:00
let psbt = self . internal . lock ( ) . unwrap ( ) . clone ( ) ;
psbt . to_string ( )
}
2022-04-22 14:10:00 -07:00
fn txid ( & self ) -> String {
let tx = self . internal . lock ( ) . unwrap ( ) . clone ( ) . extract_tx ( ) ;
let txid = tx . txid ( ) ;
txid . to_hex ( )
}
2022-09-28 16:27:07 -04:00
2022-09-01 13:05:35 -04:00
/// Return the transaction as bytes.
fn extract_tx ( & self ) -> Vec < u8 > {
self . internal
. lock ( )
. unwrap ( )
. clone ( )
. extract_tx ( )
. serialize ( )
}
2022-09-28 16:27:07 -04:00
/// Combines this PartiallySignedTransaction with other PSBT as described by BIP 174.
///
/// In accordance with BIP 174 this function is commutative i.e., `A.combine(B) == B.combine(A)`
fn combine (
& self ,
2022-10-17 16:14:55 -05:00
other : Arc < PartiallySignedTransaction > ,
) -> Result < Arc < PartiallySignedTransaction > , BdkError > {
2022-09-28 16:27:07 -04:00
let other_psbt = other . internal . lock ( ) . unwrap ( ) . clone ( ) ;
let mut original_psbt = self . internal . lock ( ) . unwrap ( ) . clone ( ) ;
original_psbt . combine ( other_psbt ) ? ;
2022-10-17 16:14:55 -05:00
Ok ( Arc ::new ( PartiallySignedTransaction {
2022-09-28 16:27:07 -04:00
internal : Mutex ::new ( original_psbt ) ,
} ) )
}
2021-10-16 16:42:35 +05:30
}
2022-08-29 15:47:37 -04:00
/// A Bitcoin wallet.
/// The Wallet acts as a way of coherently interfacing with output descriptors and related transactions. Its main components are:
/// 1. Output descriptors from which it can derive addresses.
/// 2. A Database where it tracks transactions and utxos related to the descriptors.
/// 3. Signers that can contribute signatures to addresses instantiated from the descriptors.
2022-01-24 20:32:49 +00:00
impl Wallet {
2021-10-15 00:43:17 +05:30
fn new (
descriptor : String ,
2021-10-21 14:50:52 +05:30
change_descriptor : Option < String > ,
2021-10-15 00:43:17 +05:30
network : Network ,
database_config : DatabaseConfig ,
2022-10-21 09:19:00 -04:00
) -> Result < Self , BdkError > {
2021-10-15 00:43:17 +05:30
let any_database_config = match database_config {
2022-03-01 16:14:21 -05:00
DatabaseConfig ::Memory = > AnyDatabaseConfig ::Memory ( ( ) ) ,
2021-10-15 00:43:17 +05:30
DatabaseConfig ::Sled { config } = > AnyDatabaseConfig ::Sled ( config ) ,
2022-03-11 22:45:37 -06:00
DatabaseConfig ::Sqlite { config } = > AnyDatabaseConfig ::Sqlite ( config ) ,
2021-10-15 00:43:17 +05:30
} ;
let database = AnyDatabase ::from_config ( & any_database_config ) ? ;
2022-01-30 21:22:40 +00:00
let wallet_mutex = Mutex ::new ( BdkWallet ::new (
2021-10-15 00:43:17 +05:30
& descriptor ,
2022-03-25 15:18:25 +00:00
change_descriptor . as_ref ( ) ,
2021-10-15 00:43:17 +05:30
network ,
database ,
) ? ) ;
2022-01-30 21:22:40 +00:00
Ok ( Wallet { wallet_mutex } )
2021-10-15 00:43:17 +05:30
}
2021-10-15 00:48:48 +05:30
2022-04-20 23:15:14 -07:00
fn get_wallet ( & self ) -> MutexGuard < BdkWallet < AnyDatabase > > {
2022-03-20 19:59:20 -05:00
self . wallet_mutex . lock ( ) . expect ( " wallet " )
}
2022-08-29 15:47:37 -04:00
/// Get the Bitcoin network the wallet is using.
2022-08-18 14:35:17 -04:00
fn network ( & self ) -> Network {
2022-01-24 20:32:49 +00:00
self . get_wallet ( ) . network ( )
2021-10-15 00:48:48 +05:30
}
2021-10-15 01:54:32 +05:30
2022-08-29 15:47:37 -04:00
/// Sync the internal database with the blockchain.
2021-10-15 01:54:32 +05:30
fn sync (
& self ,
2022-04-20 23:15:14 -07:00
blockchain : & Blockchain ,
progress : Option < Box < dyn Progress > > ,
2022-10-21 09:19:00 -04:00
) -> Result < ( ) , BdkError > {
2022-04-20 23:15:14 -07:00
let bdk_sync_opts = BdkSyncOptions {
progress : progress . map ( | p | {
Box ::new ( ProgressHolder { progress : p } )
as Box < ( dyn bdk ::blockchain ::Progress + 'static ) >
} ) ,
} ;
let blockchain = blockchain . get_blockchain ( ) ;
self . get_wallet ( ) . sync ( blockchain . deref ( ) , bdk_sync_opts )
2021-10-15 01:54:32 +05:30
}
2021-10-15 03:40:33 +05:30
2022-08-29 15:47:37 -04:00
/// Return a derived address using the external descriptor, see AddressIndex for available address index selection
/// strategies. If none of the keys in the descriptor are derivable (i.e. the descriptor does not end with a * character)
/// then the same address will always be returned for any AddressIndex.
2022-10-21 09:19:00 -04:00
fn get_address ( & self , address_index : AddressIndex ) -> Result < AddressInfo , BdkError > {
2022-05-16 12:07:11 -04:00
self . get_wallet ( )
. get_address ( address_index . into ( ) )
. map ( AddressInfo ::from )
2022-03-20 19:59:20 -05:00
}
2022-08-29 15:47:37 -04:00
/// Return the balance, meaning the sum of this wallet’ s unspent outputs’ values. Note that this method only operates
/// on the internal database, which first needs to be Wallet.sync manually.
2022-10-21 09:19:00 -04:00
fn get_balance ( & self ) -> Result < Balance , BdkError > {
2022-09-01 14:04:36 -04:00
self . get_wallet ( ) . get_balance ( ) . map ( | b | b . into ( ) )
2022-03-20 19:59:20 -05:00
}
2022-08-29 15:47:37 -04:00
/// Sign a transaction with all the wallet’ s signers.
2022-10-17 16:14:55 -05:00
fn sign ( & self , psbt : & PartiallySignedTransaction ) -> Result < bool , BdkError > {
2022-03-20 19:59:20 -05:00
let mut psbt = psbt . internal . lock ( ) . unwrap ( ) ;
2022-06-10 08:41:10 -03:00
self . get_wallet ( ) . sign ( & mut psbt , SignOptions ::default ( ) )
2022-03-20 19:59:20 -05:00
}
2022-08-29 15:47:37 -04:00
/// Return the list of transactions made and received by the wallet. Note that this method only operate on the internal database, which first needs to be [Wallet.sync] manually.
2022-10-21 09:19:00 -04:00
fn list_transactions ( & self ) -> Result < Vec < TransactionDetails > , BdkError > {
2022-09-05 11:02:29 -07:00
let transaction_details = self . get_wallet ( ) . list_transactions ( true ) ? ;
Ok ( transaction_details
. iter ( )
. map ( TransactionDetails ::from )
. collect ( ) )
2022-03-20 19:59:20 -05:00
}
2022-06-08 15:02:29 +02:00
2022-08-29 15:47:37 -04:00
/// Return the list of unspent outputs of this wallet. Note that this method only operates on the internal database,
/// which first needs to be Wallet.sync manually.
2022-10-21 09:19:00 -04:00
fn list_unspent ( & self ) -> Result < Vec < LocalUtxo > , BdkError > {
2022-06-08 15:02:29 +02:00
let unspents = self . get_wallet ( ) . list_unspent ( ) ? ;
2022-06-18 15:38:39 +02:00
Ok ( unspents
. iter ( )
2022-08-18 14:35:17 -04:00
. map ( | u | LocalUtxo ::from_utxo ( u , self . network ( ) ) )
2022-06-18 15:38:39 +02:00
. collect ( ) )
2022-06-08 15:02:29 +02:00
}
2021-10-15 00:43:17 +05:30
}
2022-10-21 09:19:00 -04:00
fn to_script_pubkey ( address : & str ) -> Result < BdkScript , BdkError > {
2022-09-01 13:05:35 -04:00
BdkAddress ::from_str ( address )
2022-03-31 17:26:32 +01:00
. map ( | x | x . script_pubkey ( ) )
2022-10-21 09:19:00 -04:00
. map_err ( | e | BdkError ::Generic ( e . to_string ( ) ) )
2022-03-31 17:26:32 +01:00
}
2022-09-01 13:05:35 -04:00
/// A Bitcoin address.
struct Address {
address : BdkAddress ,
}
impl Address {
2022-10-21 09:19:00 -04:00
fn new ( address : String ) -> Result < Self , BdkError > {
2022-09-01 13:05:35 -04:00
BdkAddress ::from_str ( address . as_str ( ) )
. map ( | a | Address { address : a } )
2022-10-21 09:19:00 -04:00
. map_err ( | e | BdkError ::Generic ( e . to_string ( ) ) )
2022-09-01 13:05:35 -04:00
}
fn script_pubkey ( & self ) -> Arc < Script > {
Arc ::new ( Script {
script : self . address . script_pubkey ( ) ,
} )
}
}
/// A Bitcoin script.
#[ derive(Clone) ]
pub struct Script {
script : BdkScript ,
}
impl Script {
fn new ( raw_output_script : Vec < u8 > ) -> Self {
let script : BdkScript = BdkScript ::from ( raw_output_script ) ;
Script { script }
}
}
2022-04-20 15:52:40 -07:00
#[ derive(Clone, Debug) ]
2022-04-15 21:04:21 +01:00
enum RbfValue {
Default ,
Value ( u32 ) ,
}
2022-10-18 17:13:15 -05:00
/// The result after calling the TxBuilder finish() function. Contains unsigned PSBT and
/// transaction details.
pub struct TxBuilderResult {
2022-10-17 16:14:55 -05:00
pub psbt : Arc < PartiallySignedTransaction > ,
2022-10-18 17:13:15 -05:00
pub transaction_details : TransactionDetails ,
}
2022-08-29 15:47:37 -04:00
/// A transaction builder.
/// After creating the TxBuilder, you set options on it until finally calling finish to consume the builder and generate the transaction.
/// Each method on the TxBuilder returns an instance of a new TxBuilder with the option set/added.
2022-04-20 15:52:40 -07:00
#[ derive(Clone, Debug) ]
2022-03-25 17:24:21 +00:00
struct TxBuilder {
2022-09-01 13:05:35 -04:00
recipients : Vec < ( BdkScript , u64 ) > ,
2022-06-09 13:28:23 +02:00
utxos : Vec < OutPoint > ,
unspendable : HashSet < OutPoint > ,
change_policy : ChangeSpendPolicy ,
manually_selected_only : bool ,
2022-03-25 17:24:21 +00:00
fee_rate : Option < f32 > ,
2022-06-09 13:28:23 +02:00
fee_absolute : Option < u64 > ,
2022-03-31 17:17:24 +01:00
drain_wallet : bool ,
2022-03-31 17:17:43 +01:00
drain_to : Option < String > ,
2022-04-15 21:04:21 +01:00
rbf : Option < RbfValue > ,
2022-06-23 04:20:02 -07:00
data : Vec < u8 > ,
2022-03-25 17:24:21 +00:00
}
impl TxBuilder {
fn new ( ) -> Self {
TxBuilder {
recipients : Vec ::new ( ) ,
2022-06-09 13:28:23 +02:00
utxos : Vec ::new ( ) ,
unspendable : HashSet ::new ( ) ,
change_policy : ChangeSpendPolicy ::ChangeAllowed ,
manually_selected_only : false ,
2022-03-25 17:24:21 +00:00
fee_rate : None ,
2022-06-09 13:28:23 +02:00
fee_absolute : None ,
2022-03-31 17:17:24 +01:00
drain_wallet : false ,
2022-03-31 17:17:43 +01:00
drain_to : None ,
2022-04-15 21:04:21 +01:00
rbf : None ,
2022-06-23 04:20:02 -07:00
data : Vec ::new ( ) ,
2022-03-25 17:24:21 +00:00
}
}
2022-08-29 15:47:37 -04:00
/// Add a recipient to the internal list.
2022-09-01 13:05:35 -04:00
fn add_recipient ( & self , script : Arc < Script > , amount : u64 ) -> Arc < Self > {
let mut recipients : Vec < ( BdkScript , u64 ) > = self . recipients . clone ( ) ;
recipients . append ( & mut vec! [ ( script . script . clone ( ) , amount ) ] ) ;
2022-03-25 17:24:21 +00:00
Arc ::new ( TxBuilder {
recipients ,
2022-05-12 22:50:03 +01:00
.. self . clone ( )
2022-03-25 17:24:21 +00:00
} )
}
2022-09-01 13:05:35 -04:00
fn set_recipients ( & self , recipients : Vec < ScriptAmount > ) -> Arc < Self > {
2022-08-29 06:58:46 -07:00
let recipients = recipients
. iter ( )
2022-09-01 13:05:35 -04:00
. map ( | script_amount | ( script_amount . script . script . clone ( ) , script_amount . amount ) )
2022-08-29 06:58:46 -07:00
. collect ( ) ;
Arc ::new ( TxBuilder {
recipients ,
.. self . clone ( )
} )
}
2022-08-29 15:47:37 -04:00
/// Add a utxo to the internal list of unspendable utxos. It’ s important to note that the "must-be-spent"
/// utxos added with [TxBuilder.addUtxo] have priority over this. See the Rust docs of the two linked methods for more details.
2022-06-09 13:28:23 +02:00
fn add_unspendable ( & self , unspendable : OutPoint ) -> Arc < Self > {
let mut unspendable_hash_set = self . unspendable . clone ( ) ;
unspendable_hash_set . insert ( unspendable ) ;
Arc ::new ( TxBuilder {
unspendable : unspendable_hash_set ,
.. self . clone ( )
} )
}
2022-08-29 15:47:37 -04:00
/// Add an outpoint to the internal list of UTXOs that must be spent. These have priority over the "unspendable"
/// utxos, meaning that if a utxo is present both in the "utxos" and the "unspendable" list, it will be spent.
2022-06-09 13:28:23 +02:00
fn add_utxo ( & self , outpoint : OutPoint ) -> Arc < Self > {
self . add_utxos ( vec! [ outpoint ] )
}
2022-08-29 15:47:37 -04:00
/// Add the list of outpoints to the internal list of UTXOs that must be spent. If an error occurs while adding
/// any of the UTXOs then none of them are added and the error is returned. These have priority over the "unspendable"
/// utxos, meaning that if a utxo is present both in the "utxos" and the "unspendable" list, it will be spent.
2022-06-09 13:28:23 +02:00
fn add_utxos ( & self , mut outpoints : Vec < OutPoint > ) -> Arc < Self > {
let mut utxos = self . utxos . to_vec ( ) ;
utxos . append ( & mut outpoints ) ;
Arc ::new ( TxBuilder {
utxos ,
.. self . clone ( )
} )
}
2022-08-29 15:47:37 -04:00
/// Do not spend change outputs. This effectively adds all the change outputs to the "unspendable" list. See TxBuilder.unspendable.
2022-06-09 13:28:23 +02:00
fn do_not_spend_change ( & self ) -> Arc < Self > {
Arc ::new ( TxBuilder {
change_policy : ChangeSpendPolicy ::ChangeForbidden ,
.. self . clone ( )
} )
}
2022-08-29 15:47:37 -04:00
/// Only spend utxos added by [add_utxo]. The wallet will not add additional utxos to the transaction even if they are
/// needed to make the transaction valid.
2022-06-09 13:28:23 +02:00
fn manually_selected_only ( & self ) -> Arc < Self > {
Arc ::new ( TxBuilder {
manually_selected_only : true ,
.. self . clone ( )
} )
}
2022-08-29 15:47:37 -04:00
/// Only spend change outputs. This effectively adds all the non-change outputs to the "unspendable" list. See TxBuilder.unspendable.
2022-06-09 13:28:23 +02:00
fn only_spend_change ( & self ) -> Arc < Self > {
Arc ::new ( TxBuilder {
change_policy : ChangeSpendPolicy ::OnlyChange ,
.. self . clone ( )
} )
}
2022-08-29 15:47:37 -04:00
/// Replace the internal list of unspendable utxos with a new list. It’ s important to note that the "must-be-spent" utxos added with
/// TxBuilder.addUtxo have priority over these. See the Rust docs of the two linked methods for more details.
2022-06-09 13:28:23 +02:00
fn unspendable ( & self , unspendable : Vec < OutPoint > ) -> Arc < Self > {
Arc ::new ( TxBuilder {
unspendable : unspendable . into_iter ( ) . collect ( ) ,
.. self . clone ( )
} )
}
2022-08-29 15:47:37 -04:00
/// Set a custom fee rate.
2022-03-25 17:24:21 +00:00
fn fee_rate ( & self , sat_per_vb : f32 ) -> Arc < Self > {
Arc ::new ( TxBuilder {
fee_rate : Some ( sat_per_vb ) ,
2022-05-12 22:50:03 +01:00
.. self . clone ( )
2022-03-31 17:17:24 +01:00
} )
}
2022-08-29 15:47:37 -04:00
/// Set an absolute fee.
2022-06-09 13:28:23 +02:00
fn fee_absolute ( & self , fee_amount : u64 ) -> Arc < Self > {
Arc ::new ( TxBuilder {
fee_absolute : Some ( fee_amount ) ,
.. self . clone ( )
} )
}
2022-08-29 15:47:37 -04:00
/// Spend all the available inputs. This respects filters like TxBuilder.unspendable and the change policy.
2022-03-31 17:17:24 +01:00
fn drain_wallet ( & self ) -> Arc < Self > {
Arc ::new ( TxBuilder {
drain_wallet : true ,
2022-05-12 22:50:03 +01:00
.. self . clone ( )
2022-03-31 17:17:43 +01:00
} )
}
2022-08-29 15:47:37 -04:00
/// Sets the address to drain excess coins to. Usually, when there are excess coins they are sent to a change address
/// generated by the wallet. This option replaces the usual change address with an arbitrary ScriptPubKey of your choosing.
/// Just as with a change output, if the drain output is not needed (the excess coins are too small) it will not be included
/// in the resulting transaction. The only difference is that it is valid to use drain_to without setting any ordinary recipients
/// with add_recipient (but it is perfectly fine to add recipients as well). If you choose not to set any recipients, you should
/// either provide the utxos that the transaction should spend via add_utxos, or set drain_wallet to spend all of them.
/// When bumping the fees of a transaction made with this option, you probably want to use BumpFeeTxBuilder.allow_shrinking
/// to allow this output to be reduced to pay for the extra fees.
2022-03-31 17:17:43 +01:00
fn drain_to ( & self , address : String ) -> Arc < Self > {
Arc ::new ( TxBuilder {
drain_to : Some ( address ) ,
2022-05-12 22:50:03 +01:00
.. self . clone ( )
2022-04-15 21:04:21 +01:00
} )
}
2022-08-29 15:47:37 -04:00
/// Enable signaling RBF. This will use the default `nsequence` value of `0xFFFFFFFD`.
2022-04-15 21:04:21 +01:00
fn enable_rbf ( & self ) -> Arc < Self > {
Arc ::new ( TxBuilder {
rbf : Some ( RbfValue ::Default ) ,
2022-05-12 22:50:03 +01:00
.. self . clone ( )
2022-04-15 21:04:21 +01:00
} )
}
2022-08-29 15:47:37 -04:00
/// Enable signaling RBF with a specific nSequence value. This can cause conflicts if the wallet's descriptors contain an
/// "older" (OP_CSV) operator and the given `nsequence` is lower than the CSV value. If the `nsequence` is higher than `0xFFFFFFFD`
/// an error will be thrown, since it would not be a valid nSequence to signal RBF.
2022-04-15 21:04:21 +01:00
fn enable_rbf_with_sequence ( & self , nsequence : u32 ) -> Arc < Self > {
Arc ::new ( TxBuilder {
rbf : Some ( RbfValue ::Value ( nsequence ) ) ,
2022-05-12 22:50:03 +01:00
.. self . clone ( )
2022-03-25 17:24:21 +00:00
} )
}
2022-08-29 15:47:37 -04:00
/// Add data as an output using OP_RETURN.
2022-06-23 04:20:02 -07:00
fn add_data ( & self , data : Vec < u8 > ) -> Arc < Self > {
Arc ::new ( TxBuilder {
data ,
.. self . clone ( )
} )
}
2022-08-29 15:47:37 -04:00
/// Finish building the transaction. Returns the BIP174 PSBT.
2022-10-21 09:19:00 -04:00
fn finish ( & self , wallet : & Wallet ) -> Result < TxBuilderResult , BdkError > {
2022-03-25 17:24:21 +00:00
let wallet = wallet . get_wallet ( ) ;
let mut tx_builder = wallet . build_tx ( ) ;
2022-09-01 13:05:35 -04:00
for ( script , amount ) in & self . recipients {
tx_builder . add_recipient ( script . clone ( ) , * amount ) ;
2022-03-25 17:24:21 +00:00
}
2022-06-09 13:28:23 +02:00
tx_builder . change_policy ( self . change_policy ) ;
if ! self . utxos . is_empty ( ) {
let bdk_utxos : Vec < BdkOutPoint > = self . utxos . iter ( ) . map ( BdkOutPoint ::from ) . collect ( ) ;
2022-07-21 17:00:21 +02:00
let utxos : & [ BdkOutPoint ] = & bdk_utxos ;
2022-06-09 13:28:23 +02:00
tx_builder . add_utxos ( utxos ) ? ;
}
if ! self . unspendable . is_empty ( ) {
let bdk_unspendable : Vec < BdkOutPoint > =
self . unspendable . iter ( ) . map ( BdkOutPoint ::from ) . collect ( ) ;
tx_builder . unspendable ( bdk_unspendable ) ;
}
if self . manually_selected_only {
tx_builder . manually_selected_only ( ) ;
}
2022-03-25 17:24:21 +00:00
if let Some ( sat_per_vb ) = self . fee_rate {
tx_builder . fee_rate ( FeeRate ::from_sat_per_vb ( sat_per_vb ) ) ;
}
2022-06-09 13:28:23 +02:00
if let Some ( fee_amount ) = self . fee_absolute {
tx_builder . fee_absolute ( fee_amount ) ;
}
2022-03-31 17:17:24 +01:00
if self . drain_wallet {
tx_builder . drain_wallet ( ) ;
}
2022-03-31 17:17:43 +01:00
if let Some ( address ) = & self . drain_to {
2022-03-31 17:26:32 +01:00
tx_builder . drain_to ( to_script_pubkey ( address ) ? ) ;
2022-03-31 17:17:43 +01:00
}
2022-04-15 21:04:21 +01:00
if let Some ( rbf ) = & self . rbf {
match * rbf {
RbfValue ::Default = > {
tx_builder . enable_rbf ( ) ;
}
RbfValue ::Value ( nsequence ) = > {
2022-11-01 14:15:41 -04:00
tx_builder . enable_rbf_with_sequence ( Sequence ( nsequence ) ) ;
2022-04-15 21:04:21 +01:00
}
}
}
2022-06-23 04:20:02 -07:00
if ! & self . data . is_empty ( ) {
2022-07-25 13:02:41 -07:00
tx_builder . add_data ( self . data . as_slice ( ) ) ;
2022-06-23 04:20:02 -07:00
}
2022-03-25 17:24:21 +00:00
tx_builder
. finish ( )
2022-10-18 17:13:15 -05:00
. map ( | ( psbt , tx_details ) | TxBuilderResult {
2022-10-17 16:14:55 -05:00
psbt : Arc ::new ( PartiallySignedTransaction {
2022-10-18 17:13:15 -05:00
internal : Mutex ::new ( psbt ) ,
} ) ,
transaction_details : TransactionDetails ::from ( & tx_details ) ,
2022-03-25 17:24:21 +00:00
} )
}
}
2022-08-29 15:47:37 -04:00
/// The BumpFeeTxBuilder is used to bump the fee on a transaction that has been broadcast and has its RBF flag set to true.
2022-05-12 22:50:03 +01:00
#[ derive(Clone) ]
2022-05-02 19:23:47 -07:00
struct BumpFeeTxBuilder {
txid : String ,
fee_rate : f32 ,
allow_shrinking : Option < String > ,
2022-05-06 09:59:07 -07:00
rbf : Option < RbfValue > ,
2022-05-02 19:23:47 -07:00
}
impl BumpFeeTxBuilder {
fn new ( txid : String , fee_rate : f32 ) -> Self {
Self {
txid ,
fee_rate ,
allow_shrinking : None ,
rbf : None ,
}
}
2022-08-29 15:47:37 -04:00
/// Explicitly tells the wallet that it is allowed to reduce the amount of the output matching this script_pubkey
/// in order to bump the transaction fee. Without specifying this the wallet will attempt to find a change output to
/// shrink instead. Note that the output may shrink to below the dust limit and therefore be removed. If it is preserved
/// then it is currently not guaranteed to be in the same position as it was originally. Returns an error if script_pubkey
/// can’ t be found among the recipients of the transaction we are bumping.
2022-05-02 19:23:47 -07:00
fn allow_shrinking ( & self , address : String ) -> Arc < Self > {
Arc ::new ( Self {
allow_shrinking : Some ( address ) ,
2022-05-12 22:50:03 +01:00
.. self . clone ( )
2022-05-02 19:23:47 -07:00
} )
}
2022-08-29 15:47:37 -04:00
/// Enable signaling RBF. This will use the default `nsequence` value of `0xFFFFFFFD`.
2022-05-02 19:23:47 -07:00
fn enable_rbf ( & self ) -> Arc < Self > {
Arc ::new ( Self {
2022-05-06 09:59:07 -07:00
rbf : Some ( RbfValue ::Default ) ,
2022-05-12 22:50:03 +01:00
.. self . clone ( )
2022-05-02 19:23:47 -07:00
} )
}
2022-08-29 15:47:37 -04:00
/// Enable signaling RBF with a specific nSequence value. This can cause conflicts if the wallet's descriptors contain an
/// "older" (OP_CSV) operator and the given `nsequence` is lower than the CSV value. If the `nsequence` is higher than `0xFFFFFFFD`
/// an error will be thrown, since it would not be a valid nSequence to signal RBF.
2022-05-02 19:23:47 -07:00
fn enable_rbf_with_sequence ( & self , nsequence : u32 ) -> Arc < Self > {
Arc ::new ( Self {
2022-05-06 09:59:07 -07:00
rbf : Some ( RbfValue ::Value ( nsequence ) ) ,
2022-05-12 22:50:03 +01:00
.. self . clone ( )
2022-05-02 19:23:47 -07:00
} )
}
2022-08-29 15:47:37 -04:00
/// Finish building the transaction. Returns the BIP174 PSBT.
2022-10-17 16:14:55 -05:00
fn finish ( & self , wallet : & Wallet ) -> Result < Arc < PartiallySignedTransaction > , BdkError > {
2022-05-02 19:23:47 -07:00
let wallet = wallet . get_wallet ( ) ;
let txid = Txid ::from_str ( self . txid . as_str ( ) ) ? ;
let mut tx_builder = wallet . build_fee_bump ( txid ) ? ;
tx_builder . fee_rate ( FeeRate ::from_sat_per_vb ( self . fee_rate ) ) ;
2022-05-06 09:59:07 -07:00
if let Some ( allow_shrinking ) = & self . allow_shrinking {
2022-10-21 09:19:00 -04:00
let address = BdkAddress ::from_str ( allow_shrinking )
. map_err ( | e | BdkError ::Generic ( e . to_string ( ) ) ) ? ;
2022-05-06 09:59:07 -07:00
let script = address . script_pubkey ( ) ;
tx_builder . allow_shrinking ( script ) ? ;
}
2022-05-02 19:23:47 -07:00
if let Some ( rbf ) = & self . rbf {
match * rbf {
RbfValue ::Default = > {
tx_builder . enable_rbf ( ) ;
}
RbfValue ::Value ( nsequence ) = > {
2022-11-01 14:15:41 -04:00
tx_builder . enable_rbf_with_sequence ( Sequence ( nsequence ) ) ;
2022-05-02 19:23:47 -07:00
}
}
}
tx_builder
. finish ( )
2022-10-17 16:14:55 -05:00
. map ( | ( psbt , _ ) | PartiallySignedTransaction {
2022-05-02 19:23:47 -07:00
internal : Mutex ::new ( psbt ) ,
} )
. map ( Arc ::new )
}
}
2022-10-28 10:19:57 +05:30
/// Mnemonic phrases are a human-readable version of the private keys.
/// Supported number of words are 12, 15, 18, 21 and 24.
struct Mnemonic {
internal : BdkMnemonic ,
}
impl Mnemonic {
/// Generates Mnemonic with a random entropy
fn new ( word_count : WordCount ) -> Self {
let generated_key : GeneratedKey < _ , BareCtx > =
BdkMnemonic ::generate ( ( word_count , Language ::English ) ) . unwrap ( ) ;
let mnemonic = BdkMnemonic ::parse_in ( Language ::English , generated_key . to_string ( ) ) . unwrap ( ) ;
Mnemonic { internal : mnemonic }
}
/// Parse a Mnemonic with given string
fn from_str ( mnemonic : String ) -> Result < Self , BdkError > {
BdkMnemonic ::from_str ( & mnemonic )
. map ( | m | Mnemonic { internal : m } )
. map_err ( | e | BdkError ::Generic ( e . to_string ( ) ) )
}
/// Create a new Mnemonic in the specified language from the given entropy.
/// Entropy must be a multiple of 32 bits (4 bytes) and 128-256 bits in length.
fn from_entropy ( entropy : Vec < u8 > ) -> Result < Self , BdkError > {
BdkMnemonic ::from_entropy ( entropy . as_slice ( ) )
. map ( | m | Mnemonic { internal : m } )
. map_err ( | e | BdkError ::Generic ( e . to_string ( ) ) )
}
/// Returns Mnemonic as string
fn as_string ( & self ) -> String {
self . internal . to_string ( )
}
2022-08-09 14:23:17 +05:30
}
2022-08-09 14:27:19 +05:30
struct DerivationPath {
derivation_path_mutex : Mutex < BdkDerivationPath > ,
}
impl DerivationPath {
2022-10-21 09:19:00 -04:00
fn new ( path : String ) -> Result < Self , BdkError > {
2022-08-09 14:27:19 +05:30
BdkDerivationPath ::from_str ( & path )
. map ( | x | DerivationPath {
derivation_path_mutex : Mutex ::new ( x ) ,
} )
2022-10-21 09:19:00 -04:00
. map_err ( | e | BdkError ::Generic ( e . to_string ( ) ) )
2022-08-09 14:27:19 +05:30
}
}
2022-08-09 14:39:15 +05:30
struct DescriptorSecretKey {
descriptor_secret_key_mutex : Mutex < BdkDescriptorSecretKey > ,
}
impl DescriptorSecretKey {
2022-10-28 10:19:57 +05:30
fn new ( network : Network , mnemonic : Arc < Mnemonic > , password : Option < String > ) -> Self {
let mnemonic = mnemonic . internal . clone ( ) ;
let xkey : ExtendedKey = ( mnemonic , password ) . into_extended_key ( ) . unwrap ( ) ;
2022-08-09 14:39:15 +05:30
let descriptor_secret_key = BdkDescriptorSecretKey ::XPrv ( DescriptorXKey {
origin : None ,
xkey : xkey . into_xprv ( network ) . unwrap ( ) ,
derivation_path : BdkDerivationPath ::master ( ) ,
wildcard : bdk ::descriptor ::Wildcard ::Unhardened ,
} ) ;
2022-10-28 10:19:57 +05:30
Self {
2022-08-09 14:39:15 +05:30
descriptor_secret_key_mutex : Mutex ::new ( descriptor_secret_key ) ,
2022-10-28 10:19:57 +05:30
}
2022-08-09 14:39:15 +05:30
}
2022-10-21 09:19:00 -04:00
fn derive ( & self , path : Arc < DerivationPath > ) -> Result < Arc < Self > , BdkError > {
2022-08-09 14:39:15 +05:30
let secp = Secp256k1 ::new ( ) ;
let descriptor_secret_key = self . descriptor_secret_key_mutex . lock ( ) . unwrap ( ) ;
let path = path . derivation_path_mutex . lock ( ) . unwrap ( ) . deref ( ) . clone ( ) ;
2022-08-09 14:43:06 +05:30
match descriptor_secret_key . deref ( ) {
BdkDescriptorSecretKey ::XPrv ( descriptor_x_key ) = > {
let derived_xprv = descriptor_x_key . xkey . derive_priv ( & secp , & path ) ? ;
let key_source = match descriptor_x_key . origin . clone ( ) {
Some ( ( fingerprint , origin_path ) ) = > ( fingerprint , origin_path . extend ( path ) ) ,
None = > ( descriptor_x_key . xkey . fingerprint ( & secp ) , path ) ,
} ;
let derived_descriptor_secret_key = BdkDescriptorSecretKey ::XPrv ( DescriptorXKey {
origin : Some ( key_source ) ,
xkey : derived_xprv ,
derivation_path : BdkDerivationPath ::default ( ) ,
wildcard : descriptor_x_key . wildcard ,
} ) ;
Ok ( Arc ::new ( Self {
descriptor_secret_key_mutex : Mutex ::new ( derived_descriptor_secret_key ) ,
} ) )
}
2022-11-01 14:15:41 -04:00
BdkDescriptorSecretKey ::Single ( _ ) = > {
2022-08-09 14:43:06 +05:30
unreachable! ( )
}
2022-08-09 14:39:15 +05:30
}
}
fn extend ( & self , path : Arc < DerivationPath > ) -> Arc < Self > {
let descriptor_secret_key = self . descriptor_secret_key_mutex . lock ( ) . unwrap ( ) ;
let path = path . derivation_path_mutex . lock ( ) . unwrap ( ) . deref ( ) . clone ( ) ;
2022-08-09 14:43:06 +05:30
match descriptor_secret_key . deref ( ) {
BdkDescriptorSecretKey ::XPrv ( descriptor_x_key ) = > {
let extended_path = descriptor_x_key . derivation_path . extend ( path ) ;
let extended_descriptor_secret_key = BdkDescriptorSecretKey ::XPrv ( DescriptorXKey {
origin : descriptor_x_key . origin . clone ( ) ,
xkey : descriptor_x_key . xkey ,
derivation_path : extended_path ,
wildcard : descriptor_x_key . wildcard ,
} ) ;
Arc ::new ( Self {
descriptor_secret_key_mutex : Mutex ::new ( extended_descriptor_secret_key ) ,
} )
}
2022-11-01 14:15:41 -04:00
BdkDescriptorSecretKey ::Single ( _ ) = > {
2022-08-09 14:43:06 +05:30
unreachable! ( )
}
2022-08-09 14:39:15 +05:30
}
}
fn as_public ( & self ) -> Arc < DescriptorPublicKey > {
let secp = Secp256k1 ::new ( ) ;
let descriptor_public_key = self
. descriptor_secret_key_mutex
. lock ( )
. unwrap ( )
2022-11-01 14:15:41 -04:00
. to_public ( & secp )
2022-08-09 14:39:15 +05:30
. unwrap ( ) ;
Arc ::new ( DescriptorPublicKey {
descriptor_public_key_mutex : Mutex ::new ( descriptor_public_key ) ,
} )
}
2022-09-26 10:36:40 -04:00
/// Get the private key as bytes.
2022-09-30 19:32:08 -04:00
fn secret_bytes ( & self ) -> Vec < u8 > {
2022-09-26 10:36:40 -04:00
let descriptor_secret_key = self . descriptor_secret_key_mutex . lock ( ) . unwrap ( ) ;
2022-09-30 19:32:08 -04:00
let secret_bytes : Vec < u8 > = match descriptor_secret_key . deref ( ) {
2022-09-26 10:36:40 -04:00
BdkDescriptorSecretKey ::XPrv ( descriptor_x_key ) = > {
descriptor_x_key . xkey . private_key . secret_bytes ( ) . to_vec ( )
}
2022-11-01 14:15:41 -04:00
BdkDescriptorSecretKey ::Single ( _ ) = > {
2022-09-26 11:01:46 -04:00
unreachable! ( )
2022-09-26 10:36:40 -04:00
}
} ;
2022-09-30 19:32:08 -04:00
secret_bytes
2022-09-26 10:36:40 -04:00
}
2022-08-09 14:39:15 +05:30
fn as_string ( & self ) -> String {
self . descriptor_secret_key_mutex . lock ( ) . unwrap ( ) . to_string ( )
}
}
struct DescriptorPublicKey {
descriptor_public_key_mutex : Mutex < BdkDescriptorPublicKey > ,
}
impl DescriptorPublicKey {
2022-10-21 09:19:00 -04:00
fn derive ( & self , path : Arc < DerivationPath > ) -> Result < Arc < Self > , BdkError > {
2022-08-09 14:39:15 +05:30
let secp = Secp256k1 ::new ( ) ;
let descriptor_public_key = self . descriptor_public_key_mutex . lock ( ) . unwrap ( ) ;
let path = path . derivation_path_mutex . lock ( ) . unwrap ( ) . deref ( ) . clone ( ) ;
2022-08-09 14:43:06 +05:30
match descriptor_public_key . deref ( ) {
BdkDescriptorPublicKey ::XPub ( descriptor_x_key ) = > {
let derived_xpub = descriptor_x_key . xkey . derive_pub ( & secp , & path ) ? ;
let key_source = match descriptor_x_key . origin . clone ( ) {
Some ( ( fingerprint , origin_path ) ) = > ( fingerprint , origin_path . extend ( path ) ) ,
None = > ( descriptor_x_key . xkey . fingerprint ( ) , path ) ,
} ;
let derived_descriptor_public_key = BdkDescriptorPublicKey ::XPub ( DescriptorXKey {
origin : Some ( key_source ) ,
xkey : derived_xpub ,
derivation_path : BdkDerivationPath ::default ( ) ,
wildcard : descriptor_x_key . wildcard ,
} ) ;
Ok ( Arc ::new ( Self {
descriptor_public_key_mutex : Mutex ::new ( derived_descriptor_public_key ) ,
} ) )
}
2022-11-01 14:15:41 -04:00
BdkDescriptorPublicKey ::Single ( _ ) = > {
2022-08-09 14:43:06 +05:30
unreachable! ( )
}
2022-08-09 14:39:15 +05:30
}
}
fn extend ( & self , path : Arc < DerivationPath > ) -> Arc < Self > {
2022-08-09 14:43:06 +05:30
let descriptor_public_key = self . descriptor_public_key_mutex . lock ( ) . unwrap ( ) ;
2022-08-09 14:39:15 +05:30
let path = path . derivation_path_mutex . lock ( ) . unwrap ( ) . deref ( ) . clone ( ) ;
2022-08-09 14:43:06 +05:30
match descriptor_public_key . deref ( ) {
BdkDescriptorPublicKey ::XPub ( descriptor_x_key ) = > {
let extended_path = descriptor_x_key . derivation_path . extend ( path ) ;
let extended_descriptor_public_key = BdkDescriptorPublicKey ::XPub ( DescriptorXKey {
origin : descriptor_x_key . origin . clone ( ) ,
xkey : descriptor_x_key . xkey ,
derivation_path : extended_path ,
wildcard : descriptor_x_key . wildcard ,
} ) ;
Arc ::new ( Self {
descriptor_public_key_mutex : Mutex ::new ( extended_descriptor_public_key ) ,
} )
}
2022-11-01 14:15:41 -04:00
BdkDescriptorPublicKey ::Single ( _ ) = > {
2022-08-09 14:43:06 +05:30
unreachable! ( )
}
2022-08-09 14:39:15 +05:30
}
}
fn as_string ( & self ) -> String {
self . descriptor_public_key_mutex . lock ( ) . unwrap ( ) . to_string ( )
}
}
2022-01-24 20:32:49 +00:00
uniffi ::deps ::static_assertions ::assert_impl_all! ( Wallet : Sync , Send ) ;
2022-04-20 15:52:40 -07:00
// The goal of these tests to to ensure `bdk-ffi` intermediate code correctly calls `bdk` APIs.
// These tests should not be used to verify `bdk` behavior that is already tested in the `bdk`
// crate.
#[ cfg(test) ]
mod test {
2022-08-09 14:43:06 +05:30
use crate ::* ;
2022-04-20 15:52:40 -07:00
use bdk ::bitcoin ::Address ;
use bdk ::bitcoin ::Network ::Testnet ;
use bdk ::wallet ::get_funded_wallet ;
use std ::str ::FromStr ;
use std ::sync ::Mutex ;
#[ test ]
fn test_drain_wallet ( ) {
let test_wpkh = " wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW) " ;
let ( funded_wallet , _ , _ ) = get_funded_wallet ( test_wpkh ) ;
let test_wallet = Wallet {
wallet_mutex : Mutex ::new ( funded_wallet ) ,
} ;
let drain_to_address = " tb1ql7w62elx9ucw4pj5lgw4l028hmuw80sndtntxt " . to_string ( ) ;
let tx_builder = TxBuilder ::new ( )
. drain_wallet ( )
. drain_to ( drain_to_address . clone ( ) ) ;
2022-07-25 13:02:41 -07:00
assert! ( tx_builder . drain_wallet ) ;
2022-04-20 15:52:40 -07:00
assert_eq! ( tx_builder . drain_to , Some ( drain_to_address ) ) ;
2022-10-18 17:13:15 -05:00
let tx_builder_result = tx_builder . finish ( & test_wallet ) . unwrap ( ) ;
let psbt = tx_builder_result . psbt . internal . lock ( ) . unwrap ( ) . clone ( ) ;
let tx_details = tx_builder_result . transaction_details ;
2022-04-20 15:52:40 -07:00
// confirm one input with 50,000 sats
assert_eq! ( psbt . inputs . len ( ) , 1 ) ;
let input_value = psbt
. inputs
. get ( 0 )
. cloned ( )
. unwrap ( )
. non_witness_utxo
. unwrap ( )
. output
. get ( 0 )
. unwrap ( )
. value ;
2022-07-25 13:02:41 -07:00
assert_eq! ( input_value , 50_000_ u64 ) ;
2022-04-20 15:52:40 -07:00
// confirm one output to correct address with all sats - fee
assert_eq! ( psbt . outputs . len ( ) , 1 ) ;
let output_address = Address ::from_script (
& psbt
. unsigned_tx
. output
. get ( 0 )
. cloned ( )
. unwrap ( )
. script_pubkey ,
Testnet ,
)
. unwrap ( ) ;
assert_eq! (
output_address ,
Address ::from_str ( " tb1ql7w62elx9ucw4pj5lgw4l028hmuw80sndtntxt " ) . unwrap ( )
) ;
let output_value = psbt . unsigned_tx . output . get ( 0 ) . cloned ( ) . unwrap ( ) . value ;
2022-07-25 13:02:41 -07:00
assert_eq! ( output_value , 49_890_ u64 ) ; // input - fee
2022-10-18 17:13:15 -05:00
assert_eq! (
tx_details . txid ,
" 312f1733badab22dc26b8dcbc83ba5629fb7b493af802e8abe07d865e49629c5 "
) ;
assert_eq! ( tx_details . received , 0 ) ;
assert_eq! ( tx_details . sent , 50000 ) ;
assert! ( tx_details . fee . is_some ( ) ) ;
assert_eq! ( tx_details . fee . unwrap ( ) , 110 ) ;
assert! ( tx_details . confirmation_time . is_none ( ) ) ;
2022-04-20 15:52:40 -07:00
}
2022-08-09 14:43:06 +05:30
fn get_descriptor_secret_key ( ) -> DescriptorSecretKey {
2022-10-28 10:19:57 +05:30
let mnemonic = Mnemonic ::from_str ( " chaos fabric time speed sponsor all flat solution wisdom trophy crack object robot pave observe combine where aware bench orient secret primary cable detect " . to_string ( ) ) . unwrap ( ) ;
DescriptorSecretKey ::new ( Testnet , Arc ::new ( mnemonic ) , None )
2022-08-09 14:43:06 +05:30
}
fn derive_dsk (
key : & DescriptorSecretKey ,
path : & str ,
2022-10-21 09:19:00 -04:00
) -> Result < Arc < DescriptorSecretKey > , BdkError > {
2022-08-09 14:43:06 +05:30
let path = Arc ::new ( DerivationPath ::new ( path . to_string ( ) ) . unwrap ( ) ) ;
key . derive ( path )
}
fn extend_dsk ( key : & DescriptorSecretKey , path : & str ) -> Arc < DescriptorSecretKey > {
let path = Arc ::new ( DerivationPath ::new ( path . to_string ( ) ) . unwrap ( ) ) ;
key . extend ( path )
}
fn derive_dpk (
key : & DescriptorPublicKey ,
path : & str ,
2022-10-21 09:19:00 -04:00
) -> Result < Arc < DescriptorPublicKey > , BdkError > {
2022-08-09 14:43:06 +05:30
let path = Arc ::new ( DerivationPath ::new ( path . to_string ( ) ) . unwrap ( ) ) ;
key . derive ( path )
}
fn extend_dpk ( key : & DescriptorPublicKey , path : & str ) -> Arc < DescriptorPublicKey > {
let path = Arc ::new ( DerivationPath ::new ( path . to_string ( ) ) . unwrap ( ) ) ;
key . extend ( path )
}
#[ test ]
fn test_generate_descriptor_secret_key ( ) {
let master_dsk = get_descriptor_secret_key ( ) ;
assert_eq! ( master_dsk . as_string ( ) , " tprv8ZgxMBicQKsPdWuqM1t1CDRvQtQuBPyfL6GbhQwtxDKgUAVPbxmj71pRA8raTqLrec5LyTs5TqCxdABcZr77bt2KyWA5bizJHnC4g4ysm4h/* " ) ;
assert_eq! ( master_dsk . as_public ( ) . as_string ( ) , " tpubD6NzVbkrYhZ4WywdEfYbbd62yuvqLjAZuPsNyvzCNV85JekAEMbKHWSHLF9h3j45SxewXDcLv328B1SEZrxg4iwGfmdt1pDFjZiTkGiFqGa/* " ) ;
}
#[ test ]
fn test_derive_self ( ) {
let master_dsk = get_descriptor_secret_key ( ) ;
let derived_dsk : & DescriptorSecretKey = & derive_dsk ( & master_dsk , " m " ) . unwrap ( ) ;
assert_eq! ( derived_dsk . as_string ( ) , " [d1d04177]tprv8ZgxMBicQKsPdWuqM1t1CDRvQtQuBPyfL6GbhQwtxDKgUAVPbxmj71pRA8raTqLrec5LyTs5TqCxdABcZr77bt2KyWA5bizJHnC4g4ysm4h/* " ) ;
let master_dpk : & DescriptorPublicKey = & master_dsk . as_public ( ) ;
let derived_dpk : & DescriptorPublicKey = & derive_dpk ( master_dpk , " m " ) . unwrap ( ) ;
assert_eq! ( derived_dpk . as_string ( ) , " [d1d04177]tpubD6NzVbkrYhZ4WywdEfYbbd62yuvqLjAZuPsNyvzCNV85JekAEMbKHWSHLF9h3j45SxewXDcLv328B1SEZrxg4iwGfmdt1pDFjZiTkGiFqGa/* " ) ;
}
#[ test ]
fn test_derive_descriptors_keys ( ) {
let master_dsk = get_descriptor_secret_key ( ) ;
let derived_dsk : & DescriptorSecretKey = & derive_dsk ( & master_dsk , " m/0 " ) . unwrap ( ) ;
assert_eq! ( derived_dsk . as_string ( ) , " [d1d04177/0]tprv8d7Y4JLmD25jkKbyDZXcdoPHu1YtMHuH21qeN7mFpjfumtSU7eZimFYUCSa3MYzkEYfSNRBV34GEr2QXwZCMYRZ7M1g6PUtiLhbJhBZEGYJ/* " ) ;
let master_dpk : & DescriptorPublicKey = & master_dsk . as_public ( ) ;
let derived_dpk : & DescriptorPublicKey = & derive_dpk ( master_dpk , " m/0 " ) . unwrap ( ) ;
assert_eq! ( derived_dpk . as_string ( ) , " [d1d04177/0]tpubD9oaCiP1MPmQdndm7DCD3D3QU34pWd6BbKSRedoZF1UJcNhEk3PJwkALNYkhxeTKL29oGNR7psqvT1KZydCGqUDEKXN6dVQJY2R8ooLPy8m/* " ) ;
}
#[ test ]
fn test_extend_descriptor_keys ( ) {
let master_dsk = get_descriptor_secret_key ( ) ;
let extended_dsk : & DescriptorSecretKey = & extend_dsk ( & master_dsk , " m/0 " ) ;
assert_eq! ( extended_dsk . as_string ( ) , " tprv8ZgxMBicQKsPdWuqM1t1CDRvQtQuBPyfL6GbhQwtxDKgUAVPbxmj71pRA8raTqLrec5LyTs5TqCxdABcZr77bt2KyWA5bizJHnC4g4ysm4h/0/* " ) ;
let master_dpk : & DescriptorPublicKey = & master_dsk . as_public ( ) ;
let extended_dpk : & DescriptorPublicKey = & extend_dpk ( master_dpk , " m/0 " ) ;
assert_eq! ( extended_dpk . as_string ( ) , " tpubD6NzVbkrYhZ4WywdEfYbbd62yuvqLjAZuPsNyvzCNV85JekAEMbKHWSHLF9h3j45SxewXDcLv328B1SEZrxg4iwGfmdt1pDFjZiTkGiFqGa/0/* " ) ;
}
#[ test ]
fn test_derive_and_extend_descriptor_secret_key ( ) {
let master_dsk = get_descriptor_secret_key ( ) ;
// derive DescriptorSecretKey with path "m/0" from master
let derived_dsk : & DescriptorSecretKey = & derive_dsk ( & master_dsk , " m/0 " ) . unwrap ( ) ;
assert_eq! ( derived_dsk . as_string ( ) , " [d1d04177/0]tprv8d7Y4JLmD25jkKbyDZXcdoPHu1YtMHuH21qeN7mFpjfumtSU7eZimFYUCSa3MYzkEYfSNRBV34GEr2QXwZCMYRZ7M1g6PUtiLhbJhBZEGYJ/* " ) ;
// extend derived_dsk with path "m/0"
let extended_dsk : & DescriptorSecretKey = & extend_dsk ( derived_dsk , " m/0 " ) ;
assert_eq! ( extended_dsk . as_string ( ) , " [d1d04177/0]tprv8d7Y4JLmD25jkKbyDZXcdoPHu1YtMHuH21qeN7mFpjfumtSU7eZimFYUCSa3MYzkEYfSNRBV34GEr2QXwZCMYRZ7M1g6PUtiLhbJhBZEGYJ/0/* " ) ;
}
#[ test ]
fn test_derive_hardened_path_using_public ( ) {
let master_dpk = get_descriptor_secret_key ( ) . as_public ( ) ;
let derived_dpk = & derive_dpk ( & master_dpk , " m/84h/1h/0h " ) ;
assert! ( derived_dpk . is_err ( ) ) ;
}
2022-09-26 11:01:46 -04:00
#[ test ]
fn test_retrieve_master_secret_key ( ) {
let master_dpk = get_descriptor_secret_key ( ) ;
2022-09-30 19:32:08 -04:00
let master_private_key = master_dpk . secret_bytes ( ) . to_hex ( ) ;
2022-09-26 11:01:46 -04:00
assert_eq! (
master_private_key ,
" e93315d6ce401eb4db803a56232f0ed3e69b053774e6047df54f1bd00e5ea936 "
)
}
2022-04-20 15:52:40 -07:00
}