@@ -98,7 +98,7 @@ use async_lock::RwLock;
9898use bdk_chain:: ConfirmationTime ;
9999use bip39:: Mnemonic ;
100100use bitcoin:: {
101- address:: NetworkUnchecked ,
101+ address:: { NetworkChecked , NetworkUnchecked } ,
102102 secp256k1:: { PublicKey , ThirtyTwoByteHash } ,
103103} ;
104104use bitcoin:: { bip32:: ExtendedPrivKey , Transaction } ;
@@ -1818,7 +1818,7 @@ impl<S: MutinyStorage> MutinyWallet<S> {
18181818
18191819 pub async fn send_to_address (
18201820 & self ,
1821- send_to : Address < NetworkUnchecked > ,
1821+ send_to : Address ,
18221822 amount : u64 ,
18231823 labels : Vec < String > ,
18241824 fee_rate : Option < f32 > ,
@@ -1866,6 +1866,150 @@ impl<S: MutinyStorage> MutinyWallet<S> {
18661866 }
18671867 }
18681868
1869+ /// Estimates the onchain fee for a transaction sending to the given address.
1870+ /// The amount is in satoshis and the fee rate is in sat/vbyte.
1871+ pub async fn estimate_tx_fee (
1872+ & self ,
1873+ destination_address : Address ,
1874+ amount : u64 ,
1875+ fee_rate : Option < f32 > ,
1876+ ) -> Result < u64 , MutinyError > {
1877+ log_warn ! ( self . logger, "estimate_tx_fee" ) ;
1878+
1879+ // Try each federation first
1880+ let federation_ids = self . list_federation_ids ( ) . await ?;
1881+ let mut last_federation_error = None ;
1882+ for federation_id in federation_ids {
1883+ if let Some ( fedimint_client) = self . federations . read ( ) . await . get ( & federation_id) {
1884+ // Check if the federation has enough balance
1885+ let balance = fedimint_client. get_balance ( ) . await ?;
1886+ if balance >= amount / 1_000 {
1887+ match fedimint_client
1888+ . estimate_tx_fee ( destination_address. clone ( ) , amount. clone ( ) )
1889+ . await
1890+ {
1891+ Ok ( t) => {
1892+ return Ok ( t) ;
1893+ }
1894+ Err ( e) => {
1895+ log_warn ! ( self . logger, "error estimating fedimint fee: {e}" ) ;
1896+ last_federation_error = Some ( e) ;
1897+ }
1898+ }
1899+ }
1900+ // If payment fails or invoice amount is None or balance is not sufficient, continue to next federation
1901+ }
1902+ // If federation client is not found, continue to next federation
1903+ }
1904+
1905+ let b = self . node_manager . get_balance ( ) . await ?;
1906+ if b. confirmed + b. unconfirmed > 0 {
1907+ let res = self
1908+ . node_manager
1909+ . estimate_tx_fee ( destination_address, amount, fee_rate) ?;
1910+
1911+ Ok ( res)
1912+ } else {
1913+ Err ( last_federation_error. unwrap_or ( MutinyError :: InsufficientBalance ) )
1914+ }
1915+ }
1916+
1917+ /// Estimates the onchain fee for a transaction sweep our on-chain balance
1918+ /// to the given address. If the fedimint has a balance, sweep that first.
1919+ /// Do not sweep the on chain wallet unless that is empty.
1920+ ///
1921+ /// The fee rate is in sat/vbyte.
1922+ pub async fn estimate_sweep_tx_fee (
1923+ & self ,
1924+ destination_address : Address ,
1925+ fee_rate : Option < f32 > ,
1926+ ) -> Result < u64 , MutinyError > {
1927+ // Try each federation first
1928+ let federation_ids = self . list_federation_ids ( ) . await ?;
1929+ for federation_id in federation_ids {
1930+ if let Some ( fedimint_client) = self . federations . read ( ) . await . get ( & federation_id) {
1931+ // Check if the federation has enough balance
1932+ let balance = fedimint_client. get_balance ( ) . await ?;
1933+ match fedimint_client
1934+ . estimate_tx_fee ( destination_address. clone ( ) , balance. clone ( ) )
1935+ . await
1936+ {
1937+ Ok ( t) => {
1938+ return Ok ( t) ;
1939+ }
1940+ Err ( e) => return Err ( e) ,
1941+ }
1942+ // If payment fails or invoice amount is None or balance is not sufficient, continue to next federation
1943+ }
1944+ // If federation client is not found, continue to next federation
1945+ }
1946+
1947+ let b = self . node_manager . get_balance ( ) . await ?;
1948+ if b. confirmed + b. unconfirmed > 0 {
1949+ let res = self
1950+ . node_manager
1951+ . estimate_sweep_tx_fee ( destination_address, fee_rate) ?;
1952+
1953+ Ok ( res)
1954+ } else {
1955+ log_error ! ( self . logger, "node manager doesn't have a a balance" ) ;
1956+ Err ( MutinyError :: InsufficientBalance )
1957+ }
1958+ }
1959+
1960+ /// Sweeps all the funds from the wallet to the given address.
1961+ /// The fee rate is in sat/vbyte.
1962+ ///
1963+ /// If a fee rate is not provided, one will be used from the fee estimator.
1964+ pub async fn sweep_wallet (
1965+ & self ,
1966+ send_to : Address ,
1967+ labels : Vec < String > ,
1968+ fee_rate : Option < f32 > ,
1969+ ) -> Result < Txid , MutinyError > {
1970+ // Try each federation first
1971+ let federation_ids = self . list_federation_ids ( ) . await ?;
1972+ for federation_id in federation_ids {
1973+ if let Some ( fedimint_client) = self . federations . read ( ) . await . get ( & federation_id) {
1974+ // Check if the federation has enough balance
1975+ let balance = fedimint_client. get_balance ( ) . await ?;
1976+ match fedimint_client
1977+ . estimate_tx_fee ( send_to. clone ( ) , balance. clone ( ) )
1978+ . await
1979+ {
1980+ Ok ( f) => {
1981+ match fedimint_client
1982+ . send_onchain ( send_to. clone ( ) , balance - f, labels)
1983+ . await
1984+ {
1985+ Ok ( t) => return Ok ( t) ,
1986+ Err ( e) => {
1987+ log_error ! ( self . logger, "error sending the fedimint balance" ) ;
1988+ return Err ( e) ;
1989+ }
1990+ }
1991+ }
1992+ Err ( e) => return Err ( e) ,
1993+ }
1994+ // If payment fails or invoice amount is None or balance is not sufficient, continue to next federation
1995+ }
1996+ // If federation client is not found, continue to next federation
1997+ }
1998+
1999+ let b = self . node_manager . get_balance ( ) . await ?;
2000+ if b. confirmed + b. unconfirmed > 0 {
2001+ let res = self
2002+ . node_manager
2003+ . sweep_wallet ( send_to. clone ( ) , labels, fee_rate)
2004+ . await ?;
2005+
2006+ Ok ( res)
2007+ } else {
2008+ log_error ! ( self . logger, "node manager doesn't have a a balance" ) ;
2009+ Err ( MutinyError :: InsufficientBalance )
2010+ }
2011+ }
2012+
18692013 async fn create_address ( & self , labels : Vec < String > ) -> Result < bitcoin:: Address , MutinyError > {
18702014 // Attempt to create federation invoice if available
18712015 let federation_ids = self . list_federation_ids ( ) . await ?;
@@ -3245,6 +3389,11 @@ impl<S: MutinyStorage> MutinyWallet<S> {
32453389
32463390 Ok ( response. price )
32473391 }
3392+
3393+ /// Returns the network of the wallet.
3394+ pub fn get_network ( & self ) -> Network {
3395+ self . network
3396+ }
32483397}
32493398
32503399impl < S : MutinyStorage > InvoiceHandler for MutinyWallet < S > {
0 commit comments