]> Untitled Git - bdk/commitdiff
[wallet] Add "needed" and "available" metadata to Error::InsufficientFunds
authorJustin Moon <mail@justinmoon.com>
Wed, 18 Nov 2020 00:05:33 +0000 (18:05 -0600)
committerAlekos Filini <alekos.filini@gmail.com>
Mon, 18 Jan 2021 10:15:10 +0000 (11:15 +0100)
src/error.rs
src/wallet/coin_selection.rs
src/wallet/mod.rs
src/wallet/utils.rs

index 40e2953323db595c824ece303f03cb5c2fbf79e6..226ee43b0ccdc11a57529ca719c6e860f4a1ef43 100644 (file)
@@ -47,7 +47,12 @@ pub enum Error {
     /// Output created is under the dust limit, 546 satoshis
     OutputBelowDustLimit(usize),
     /// Wallet's UTXO set is not enough to cover recipient's requested plus fee
-    InsufficientFunds,
+    InsufficientFunds {
+        /// Sats needed for some transaction
+        needed: u64,
+        /// Sats available for spending
+        available: u64,
+    },
     /// Branch and bound coin selection possible attempts with sufficiently big UTXO set could grow
     /// exponentially, thus a limit is set, and when hit, this error is thrown
     BnBTotalTriesExceeded,
index 87808db137d125661fece09ba707f77e99d66426..d4fcd02af6cb0ac0fd254de4cb226ed7825ac3ea 100644 (file)
@@ -71,9 +71,9 @@
 //!             })
 //!             .collect::<Vec<_>>();
 //!         let additional_fees = additional_weight as f32 * fee_rate.as_sat_vb() / 4.0;
-//!
-//!         if (fee_amount + additional_fees).ceil() as u64 + amount_needed > selected_amount {
-//!             return Err(bdk::Error::InsufficientFunds);
+//!         let amount_needed_with_fees = (fee_amount + additional_fees).ceil() as u64 + amount_needed;
+//!         if  amount_needed_with_fees > selected_amount {
+//!             return Err(bdk::Error::InsufficientFunds{ needed: amount_needed_with_fees, available: selected_amount });
 //!         }
 //!
 //!         Ok(CoinSelectionResult {
@@ -221,8 +221,12 @@ impl<D: Database> CoinSelectionAlgorithm<D> for LargestFirstCoinSelection {
             )
             .collect::<Vec<_>>();
 
-        if selected_amount < amount_needed + (fee_amount.ceil() as u64) {
-            return Err(Error::InsufficientFunds);
+        let amount_needed_with_fees = amount_needed + (fee_amount.ceil() as u64);
+        if selected_amount < amount_needed_with_fees {
+            return Err(Error::InsufficientFunds {
+                needed: amount_needed_with_fees,
+                available: selected_amount,
+            });
         }
 
         Ok(CoinSelectionResult {
@@ -321,7 +325,10 @@ impl<D: Database> CoinSelectionAlgorithm<D> for BranchAndBoundCoinSelection {
         let cost_of_change = self.size_of_change as f32 * fee_rate.as_sat_vb();
 
         if curr_available_value + curr_value < actual_target {
-            return Err(Error::InsufficientFunds);
+            return Err(Error::InsufficientFunds {
+                needed: actual_target,
+                available: curr_available_value + curr_value,
+            });
         }
 
         Ok(self
index c9b4a5beed7c4c429c1d84c43ddb2918db77b441..1a82f16f18393d57665c7bb8bf684ed1c2d1caf4 100644 (file)
@@ -59,7 +59,10 @@ pub use utils::IsDust;
 use address_validator::AddressValidator;
 use signer::{Signer, SignerId, SignerOrdering, SignersContainer};
 use tx_builder::{BumpFee, CreateTx, FeePolicy, TxBuilder, TxBuilderContext};
-use utils::{check_nlocktime, check_nsequence_rbf, descriptor_to_pk_ctx, After, Older, SecpCtx};
+use utils::{
+    check_nlocktime, check_nsequence_rbf, descriptor_to_pk_ctx, After, Older, SecpCtx,
+    DUST_LIMIT_SATOSHI,
+};
 
 use crate::blockchain::{Blockchain, Progress};
 use crate::database::{BatchDatabase, BatchOperations, DatabaseUtils};
@@ -508,7 +511,11 @@ where
         match change_output {
             None if change_val.is_dust() => {
                 // single recipient, but the only output would be below dust limit
-                return Err(Error::InsufficientFunds); // TODO: or OutputBelowDustLimit?
+                // TODO: or OutputBelowDustLimit?
+                return Err(Error::InsufficientFunds {
+                    needed: DUST_LIMIT_SATOSHI,
+                    available: change_val,
+                });
             }
             Some(_) if change_val.is_dust() => {
                 // skip the change output because it's dust -- just include it in the fee.
@@ -786,7 +793,11 @@ where
             }
             Some(_) if change_val_after_add.is_dust() => {
                 // single_recipient but the only output would be below dust limit
-                return Err(Error::InsufficientFunds); // TODO: or OutputBelowDustLimit?
+                // TODO: or OutputBelowDustLimit?
+                return Err(Error::InsufficientFunds {
+                    needed: DUST_LIMIT_SATOSHI,
+                    available: change_val_after_add,
+                });
             }
             None => {
                 removed_updatable_output.value = change_val_after_add;
index 108a21a76c3cb8736ae9b6ce15a4cab1d73b9f6e..5f2b8004649be5f00a81b1a8417d6ffa135698c6 100644 (file)
@@ -29,7 +29,7 @@ use miniscript::descriptor::DescriptorPublicKeyCtx;
 use miniscript::{MiniscriptKey, Satisfier, ToPublicKey};
 
 // De-facto standard "dust limit" (even though it should change based on the output type)
-const DUST_LIMIT_SATOSHI: u64 = 546;
+pub const DUST_LIMIT_SATOSHI: u64 = 546;
 
 // MSB of the nSequence. If set there's no consensus-constraint, so it must be disabled when
 // spending using CSV in order to enforce CSV rules