@@ -66,7 +66,7 @@ use crate::descriptor::{
6666 calc_checksum, into_wallet_descriptor_checked, DerivedDescriptor , DescriptorMeta ,
6767 ExtendedDescriptor , ExtractPolicy , IntoWalletDescriptor , Policy , XKeyUtils ,
6868} ;
69- use crate :: error:: { Error , MiniscriptPsbtError } ;
69+ use crate :: error:: { CalculateFeeError , Error , MiniscriptPsbtError } ;
7070use crate :: psbt:: PsbtUtils ;
7171use crate :: signer:: SignerError ;
7272use crate :: types:: * ;
@@ -430,27 +430,52 @@ impl<D> Wallet<D> {
430430 . next ( )
431431 }
432432
433- /// Return a single transactions made and received by the wallet
433+ /// Calculates the fee of a given transaction. Returns 0 if `tx` is a coinbase transaction.
434434 ///
435- /// Optionally fill the [`TransactionDetails::transaction`] field with the raw transaction if
436- /// `include_raw` is `true`.
437- pub fn get_tx ( & self , txid : Txid , include_raw : bool ) -> Option < TransactionDetails > {
435+ /// Note `tx` does not have to be in the graph for this to work.
436+ pub fn calculate_fee ( & self , tx : & Transaction ) -> Result < u64 , CalculateFeeError > {
437+ match self . indexed_graph . graph ( ) . calculate_fee ( tx) {
438+ None => Err ( CalculateFeeError :: MissingTxOut ) ,
439+ Some ( fee) if fee < 0 => Err ( CalculateFeeError :: NegativeFee ( fee) ) ,
440+ Some ( fee) => Ok ( u64:: try_from ( fee) . unwrap ( ) ) ,
441+ }
442+ }
443+
444+ /// Calculate the `FeeRate` for a given transaction.
445+ ///
446+ /// Note `tx` does not have to be in the graph for this to work.
447+ pub fn calculate_fee_rate ( & self , tx : & Transaction ) -> Result < FeeRate , CalculateFeeError > {
448+ self . calculate_fee ( tx) . map ( |fee| {
449+ let weight = tx. weight ( ) ;
450+ FeeRate :: from_wu ( fee, weight)
451+ } )
452+ }
453+
454+ /// Computes total input value going from script pubkeys in the index (sent) and the total output
455+ /// value going to script pubkeys in the index (received) in `tx`. For the `sent` to be computed
456+ /// correctly, the output being spent must have already been scanned by the index. Calculating
457+ /// received just uses the transaction outputs directly, so it will be correct even if it has not
458+ /// been scanned.
459+ pub fn sent_and_received ( & self , tx : & Transaction ) -> ( u64 , u64 ) {
460+ self . indexed_graph . index . sent_and_received ( tx)
461+ }
462+
463+ /// Return a single `CanonicalTx` made and received by the wallet or `None` if it doesn't
464+ /// exist in the wallet
465+ pub fn get_tx (
466+ & self ,
467+ txid : Txid ,
468+ ) -> Option < CanonicalTx < ' _ , Transaction , ConfirmationTimeAnchor > > {
438469 let graph = self . indexed_graph . graph ( ) ;
439470
440- let canonical_tx = CanonicalTx {
471+ Some ( CanonicalTx {
441472 chain_position : graph. get_chain_position (
442473 & self . chain ,
443474 self . chain . tip ( ) . map ( |cp| cp. block_id ( ) ) . unwrap_or_default ( ) ,
444475 txid,
445476 ) ?,
446477 tx_node : graph. get_tx_node ( txid) ?,
447- } ;
448-
449- Some ( new_tx_details (
450- & self . indexed_graph ,
451- canonical_tx,
452- include_raw,
453- ) )
478+ } )
454479 }
455480
456481 /// Add a new checkpoint to the wallet's internal view of the chain.
@@ -603,7 +628,7 @@ impl<D> Wallet<D> {
603628 /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
604629 /// # let mut wallet = doctest_wallet!();
605630 /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
606- /// let ( psbt, details) = {
631+ /// let psbt = {
607632 /// let mut builder = wallet.build_tx();
608633 /// builder
609634 /// .add_recipient(to_address.script_pubkey(), 50_000);
@@ -628,7 +653,7 @@ impl<D> Wallet<D> {
628653 & mut self ,
629654 coin_selection : Cs ,
630655 params : TxParams ,
631- ) -> Result < ( psbt:: PartiallySignedTransaction , TransactionDetails ) , Error >
656+ ) -> Result < psbt:: PartiallySignedTransaction , Error >
632657 where
633658 D : PersistBackend < ChangeSet > ,
634659 {
@@ -976,20 +1001,8 @@ impl<D> Wallet<D> {
9761001 // sort input/outputs according to the chosen algorithm
9771002 params. ordering . sort_tx ( & mut tx) ;
9781003
979- let txid = tx. txid ( ) ;
980- let sent = coin_selection. local_selected_amount ( ) ;
9811004 let psbt = self . complete_transaction ( tx, coin_selection. selected , params) ?;
982-
983- let transaction_details = TransactionDetails {
984- transaction : None ,
985- txid,
986- confirmation_time : ConfirmationTime :: Unconfirmed { last_seen : 0 } ,
987- received,
988- sent,
989- fee : Some ( fee_amount) ,
990- } ;
991-
992- Ok ( ( psbt, transaction_details) )
1005+ Ok ( psbt)
9931006 }
9941007
9951008 /// Bump the fee of a transaction previously created with this wallet.
@@ -1008,7 +1021,7 @@ impl<D> Wallet<D> {
10081021 /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
10091022 /// # let mut wallet = doctest_wallet!();
10101023 /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
1011- /// let ( mut psbt, _) = {
1024+ /// let mut psbt = {
10121025 /// let mut builder = wallet.build_tx();
10131026 /// builder
10141027 /// .add_recipient(to_address.script_pubkey(), 50_000)
@@ -1018,7 +1031,7 @@ impl<D> Wallet<D> {
10181031 /// let _ = wallet.sign(&mut psbt, SignOptions::default())?;
10191032 /// let tx = psbt.extract_tx();
10201033 /// // broadcast tx but it's taking too long to confirm so we want to bump the fee
1021- /// let ( mut psbt, _) = {
1034+ /// let mut psbt = {
10221035 /// let mut builder = wallet.build_fee_bump(tx.txid())?;
10231036 /// builder
10241037 /// .fee_rate(bdk::FeeRate::from_sat_per_vb(5.0));
@@ -1179,7 +1192,7 @@ impl<D> Wallet<D> {
11791192 /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
11801193 /// # let mut wallet = doctest_wallet!();
11811194 /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
1182- /// let ( mut psbt, _) = {
1195+ /// let mut psbt = {
11831196 /// let mut builder = wallet.build_tx();
11841197 /// builder.add_recipient(to_address.script_pubkey(), 50_000);
11851198 /// builder.finish()?
@@ -1735,7 +1748,7 @@ impl<D> Wallet<D> {
17351748 Ok ( ( ) )
17361749 }
17371750
1738- /// Commits all curently [`staged`] changed to the persistence backend returning and error when
1751+ /// Commits all currently [`staged`] changed to the persistence backend returning and error when
17391752 /// this fails.
17401753 ///
17411754 /// This returns whether the `update` resulted in any changes.
@@ -1826,61 +1839,6 @@ fn new_local_utxo(
18261839 }
18271840}
18281841
1829- fn new_tx_details (
1830- indexed_graph : & IndexedTxGraph < ConfirmationTimeAnchor , KeychainTxOutIndex < KeychainKind > > ,
1831- canonical_tx : CanonicalTx < ' _ , Transaction , ConfirmationTimeAnchor > ,
1832- include_raw : bool ,
1833- ) -> TransactionDetails {
1834- let graph = indexed_graph. graph ( ) ;
1835- let index = & indexed_graph. index ;
1836- let tx = canonical_tx. tx_node . tx ;
1837-
1838- let received = tx
1839- . output
1840- . iter ( )
1841- . map ( |txout| {
1842- if index. index_of_spk ( & txout. script_pubkey ) . is_some ( ) {
1843- txout. value
1844- } else {
1845- 0
1846- }
1847- } )
1848- . sum ( ) ;
1849-
1850- let sent = tx
1851- . input
1852- . iter ( )
1853- . map ( |txin| {
1854- if let Some ( ( _, txout) ) = index. txout ( txin. previous_output ) {
1855- txout. value
1856- } else {
1857- 0
1858- }
1859- } )
1860- . sum ( ) ;
1861-
1862- let inputs = tx
1863- . input
1864- . iter ( )
1865- . map ( |txin| {
1866- graph
1867- . get_txout ( txin. previous_output )
1868- . map ( |txout| txout. value )
1869- } )
1870- . sum :: < Option < u64 > > ( ) ;
1871- let outputs = tx. output . iter ( ) . map ( |txout| txout. value ) . sum ( ) ;
1872- let fee = inputs. map ( |inputs| inputs. saturating_sub ( outputs) ) ;
1873-
1874- TransactionDetails {
1875- transaction : if include_raw { Some ( tx. clone ( ) ) } else { None } ,
1876- txid : canonical_tx. tx_node . txid ,
1877- received,
1878- sent,
1879- fee,
1880- confirmation_time : canonical_tx. chain_position . cloned ( ) . into ( ) ,
1881- }
1882- }
1883-
18841842#[ macro_export]
18851843#[ doc( hidden) ]
18861844/// Macro for getting a wallet for use in a doctest
0 commit comments