diff --git a/state-chain/pallets/cf-environment/src/lib.rs b/state-chain/pallets/cf-environment/src/lib.rs index 17fb26a09a..e84c483d2b 100644 --- a/state-chain/pallets/cf-environment/src/lib.rs +++ b/state-chain/pallets/cf-environment/src/lib.rs @@ -424,20 +424,24 @@ impl Pallet { T::BitcoinFeeInfo::bitcoin_fee_info(); match utxo_selection_type { UtxoSelectionType::SelectAllForRotation => { - let available_utxos = BitcoinAvailableUtxos::::take(); - (!available_utxos.is_empty()).then_some(available_utxos).and_then( - |available_utxos| { - available_utxos - .iter() - .map(|Utxo { amount, .. }| *amount) - .sum::() - .checked_sub( - ((available_utxos.len() as u64) * fee_per_input_utxo) + - fee_per_output_utxo + min_fee_required_per_tx, - ) - .map(|change_amount| (available_utxos, change_amount)) - }, - ) + let spendable_utxos: Vec<_> = BitcoinAvailableUtxos::::take() + .into_iter() + .filter(|utxo| utxo.amount > fee_per_input_utxo) + .collect(); + + if spendable_utxos.is_empty() { + return None + } + + let total_fee = spendable_utxos.len() as u64 * fee_per_input_utxo + + fee_per_output_utxo + min_fee_required_per_tx; + + spendable_utxos + .iter() + .map(|utxo| utxo.amount) + .sum::() + .checked_sub(total_fee) + .map(|change_amount| (spendable_utxos, change_amount)) }, UtxoSelectionType::Some { output_amount, number_of_outputs } => BitcoinAvailableUtxos::::try_mutate(|available_utxos| { diff --git a/state-chain/pallets/cf-environment/src/tests.rs b/state-chain/pallets/cf-environment/src/tests.rs index e3aa2754b5..058343229d 100644 --- a/state-chain/pallets/cf-environment/src/tests.rs +++ b/state-chain/pallets/cf-environment/src/tests.rs @@ -46,6 +46,12 @@ fn test_btc_utxo_selection() { add_utxo_amount(100000); add_utxo_amount(5000000); add_utxo_amount(25000); + // dust amount should be ignored in all cases + let dust_amount = { + use cf_traits::GetBitcoinFeeInfo; + ::BitcoinFeeInfo::bitcoin_fee_info().fee_per_input_utxo + }; + add_utxo_amount(dust_amount); // select some utxos for a tx assert_eq!(