Skip to content

Commit

Permalink
Merge #997: gui: add transaction redirection
Browse files Browse the repository at this point in the history
0c1a1b8 gui: add redirection to selected transaction panel (edouardparis)

Pull request description:

  based on #959
  This PR removes the payment section about the transaction inputs outputs for a redirection to the payment transaction (The `See transaction details` button). It makes it easy to fee bump a payment by clicking on it to be redirected to the transaction to rbf

  ![20240305_18h13m51s_grim](https://github.com/wizardsardine/liana/assets/6933020/bbb21e84-9fb6-4eed-ba93-2c4f6177cb95)

  Maybe the UX/UI of the payment should be changed to remove more transaction information, but I fear it makes the panel a little bit empty.

ACKs for top commit:
  jp1ac4:
    ACK 0c1a1b8.

Tree-SHA512: f767b1cbf86cafcd0b46e5dfc0625f15719b48314de93418b73e59bd32e6dc659ab2ea3a4e2d379680c4209bfbd633c5329fe9fa2616c042dd2851f62f860498
  • Loading branch information
edouardparis committed Mar 7, 2024
2 parents 505b218 + 0c1a1b8 commit f5a1551
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 61 deletions.
1 change: 1 addition & 0 deletions gui/src/app/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub enum Menu {
Receive,
PSBTs,
Transactions,
TransactionPreSelected(Txid),
Settings,
Coins,
CreateSpendTx,
Expand Down
13 changes: 13 additions & 0 deletions gui/src/app/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ impl Panels {
Menu::Receive => &self.receive,
Menu::PSBTs => &self.psbts,
Menu::Transactions => &self.transactions,
Menu::TransactionPreSelected(_) => &self.transactions,
Menu::Settings => &self.settings,
Menu::Coins => &self.coins,
Menu::CreateSpendTx => &self.create_spend,
Expand All @@ -99,6 +100,7 @@ impl Panels {
Menu::Receive => &mut self.receive,
Menu::PSBTs => &mut self.psbts,
Menu::Transactions => &mut self.transactions,
Menu::TransactionPreSelected(_) => &mut self.transactions,
Menu::Settings => &mut self.settings,
Menu::Coins => &mut self.coins,
Menu::CreateSpendTx => &mut self.create_spend,
Expand Down Expand Up @@ -152,6 +154,17 @@ impl App {

fn set_current_panel(&mut self, menu: Menu) -> Command<Message> {
match &menu {
menu::Menu::TransactionPreSelected(txid) => {
if let Ok(Some(tx)) = self
.daemon
.get_history_txs(&[*txid])
.map(|txs| txs.first().cloned())
{
self.panels.transactions.preselect(tx);
self.panels.current = menu;
return Command::none();
};
}
menu::Menu::PsbtPreSelected(txid) => {
// Get preselected spend from DB in case it's not yet in the cache.
// We only need this single spend as we will go straight to its view and not show the PSBTs list.
Expand Down
75 changes: 39 additions & 36 deletions gui/src/app/state/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub struct TransactionsPanel {
pending_txs: Vec<HistoryTransaction>,
txs: Vec<HistoryTransaction>,
labels_edited: LabelsEdited,
selected_tx: Option<usize>,
selected_tx: Option<HistoryTransaction>,
warning: Option<Error>,
create_rbf_modal: Option<CreateRbfModal>,
}
Expand All @@ -52,16 +52,17 @@ impl TransactionsPanel {
create_rbf_modal: None,
}
}

pub fn preselect(&mut self, tx: HistoryTransaction) {
self.selected_tx = Some(tx);
self.warning = None;
self.create_rbf_modal = None;
}
}

impl State for TransactionsPanel {
fn view<'a>(&'a self, cache: &'a Cache) -> Element<'a, view::Message> {
if let Some(i) = self.selected_tx {
let tx = if i < self.pending_txs.len() {
&self.pending_txs[i]
} else {
&self.txs[i - self.pending_txs.len()]
};
if let Some(tx) = self.selected_tx.as_ref() {
let content = view::transactions::tx_view(
cache,
tx,
Expand Down Expand Up @@ -121,40 +122,42 @@ impl State for TransactionsPanel {
return self.reload(daemon);
}
Message::View(view::Message::Select(i)) => {
self.selected_tx = Some(i);
self.selected_tx = if i < self.pending_txs.len() {
self.pending_txs.get(i).cloned()
} else {
self.txs.get(i - self.pending_txs.len()).cloned()
};
}
Message::View(view::Message::CreateRbf(view::CreateRbfMessage::Cancel)) => {
self.create_rbf_modal = None;
}
Message::View(view::Message::CreateRbf(view::CreateRbfMessage::New(is_cancel))) => {
if let Some(idx) = self.selected_tx {
if let Some(tx) = self.pending_txs.get(idx) {
if tx.fee_amount.is_some() {
let tx = tx.clone();
let txid = tx.tx.txid();
return Command::perform(
async move {
daemon
// TODO: filter for spending coins when this is possible:
// https://github.com/wizardsardine/liana/issues/677
.list_coins()
.map(|res| {
res.coins
.iter()
.filter_map(|c| {
if c.outpoint.txid == txid {
c.spend_info.map(|info| info.txid)
} else {
None
}
})
.collect()
})
.map_err(|e| e.into())
},
move |res| Message::RbfModal(tx, is_cancel, res),
);
}
if let Some(tx) = &self.selected_tx {
if tx.fee_amount.is_some() {
let tx = tx.clone();
let txid = tx.tx.txid();
return Command::perform(
async move {
daemon
// TODO: filter for spending coins when this is possible:
// https://github.com/wizardsardine/liana/issues/677
.list_coins()
.map(|res| {
res.coins
.iter()
.filter_map(|c| {
if c.outpoint.txid == txid {
c.spend_info.map(|info| info.txid)
} else {
None
}
})
.collect()
})
.map_err(|e| e.into())
},
move |res| Message::RbfModal(tx, is_cancel, res),
);
}
}
}
Expand Down
27 changes: 2 additions & 25 deletions gui/src/app/view/home.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,31 +315,8 @@ pub fn payment_view<'a>(
.spacing(5),
))
.push(
Column::new()
.spacing(20)
// We do not need to display inputs for external incoming transactions
.push_maybe(if tx.is_external() {
None
} else {
Some(super::psbt::inputs_view(
&tx.coins,
&tx.tx,
&tx.labels,
labels_editing,
))
})
.push(super::psbt::outputs_view(
&tx.tx,
cache.network,
if tx.is_external() {
None
} else {
Some(tx.change_indexes.clone())
},
&tx.labels,
labels_editing,
tx.is_single_payment().is_some(),
)),
button::primary(None, "See transaction details")
.on_press(Message::Menu(Menu::TransactionPreSelected(tx.tx.txid()))),
)
.spacing(20),
)
Expand Down
38 changes: 38 additions & 0 deletions gui/src/daemon/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,44 @@ pub trait Daemon: Debug {
Ok(txs)
}

fn get_history_txs(
&self,
txids: &[Txid],
) -> Result<Vec<model::HistoryTransaction>, DaemonError> {
let info = self.get_info()?;
let coins = self.list_coins()?.coins;
let txs = self.list_txs(txids)?.transactions;
let mut txs = txs
.into_iter()
.map(|tx| {
let mut tx_coins = Vec::new();
let mut change_indexes = Vec::new();
for coin in &coins {
if coin.outpoint.txid == tx.tx.txid() {
change_indexes.push(coin.outpoint.vout as usize)
} else if tx
.tx
.input
.iter()
.any(|input| input.previous_output == coin.outpoint)
{
tx_coins.push(coin.clone());
}
}
model::HistoryTransaction::new(
tx.tx,
tx.height,
tx.time,
tx_coins,
change_indexes,
info.network,
)
})
.collect();
load_labels(self, &mut txs)?;
Ok(txs)
}

fn list_pending_txs(&self) -> Result<Vec<model::HistoryTransaction>, DaemonError> {
let info = self.get_info()?;
let coins = self.list_coins()?.coins;
Expand Down

0 comments on commit f5a1551

Please sign in to comment.