diff --git a/gui/src/app/view/psbt.rs b/gui/src/app/view/psbt.rs index 42aadaf5..4a4f4e6b 100644 --- a/gui/src/app/view/psbt.rs +++ b/gui/src/app/view/psbt.rs @@ -198,14 +198,25 @@ pub fn spend_header<'a>( let txid = tx.psbt.unsigned_tx.txid().to_string(); Column::new() .spacing(20) - .push(if let Some(label) = labels_editing.get(&txid) { + .push(if let Some(outpoint) = tx.is_single_payment() { + let outpoint = outpoint.to_string(); + if let Some(label) = labels_editing.get(&outpoint) { + label::label_editing(vec![outpoint.clone(), txid.clone()], label, H3_SIZE) + } else { + label::label_editable( + vec![outpoint.clone(), txid.clone()], + tx.labels.get(&outpoint), + H3_SIZE, + ) + } + } else if let Some(label) = labels_editing.get(&txid) { label::label_editing(vec![txid.clone()], label, H3_SIZE) } else { - label::label_editable(vec![txid.clone()], tx.labels.get(&txid), H1_SIZE) + label::label_editable(vec![txid.clone()], tx.labels.get(&txid), H3_SIZE) }) .push( Column::new() - .push(if tx.is_self_send() { + .push(if tx.is_send_to_self() { Container::new(h1("Self-transfer")) } else { Container::new(amount_with_size(&tx.spend_amount, H1_SIZE)) diff --git a/gui/src/app/view/psbts.rs b/gui/src/app/view/psbts.rs index 1cff99c9..a386cc7a 100644 --- a/gui/src/app/view/psbts.rs +++ b/gui/src/app/view/psbts.rs @@ -96,7 +96,7 @@ fn spend_tx_list_view(i: usize, tx: &SpendTx) -> Element<'_, Message> { Row::new() .push( Row::new() - .push(if tx.is_self_send() { + .push(if tx.is_send_to_self() { badge::cycle() } else { badge::spend() @@ -147,7 +147,7 @@ fn spend_tx_list_view(i: usize, tx: &SpendTx) -> Element<'_, Message> { .push( Column::new() .align_items(Alignment::End) - .push(if !tx.is_self_send() { + .push(if !tx.is_send_to_self() { Container::new(amount(&tx.spend_amount)) } else { Container::new(p1_regular("Self-transfer")) diff --git a/gui/src/daemon/model.rs b/gui/src/daemon/model.rs index 0afbffc4..005ab851 100644 --- a/gui/src/daemon/model.rs +++ b/gui/src/daemon/model.rs @@ -41,6 +41,7 @@ pub struct SpendTx { pub status: SpendStatus, pub sigs: PartialSpendInfo, pub updated_at: Option, + pub kind: TransactionKind, } #[derive(PartialOrd, Ord, Debug, Clone, PartialEq, Eq)] @@ -92,6 +93,31 @@ impl SpendTx { Self { labels: HashMap::new(), + kind: if spend_amount == Amount::from_sat(0) { + TransactionKind::SendToSelf + } else { + let outpoints: Vec = psbt + .unsigned_tx + .output + .iter() + .enumerate() + .filter_map(|(i, _)| { + if !change_indexes.contains(&i) { + Some(OutPoint { + txid: psbt.unsigned_tx.txid(), + vout: i as u32, + }) + } else { + None + } + }) + .collect(); + if outpoints.len() == 1 { + TransactionKind::OutgoingSinglePayment(outpoints[0]) + } else { + TransactionKind::OutgoingPaymentBatch(outpoints) + } + }, updated_at, coins, psbt, @@ -132,10 +158,6 @@ impl SpendTx { signers } - pub fn is_self_send(&self) -> bool { - !self.coins.is_empty() && self.spend_amount == Amount::from_sat(0) - } - /// Feerate obtained if all transaction inputs have the maximum satisfaction size. pub fn min_feerate_vb(&self) -> u64 { // This assumes all inputs are internal (have same max satisfaction size). @@ -144,15 +166,23 @@ impl SpendTx { self.fee_amount.to_sat() / max_tx_vbytes as u64 } + pub fn is_send_to_self(&self) -> bool { + matches!(self.kind, TransactionKind::SendToSelf) + } + + pub fn is_single_payment(&self) -> Option { + match self.kind { + TransactionKind::IncomingSinglePayment(outpoint) => Some(outpoint), + TransactionKind::OutgoingSinglePayment(outpoint) => Some(outpoint), + _ => None, + } + } + pub fn is_batch(&self) -> bool { - self.psbt - .unsigned_tx - .output - .iter() - .enumerate() - .filter(|(i, _)| !self.change_indexes.contains(i)) - .count() - > 1 + matches!( + self.kind, + TransactionKind::IncomingPaymentBatch(_) | TransactionKind::OutgoingPaymentBatch(_) + ) } }