diff --git a/gui/src/app/state/spend/step.rs b/gui/src/app/state/spend/step.rs
index 38b621bdf..f26dab0f9 100644
--- a/gui/src/app/state/spend/step.rs
+++ b/gui/src/app/state/spend/step.rs
@@ -6,12 +6,9 @@ use iced::{Command, Subscription};
use liana::{
descriptors::LianaDescriptor,
miniscript::bitcoin::{
- self, address, psbt::Psbt, secp256k1, Address, Amount, Denomination, Network, OutPoint,
- },
- spend::{
- create_spend, CandidateCoin, SpendCreationError, SpendOutputAddress, SpendTxFees, TxGetter,
- MAX_FEERATE,
+ address, psbt::Psbt, secp256k1, Address, Amount, Denomination, Network, OutPoint,
},
+ spend::{SpendCreationError, MAX_FEERATE},
};
use liana_ui::{component::form, widget::Element};
@@ -192,86 +189,50 @@ impl DefineSpend {
return;
}
- let destinations: Vec<(SpendOutputAddress, Amount)> = self
+ let destinations: HashMap
, u64> = self
.recipients
.iter()
.map(|recipient| {
(
- SpendOutputAddress {
- addr: Address::from_str(&recipient.address.value)
- .expect("Checked before")
- .assume_checked(),
- info: None,
- },
- Amount::from_sat(recipient.amount().expect("Checked before")),
+ Address::from_str(&recipient.address.value).expect("Checked before"),
+ recipient.amount().expect("Checked before"),
)
})
.collect();
- let coins: Vec = if self.is_user_coin_selection {
+ let outpoints = if self.is_user_coin_selection {
self.coins
.iter()
- .filter_map(|(c, selected)| {
- if *selected {
- Some(CandidateCoin {
- amount: c.amount,
- outpoint: c.outpoint,
- deriv_index: c.derivation_index,
- is_change: c.is_change,
- sequence: None,
- must_select: *selected,
- })
- } else {
- None
- }
- })
+ .filter_map(
+ |(c, selected)| {
+ if *selected {
+ Some(c.outpoint)
+ } else {
+ None
+ }
+ },
+ )
.collect()
} else {
- // For automated coin selection, only confirmed coins are considered
- self.coins
- .iter()
- .filter_map(|(c, _)| {
- if c.block_height.is_some() {
- Some(CandidateCoin {
- amount: c.amount,
- outpoint: c.outpoint,
- deriv_index: c.derivation_index,
- is_change: c.is_change,
- sequence: None,
- must_select: false,
- })
- } else {
- None
- }
- })
- .collect()
+ Vec::new() // pass empty list for auto-selection
};
+ // Use a fixed change address so that we don't increment the change index.
let dummy_address = self
.descriptor
.change_descriptor()
.derive(0.into(), &self.curve)
- .address(self.network);
+ .address(self.network)
+ .as_unchecked()
+ .clone();
let feerate_vb = self.feerate.value.parse::().expect("Checked before");
- // Create a spend with empty inputs in order to use auto-selection.
- match create_spend(
- &self.descriptor,
- &self.curve,
- &mut DaemonTxGetter(&daemon),
- &destinations,
- &coins,
- SpendTxFees::Regular(feerate_vb),
- SpendOutputAddress {
- addr: dummy_address,
- info: None,
- },
- ) {
- Ok(spend) => {
+
+ match daemon.create_spend_tx(&outpoints, &destinations, feerate_vb, Some(dummy_address)) {
+ Ok(CreateSpendResult::Success { psbt, .. }) => {
self.warning = None;
if !self.is_user_coin_selection {
- let selected_coins: Vec = spend
- .psbt
+ let selected_coins: Vec = psbt
.unsigned_tx
.input
.iter()
@@ -290,8 +251,8 @@ impl DefineSpend {
// User can then either:
// - modify recipient amounts and/or feerate and let coin selection run again, or
// - select coins manually.
- Err(SpendCreationError::CoinSelection(amount)) => {
- self.amount_left_to_select = Some(Amount::from_sat(amount.missing));
+ Ok(CreateSpendResult::InsufficientFunds { missing }) => {
+ self.amount_left_to_select = Some(Amount::from_sat(missing));
}
Err(e) => {
self.warning = Some(e.into());
@@ -300,16 +261,6 @@ impl DefineSpend {
}
}
-pub struct DaemonTxGetter<'a>(&'a Arc);
-impl<'a> TxGetter for DaemonTxGetter<'a> {
- fn get_tx(&mut self, txid: &bitcoin::Txid) -> Option {
- self.0
- .list_txs(&[*txid])
- .ok()
- .and_then(|mut txs| txs.transactions.pop().map(|tx| tx.tx))
- }
-}
-
impl Step for DefineSpend {
fn update(
&mut self,