Skip to content

Commit

Permalink
feat(wallet): add maturity to transaction detail (#3042)
Browse files Browse the repository at this point in the history
  • Loading branch information
stringhandler committed Jul 1, 2021
2 parents fb1a692 + 2cd35c5 commit 9b281ce
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 86 deletions.
171 changes: 93 additions & 78 deletions applications/tari_console_wallet/src/ui/components/transactions_tab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,17 @@ impl TransactionsTab {
.title(Span::styled("(P)ending Transactions", style));
f.render_widget(block, list_areas[0]);

self.draw_pending_transactions(f, list_areas[0], app_state);
self.draw_completed_transactions(f, list_areas[1], app_state);
}

fn draw_pending_transactions<B>(&mut self, f: &mut Frame<B>, area: Rect, app_state: &AppState)
where B: Backend {
// Pending Transactions
self.pending_list_state.set_num_items(app_state.get_pending_txs().len());
let mut pending_list_state = self
.pending_list_state
.get_list_state((list_areas[0].height as usize).saturating_sub(3));
.get_list_state((area.height as usize).saturating_sub(3));
let window = self.pending_list_state.get_start_end();
let windowed_view = app_state.get_pending_txs_slice(window.0, window.1);

Expand Down Expand Up @@ -132,8 +138,11 @@ impl TransactionsTab {
.add_column(Some("Amount"), Some(18), column1_items)
.add_column(Some("Local Date/Time"), Some(20), column2_items)
.add_column(Some("Message"), None, column3_items);
column_list.render(f, list_areas[0], &mut pending_list_state);
column_list.render(f, area, &mut pending_list_state);
}

fn draw_completed_transactions<B>(&mut self, f: &mut Frame<B>, area: Rect, app_state: &AppState)
where B: Backend {
// Completed Transactions
let style = if self.selected_tx_list == SelectedTransactionList::CompletedTxs {
Style::default().fg(Color::Magenta).add_modifier(Modifier::BOLD)
Expand All @@ -143,23 +152,35 @@ impl TransactionsTab {
let block = Block::default()
.borders(Borders::ALL)
.title(Span::styled("Completed (T)ransactions", style));
f.render_widget(block, list_areas[1]);
f.render_widget(block, area);

let completed_txs = app_state.get_completed_txs();
self.completed_list_state.set_num_items(completed_txs.len());
let mut completed_list_state = self
.completed_list_state
.get_list_state((list_areas[1].height as usize).saturating_sub(3));
let window = self.completed_list_state.get_start_end();
let windowed_view = &completed_txs[window.0..window.1];
.get_list_state((area.height as usize).saturating_sub(3));
let (start, end) = self.completed_list_state.get_start_end();
let windowed_view = &completed_txs[start..end];

let text_colors: HashMap<bool, Color> = [(true, Color::DarkGray), (false, Color::Reset)]
.iter()
.cloned()
.collect();

let base_node_state = app_state.get_base_node_state();
let chain_height = base_node_state
.chain_metadata
.as_ref()
.map(|cm| cm.height_of_longest_chain());

let mut column0_items = Vec::new();
let mut column1_items = Vec::new();
let mut column2_items = Vec::new();
let mut column3_items = Vec::new();

for t in windowed_view.iter() {
let text_color = text_colors.get(&t.cancelled).unwrap_or(&Color::Reset).to_owned();
let cancelled = t.cancelled || !t.valid;
let text_color = text_colors.get(&cancelled).unwrap_or(&Color::Reset).to_owned();
if t.direction == TransactionDirection::Outbound {
column0_items.push(ListItem::new(Span::styled(
format!("{}", t.destination_public_key),
Expand All @@ -176,11 +197,20 @@ impl TransactionsTab {
format!("{}", t.source_public_key),
Style::default().fg(text_color),
)));
let amount_style = if t.cancelled {
Style::default().fg(Color::Green).add_modifier(Modifier::DIM)
let maturity = if let Some(output) = t.transaction.body.outputs().first() {
output.features.maturity
} else {
Style::default().fg(Color::Green)
0
};
let color = match (t.cancelled, chain_height) {
// cancelled
(true, _) => Color::DarkGray,
// not mature yet
(_, Some(height)) if maturity > height => Color::Yellow,
// default
_ => Color::Green,
};
let amount_style = Style::default().fg(color);
column1_items.push(ListItem::new(Span::styled(format!("{}", t.amount), amount_style)));
}
let local_time = DateTime::<Local>::from_utc(t.timestamp, Local::now().offset().to_owned());
Expand Down Expand Up @@ -209,7 +239,7 @@ impl TransactionsTab {
.add_column(Some("Local Date/Time"), Some(20), column2_items)
.add_column(Some("Status"), None, column3_items);

column_list.render(f, list_areas[1], &mut completed_list_state);
column_list.render(f, area, &mut completed_list_state);
}

fn draw_detailed_transaction<B>(&self, f: &mut Frame<B>, area: Rect, app_state: &AppState)
Expand All @@ -226,27 +256,9 @@ impl TransactionsTab {
.margin(1)
.split(area);

// Labels:
let label_layout = Layout::default()
.constraints(
[
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
]
.as_ref(),
)
.split(columns[0]);
// Labels
let constraints = [Constraint::Length(1); 13];
let label_layout = Layout::default().constraints(constraints).split(columns[0]);

let tx_id = Span::styled("TxID:", Style::default().fg(Color::Magenta));
let source_public_key = Span::styled("Source Public Key:", Style::default().fg(Color::Magenta));
Expand All @@ -260,53 +272,41 @@ impl TransactionsTab {
let excess = Span::styled("Excess:", Style::default().fg(Color::Magenta));
let confirmations = Span::styled("Confirmations:", Style::default().fg(Color::Magenta));
let mined_height = Span::styled("Mined Height:", Style::default().fg(Color::Magenta));
let paragraph = Paragraph::new(tx_id).wrap(Wrap { trim: true });
let maturity = Span::styled("Maturity:", Style::default().fg(Color::Magenta));

let trim = Wrap { trim: true };
let paragraph = Paragraph::new(tx_id).wrap(trim);
f.render_widget(paragraph, label_layout[0]);
let paragraph = Paragraph::new(source_public_key).wrap(Wrap { trim: true });
let paragraph = Paragraph::new(source_public_key).wrap(trim);
f.render_widget(paragraph, label_layout[1]);
let paragraph = Paragraph::new(destination_public_key).wrap(Wrap { trim: true });
let paragraph = Paragraph::new(destination_public_key).wrap(trim);
f.render_widget(paragraph, label_layout[2]);
let paragraph = Paragraph::new(direction).wrap(Wrap { trim: true });
let paragraph = Paragraph::new(direction).wrap(trim);
f.render_widget(paragraph, label_layout[3]);
let paragraph = Paragraph::new(amount).wrap(Wrap { trim: true });
let paragraph = Paragraph::new(amount).wrap(trim);
f.render_widget(paragraph, label_layout[4]);
let paragraph = Paragraph::new(fee).wrap(Wrap { trim: true });
let paragraph = Paragraph::new(fee).wrap(trim);
f.render_widget(paragraph, label_layout[5]);
let paragraph = Paragraph::new(status).wrap(Wrap { trim: true });
let paragraph = Paragraph::new(status).wrap(trim);
f.render_widget(paragraph, label_layout[6]);
let paragraph = Paragraph::new(message).wrap(Wrap { trim: true });
let paragraph = Paragraph::new(message).wrap(trim);
f.render_widget(paragraph, label_layout[7]);
let paragraph = Paragraph::new(timestamp).wrap(Wrap { trim: true });
let paragraph = Paragraph::new(timestamp).wrap(trim);
f.render_widget(paragraph, label_layout[8]);
let paragraph = Paragraph::new(excess).wrap(Wrap { trim: true });
let paragraph = Paragraph::new(excess).wrap(trim);
f.render_widget(paragraph, label_layout[9]);
let paragraph = Paragraph::new(confirmations).wrap(Wrap { trim: true });
let paragraph = Paragraph::new(confirmations).wrap(trim);
f.render_widget(paragraph, label_layout[10]);
let paragraph = Paragraph::new(mined_height).wrap(Wrap { trim: true });
let paragraph = Paragraph::new(mined_height).wrap(trim);
f.render_widget(paragraph, label_layout[11]);
// Content:
let paragraph = Paragraph::new(maturity).wrap(trim);
f.render_widget(paragraph, label_layout[12]);

// Content
let required_confirmations = app_state.get_required_confirmations();
if let Some(tx) = self.detailed_transaction.as_ref() {
let content_layout = Layout::default()
.constraints(
[
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
Constraint::Length(1),
]
.as_ref(),
)
.split(columns[1]);
let constraints = [Constraint::Length(1); 13];
let content_layout = Layout::default().constraints(constraints).split(columns[1]);
let tx_id = Span::styled(format!("{}", tx.tx_id), Style::default().fg(Color::White));

let source_public_key =
Expand Down Expand Up @@ -366,31 +366,46 @@ impl TransactionsTab {
.unwrap_or_else(|| "N/A".to_string()),
Style::default().fg(Color::White),
);
let maturity = tx
.transaction
.body
.outputs()
.first()
.map(|o| o.features.maturity)
.unwrap_or_else(|| 0);
let maturity = if maturity > 0 {
format!("Spendable at Block #{}", maturity)
} else {
"N/A".to_string()
};
let maturity = Span::styled(maturity, Style::default().fg(Color::White));

let paragraph = Paragraph::new(tx_id).wrap(Wrap { trim: true });
let paragraph = Paragraph::new(tx_id).wrap(trim);
f.render_widget(paragraph, content_layout[0]);
let paragraph = Paragraph::new(source_public_key).wrap(Wrap { trim: true });
let paragraph = Paragraph::new(source_public_key).wrap(trim);
f.render_widget(paragraph, content_layout[1]);
let paragraph = Paragraph::new(destination_public_key).wrap(Wrap { trim: true });
let paragraph = Paragraph::new(destination_public_key).wrap(trim);
f.render_widget(paragraph, content_layout[2]);
let paragraph = Paragraph::new(direction).wrap(Wrap { trim: true });
let paragraph = Paragraph::new(direction).wrap(trim);
f.render_widget(paragraph, content_layout[3]);
let paragraph = Paragraph::new(amount).wrap(Wrap { trim: true });
let paragraph = Paragraph::new(amount).wrap(trim);
f.render_widget(paragraph, content_layout[4]);
let paragraph = Paragraph::new(fee).wrap(Wrap { trim: true });
let paragraph = Paragraph::new(fee).wrap(trim);
f.render_widget(paragraph, content_layout[5]);
let paragraph = Paragraph::new(status).wrap(Wrap { trim: true });
let paragraph = Paragraph::new(status).wrap(trim);
f.render_widget(paragraph, content_layout[6]);
let paragraph = Paragraph::new(message).wrap(Wrap { trim: true });
let paragraph = Paragraph::new(message).wrap(trim);
f.render_widget(paragraph, content_layout[7]);
let paragraph = Paragraph::new(timestamp).wrap(Wrap { trim: true });
let paragraph = Paragraph::new(timestamp).wrap(trim);
f.render_widget(paragraph, content_layout[8]);
let paragraph = Paragraph::new(excess).wrap(Wrap { trim: true });
let paragraph = Paragraph::new(excess).wrap(trim);
f.render_widget(paragraph, content_layout[9]);
let paragraph = Paragraph::new(confirmations).wrap(Wrap { trim: true });
let paragraph = Paragraph::new(confirmations).wrap(trim);
f.render_widget(paragraph, content_layout[10]);
let paragraph = Paragraph::new(mined_height).wrap(Wrap { trim: true });
let paragraph = Paragraph::new(mined_height).wrap(trim);
f.render_widget(paragraph, content_layout[11]);
let paragraph = Paragraph::new(maturity).wrap(trim);
f.render_widget(paragraph, content_layout[12]);
}
}
}
Expand All @@ -403,7 +418,7 @@ impl<B: Backend> Component<B> for TransactionsTab {
Constraint::Length(3),
Constraint::Length(1),
Constraint::Min(10),
Constraint::Length(14),
Constraint::Length(15),
]
.as_ref(),
)
Expand Down
5 changes: 4 additions & 1 deletion base_layer/wallet/src/output_manager_service/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1274,8 +1274,11 @@ impl Balance {
impl fmt::Display for Balance {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "Available balance: {}", self.available_balance)?;
if let Some(locked) = self.time_locked_balance {
writeln!(f, "Time locked: {}", locked)?;
}
writeln!(f, "Pending incoming balance: {}", self.pending_incoming_balance)?;
write!(f, "Pending outgoing balance: {}", self.pending_outgoing_balance)?;
writeln!(f, "Pending outgoing balance: {}", self.pending_outgoing_balance)?;
Ok(())
}
}
Expand Down
2 changes: 1 addition & 1 deletion base_layer/wallet/src/transaction_service/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1804,7 +1804,7 @@ where
MicroTari::from(0),
tx.clone(),
TransactionStatus::Coinbase,
format!("Coinbase Transaction for Block {}", block_height),
format!("Coinbase Transaction for Block #{}", block_height),
Utc::now().naive_utc(),
TransactionDirection::Inbound,
Some(block_height),
Expand Down
7 changes: 1 addition & 6 deletions base_layer/wallet/tests/output_manager_service/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,12 +297,7 @@ fn generate_sender_transaction_message(amount: MicroTari) -> (TxId, TransactionS
.with_change_secret(alice.change_spend_key)
.with_input(utxo, input)
.with_amount(0, amount)
.with_recipient_script(
0,
script!(Nop),
PrivateKey::random(&mut OsRng),
OutputFeatures::default(),
)
.with_recipient_script(0, script!(Nop), PrivateKey::random(&mut OsRng), Default::default())
.with_change_script(
script!(Nop),
inputs!(PublicKey::from_secret_key(&script_private_key)),
Expand Down

0 comments on commit 9b281ce

Please sign in to comment.