diff --git a/src/wallet/direct_send.rs b/src/wallet/direct_send.rs index be383760..cd2fd6d7 100644 --- a/src/wallet/direct_send.rs +++ b/src/wallet/direct_send.rs @@ -72,8 +72,18 @@ impl Wallet { coins_to_spend: &[(ListUnspentResultEntry, UTXOSpendInfo)], ) -> Result { log::info!("Creating Direct-Spend from Wallet."); - let mut tx_inputs = Vec::::new(); - let mut spend_infos = Vec::new(); + + // Set the Anti-Fee-Snipping locktime + let current_height = self.rpc.get_block_count()?; + let lock_time = LockTime::from_height(current_height as u32)?; + + let mut tx = Transaction { + version: Version::TWO, + lock_time, + input: vec![], + output: vec![], + }; + let mut total_input_value = Amount::ZERO; for (utxo_data, spend_info) in coins_to_spend { @@ -93,24 +103,16 @@ impl Wallet { _ => 0, }; - tx_inputs.push(TxIn { + tx.input.push(TxIn { previous_output: OutPoint::new(utxo_data.txid, utxo_data.vout), sequence: Sequence(sequence), witness: Witness::new(), script_sig: ScriptBuf::new(), }); - spend_infos.push(spend_info); - total_input_value += utxo_data.amount; } - if tx_inputs.len() != coins_to_spend.len() { - return Err(WalletError::Protocol( - "Could not fetch all inputs.".to_string(), - )); - } - log::info!("Total Input Amount: {} | Fees: {}", total_input_value, fee); let dest_addr = match destination { @@ -133,12 +135,19 @@ impl Wallet { } }; - let mut output = Vec::::new(); - let txout = { let value = match send_amount { SendAmount::Max => (total_input_value - fee).to_sat(), - SendAmount::Amount(a) => a.to_sat(), + SendAmount::Amount(a) => { + if a + fee <= total_input_value { + a.to_sat() + } else { + return Err(WalletError::Protocol( + "Insufficient funds: Amount plus fees exceeds available UTXOs." + .to_string(), + )); + } + } }; log::info!("Sending {} to {}.", value, dest_addr); TxOut { @@ -147,7 +156,7 @@ impl Wallet { } }; - output.push(txout); + tx.output.push(txout); // Only include change if remaining > dust if let SendAmount::Amount(amount) = send_amount { @@ -155,23 +164,13 @@ impl Wallet { let remaining = total_input_value - amount - fee; if remaining > internal_spk.minimal_non_dust() { log::info!("Adding Change {}:{}", internal_spk, remaining); - output.push(TxOut { + tx.output.push(TxOut { script_pubkey: internal_spk, value: remaining, }); } } - // Set the Anti-Fee-Snipping locktime - let current_height = self.rpc.get_block_count()?; - let lock_time = LockTime::from_height(current_height as u32)?; - - let mut tx = Transaction { - input: tx_inputs, - output, - lock_time, - version: Version::TWO, - }; self.sign_transaction( &mut tx, &mut coins_to_spend.iter().map(|(_, usi)| usi.clone()),