@@ -446,15 +446,51 @@ where
446446 self . database . borrow ( ) . iter_txs ( include_raw)
447447 }
448448
449- /// Return the balance, meaning the sum of this wallet's unspent outputs' values
449+ /// Return the balance, separated into available, trusted-pending, untrusted-pending and immature
450+ /// values.
450451 ///
451452 /// Note that this methods only operate on the internal database, which first needs to be
452453 /// [`Wallet::sync`] manually.
453- pub fn get_balance ( & self ) -> Result < u64 , Error > {
454- Ok ( self
455- . list_unspent ( ) ?
456- . iter ( )
457- . fold ( 0 , |sum, i| sum + i. txout . value ) )
454+ pub fn get_balance ( & self ) -> Result < Balance , Error > {
455+ let mut immature = 0 ;
456+ let mut trusted_pending = 0 ;
457+ let mut untrusted_pending = 0 ;
458+ let mut available = 0 ;
459+ let utxos = self . list_unspent ( ) ?;
460+ let database = self . database . borrow ( ) ;
461+ for u in utxos {
462+ // Unwrap used since utxo set is created from database
463+ let tx = database. get_tx ( & u. outpoint . txid , true ) ?. unwrap ( ) ;
464+ if let Some ( tx_conf_time) = & tx. confirmation_time {
465+ if tx. transaction . expect ( "No transaction" ) . is_coin_base ( ) {
466+ let last_sync_height = self
467+ . database ( )
468+ . get_sync_time ( ) ?
469+ . map ( |sync_time| sync_time. block_time . height ) ;
470+
471+ if let Some ( last_sync_height) = last_sync_height {
472+ if ( last_sync_height - tx_conf_time. height ) >= COINBASE_MATURITY {
473+ available += u. txout . value ;
474+ } else {
475+ immature += u. txout . value ;
476+ }
477+ }
478+ } else {
479+ available += u. txout . value ;
480+ }
481+ } else if u. keychain == KeychainKind :: Internal {
482+ trusted_pending += u. txout . value ;
483+ } else {
484+ untrusted_pending += u. txout . value ;
485+ }
486+ }
487+
488+ Ok ( Balance {
489+ immature,
490+ trusted_pending,
491+ untrusted_pending,
492+ available,
493+ } )
458494 }
459495
460496 /// Add an external signer
@@ -4686,23 +4722,30 @@ pub(crate) mod test {
46864722 Some ( confirmation_time) ,
46874723 ( @coinbase true )
46884724 ) ;
4725+ let sync_time = SyncTime {
4726+ block_time : BlockTime {
4727+ height : confirmation_time,
4728+ timestamp : 0 ,
4729+ } ,
4730+ } ;
4731+ wallet
4732+ . database
4733+ . borrow_mut ( )
4734+ . set_sync_time ( sync_time. clone ( ) )
4735+ . unwrap ( ) ;
46894736
46904737 let not_yet_mature_time = confirmation_time + COINBASE_MATURITY - 1 ;
46914738 let maturity_time = confirmation_time + COINBASE_MATURITY ;
46924739
4693- // The balance is nonzero, even if we can't spend anything
4694- // FIXME: we should differentiate the balance between immature,
4695- // trusted, untrusted_pending
4696- // See https://github.com/bitcoindevkit/bdk/issues/238
46974740 let balance = wallet. get_balance ( ) . unwrap ( ) ;
4698- assert ! ( balance != 0 ) ;
4741+ assert ! ( balance. immature != 0 ) ;
46994742
47004743 // We try to create a transaction, only to notice that all
47014744 // our funds are unspendable
47024745 let addr = Address :: from_str ( "2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX" ) . unwrap ( ) ;
47034746 let mut builder = wallet. build_tx ( ) ;
47044747 builder
4705- . add_recipient ( addr. script_pubkey ( ) , balance / 2 )
4748+ . add_recipient ( addr. script_pubkey ( ) , balance. immature / 2 )
47064749 . set_current_height ( confirmation_time) ;
47074750 assert ! ( matches!(
47084751 builder. finish( ) . unwrap_err( ) ,
@@ -4715,7 +4758,7 @@ pub(crate) mod test {
47154758 // Still unspendable...
47164759 let mut builder = wallet. build_tx ( ) ;
47174760 builder
4718- . add_recipient ( addr. script_pubkey ( ) , balance / 2 )
4761+ . add_recipient ( addr. script_pubkey ( ) , balance. immature / 2 )
47194762 . set_current_height ( not_yet_mature_time) ;
47204763 assert ! ( matches!(
47214764 builder. finish( ) . unwrap_err( ) ,
@@ -4728,7 +4771,7 @@ pub(crate) mod test {
47284771 // ...Now the coinbase is mature :)
47294772 let mut builder = wallet. build_tx ( ) ;
47304773 builder
4731- . add_recipient ( addr. script_pubkey ( ) , balance / 2 )
4774+ . add_recipient ( addr. script_pubkey ( ) , balance. immature / 2 )
47324775 . set_current_height ( maturity_time) ;
47334776 builder. finish ( ) . unwrap ( ) ;
47344777 }
0 commit comments