wallet: fix confirmations count, ability to repost and cancel transaction at posting state after timeout, repost height, fix posting state flag, cancel tx at send/receive modal

This commit is contained in:
ardocrat 2024-04-21 19:59:12 +03:00
parent f42fd94281
commit 1b7d96eff5
5 changed files with 132 additions and 38 deletions

View file

@ -358,8 +358,9 @@ impl WalletContent {
columns[1].vertical_centered_justified(|ui| {
let is_messages = current_type == WalletTabType::Messages;
View::tab_button(ui, CHAT_CIRCLE_TEXT, is_messages, || {
let dandelion = wallet.get_config().use_dandelion.unwrap_or(true);
self.current_tab = Box::new(WalletMessages::new(dandelion));
self.current_tab = Box::new(
WalletMessages::new(wallet.can_use_dandelion())
);
});
});
columns[2].vertical_centered_justified(|ui| {

View file

@ -671,7 +671,7 @@ impl WalletMessages {
} else {
t!("wallets.invoice_desc","amount" => amount_format)
};
ui.label(RichText::new(desc_text).size(16.0).color(Colors::INACTIVE_TEXT));
ui.label(RichText::new(desc_text).size(16.0).color(Colors::GRAY));
ui.add_space(6.0);
View::horizontal_line(ui, Colors::ITEM_STROKE);
ui.add_space(3.0);
@ -699,12 +699,37 @@ impl WalletMessages {
});
ui.add_space(2.0);
View::horizontal_line(ui, Colors::ITEM_STROKE);
ui.add_space(10.0);
});
// Show modal buttons.
ui.add_space(12.0);
// Setup spacing between buttons.
ui.spacing_mut().item_spacing = egui::Vec2::new(6.0, 0.0);
ui.columns(2, |columns| {
columns[0].vertical_centered_justified(|ui| {
// Button to cancel transaction.
let clear_text = format!("{} {}", PROHIBIT, t!("modal.cancel"));
View::button(ui, clear_text, Colors::BUTTON, || {
if let Ok(slate) = wallet.parse_slatepack(self.request_edit.clone()) {
if let Some(tx) = wallet.tx_by_slate(&slate) {
wallet.cancel(tx.data.id);
}
}
self.amount_edit = "".to_string();
self.request_edit = "".to_string();
modal.close();
});
});
columns[1].vertical_centered_justified(|ui| {
// Draw copy button.
let copy_text = format!("{} {}", COPY, t!("copy"));
View::button(ui, copy_text, Colors::BUTTON, || {
cb.copy_string_to_buffer(self.request_edit.clone());
self.amount_edit = "".to_string();
self.request_edit = "".to_string();
modal.close();
});
});
});

View file

@ -15,10 +15,10 @@
use egui::{Align, Id, Layout, Margin, RichText, Rounding, ScrollArea};
use egui::scroll_area::ScrollBarVisibility;
use grin_core::core::amount_to_hr_string;
use grin_wallet_libwallet::{TxLogEntryType};
use grin_wallet_libwallet::{Slate, SlateState, TxLogEntryType};
use crate::gui::Colors;
use crate::gui::icons::{ARROW_CIRCLE_DOWN, BRIDGE, CALENDAR_CHECK, CHAT_CIRCLE_TEXT, CHECK_CIRCLE, DOTS_THREE_CIRCLE, FILE_TEXT, GEAR_FINE, PROHIBIT, X_CIRCLE};
use crate::gui::icons::{ARROW_CIRCLE_DOWN, ARROWS_CLOCKWISE, BRIDGE, CALENDAR_CHECK, CHAT_CIRCLE_TEXT, CHECK_CIRCLE, DOTS_THREE_CIRCLE, FILE_TEXT, GEAR_FINE, PROHIBIT, X_CIRCLE};
use crate::gui::platform::PlatformCallbacks;
use crate::gui::views::{Root, View};
use crate::gui::views::wallets::types::WalletTab;
@ -183,14 +183,43 @@ fn tx_item_ui(ui: &mut egui::Ui,
//TODO: Show tx info
});
if !tx.posting && !tx.data.confirmed &&
// Setup flag to repost unconfirmed posting transaction after min confirmation time.
let last_height = data.info.last_confirmed_height;
let min_conf = data.info.minimum_confirmations;
let can_repost = tx.posting && tx.repost_height.is_some() &&
last_height - tx.repost_height.unwrap() > min_conf;
// Draw cancel button for txs to repost or also non-cancelled, non-posting.
if can_repost || (!tx.posting && !tx.data.confirmed &&
tx.data.tx_type != TxLogEntryType::TxReceivedCancelled
&& tx.data.tx_type != TxLogEntryType::TxSentCancelled {
&& tx.data.tx_type != TxLogEntryType::TxSentCancelled) {
View::item_button(ui, Rounding::default(), PROHIBIT, Some(Colors::RED), || {
wallet.cancel(tx.data.id);
});
}
// Draw button to repost transaction.
if can_repost {
View::item_button(ui,
Rounding::default(),
ARROWS_CLOCKWISE,
Some(Colors::GREEN), || {
// Create slate to check existing file.
let mut slate = Slate::blank(1, false);
slate.id = tx.data.tx_slate_id.unwrap();
slate.state = match tx.data.tx_type {
TxLogEntryType::TxReceived => SlateState::Invoice3,
_ => SlateState::Standard3
};
// Post tx after getting slate from slatepack file.
if let Some(sp) = wallet.read_slatepack(&slate) {
if let Ok(s) = wallet.parse_slatepack(sp) {
let _ = wallet.post(&s, wallet.can_use_dandelion());
}
}
});
}
let layout_size = ui.available_size();
ui.allocate_ui_with_layout(layout_size, Layout::left_to_right(Align::Center), |ui| {
ui.add_space(12.0);
@ -230,9 +259,7 @@ fn tx_item_ui(ui: &mut egui::Ui,
|| tx.data.tx_type == TxLogEntryType::TxReceivedCancelled;
if is_canceled {
format!("{} {}", X_CIRCLE, t!("wallets.tx_canceled"))
} else if tx.posting || (tx.data.kernel_excess.is_some() &&
(tx.data.tx_type == TxLogEntryType::TxReceived ||
tx.data.tx_type == TxLogEntryType::TxSent)) {
} else if tx.posting {
format!("{} {}", DOTS_THREE_CIRCLE, t!("wallets.tx_finalizing"))
} else {
match tx.data.tx_type {
@ -254,7 +281,7 @@ fn tx_item_ui(ui: &mut egui::Ui,
format!("{} {}", CHECK_CIRCLE, t!("wallets.tx_confirmed"))
},
TxLogEntryType::TxSent | TxLogEntryType::TxReceived => {
if data.info.last_confirmed_height - tx_height > min_conf + 1 {
if data.info.last_confirmed_height - tx_height > min_conf {
let text = if tx.data.tx_type == TxLogEntryType::TxSent {
t!("wallets.tx_sent")
} else {

View file

@ -28,7 +28,7 @@ pub enum PhraseMode {
Import
}
/// Mnemonic phrase size based on words count.
/// Mnemonic phrase size based on entropy.
#[derive(PartialEq, Clone)]
pub enum PhraseSize { Words12, Words15, Words18, Words21, Words24 }
@ -41,7 +41,7 @@ impl PhraseSize {
PhraseSize::Words24
];
/// Gen words count number.
/// Get entropy value.
pub fn value(&self) -> usize {
match *self {
PhraseSize::Words12 => 12,
@ -52,7 +52,7 @@ impl PhraseSize {
}
}
/// Gen entropy size for current phrase size.
/// Get entropy size for current phrase size.
pub fn entropy_size(&self) -> usize {
match *self {
PhraseSize::Words12 => 16,
@ -63,6 +63,7 @@ impl PhraseSize {
}
}
/// Get phrase type for entropy size.
pub fn type_for_value(count: usize) -> Option<PhraseSize> {
if Self::is_correct_count(count) {
match count {
@ -90,7 +91,7 @@ impl PhraseSize {
}
}
/// Check if correct word count provided.
/// Check if correct entropy size was provided.
pub fn is_correct_count(count: usize) -> bool {
count == 12 || count == 15 || count == 18 || count == 21 || count == 24
}
@ -144,8 +145,10 @@ pub struct WalletData {
pub struct WalletTransaction {
/// Transaction information.
pub data: TxLogEntry,
/// Calculated total transaction amount.
/// Calculated transaction amount between debited and credited amount.
pub amount: u64,
/// Flag to check if transaction is posting after finalizing.
pub posting: bool
/// Flag to check if transaction is posting after finalization.
pub posting: bool,
/// Last wallet block height of transaction reposting.
pub repost_height: Option<u64>
}

View file

@ -13,7 +13,6 @@
// limitations under the License.
use std::{fs, thread};
use std::collections::BTreeSet;
use std::fs::File;
use std::io::Write;
use std::net::{SocketAddr, TcpListener};
@ -64,6 +63,7 @@ pub struct Wallet {
is_open: Arc<AtomicBool>,
/// Flag to check if wallet is closing.
closing: Arc<AtomicBool>,
/// Flag to check if wallet was deleted to remove it from the list.
deleted: Arc<AtomicBool>,
@ -222,7 +222,13 @@ impl Wallet {
w_config.save();
}
/// Update usage of Dandelion to broadcast transactions.
/// Check if Dandelion usage is needed to post transactions.
pub fn can_use_dandelion(&self) -> bool {
let r_config = self.config.read().unwrap();
r_config.use_dandelion.unwrap_or(false)
}
/// Update usage of Dandelion to post transactions.
pub fn update_use_dandelion(&self, use_dandelion: bool) {
let mut w_config = self.config.write().unwrap();
w_config.use_dandelion = Some(use_dandelion);
@ -470,7 +476,7 @@ impl Wallet {
}
/// Create Slatepack message from provided slate.
fn create_slatepack_message(&self, slate: Slate) -> Result<String, Error> {
fn create_slatepack_message(&self, slate: &Slate) -> Result<String, Error> {
let mut message = "".to_string();
let mut api = Owner::new(self.instance.clone().unwrap(), None);
controller::owner_single_use(None, None, Some(&mut api), |api, m| {
@ -528,7 +534,7 @@ impl Wallet {
api.tx_lock_outputs(None, &slate)?;
// Create Slatepack message response.
let response = self.create_slatepack_message(slate)?;
let response = self.create_slatepack_message(&slate)?;
// Sync wallet info.
self.sync();
@ -547,7 +553,7 @@ impl Wallet {
let slate = api.issue_invoice_tx(None, args)?;
// Create Slatepack message response.
let response = self.create_slatepack_message(slate)?;
let response = self.create_slatepack_message(&slate)?;
// Sync wallet info.
self.sync();
@ -571,7 +577,7 @@ impl Wallet {
api.tx_lock_outputs(None, &slate)?;
// Create Slatepack message response.
let response = self.create_slatepack_message(slate)?;
let response = self.create_slatepack_message(&slate)?;
// Sync wallet info.
self.sync();
@ -588,7 +594,7 @@ impl Wallet {
Ok(())
})?;
// Create Slatepack message response.
let response = self.create_slatepack_message(slate)?;
let response = self.create_slatepack_message(&slate)?;
// Sync wallet info.
self.sync();
@ -601,10 +607,9 @@ impl Wallet {
let mut slate = self.parse_slatepack(message)?;
let api = Owner::new(self.instance.clone().unwrap(), None);
slate = api.finalize_tx(None, &slate)?;
// Create Slatepack message.
let _ = self.create_slatepack_message(slate.clone())?;
// Post transaction to blockchain.
api.post_tx(None, &slate, dandelion)?;
let _ = self.create_slatepack_message(&slate)?;
let _ = self.post(&slate, dandelion);
// Sync wallet info.
self.sync();
Ok(slate)
@ -615,6 +620,24 @@ impl Wallet {
// Post transaction to blockchain.
let api = Owner::new(self.instance.clone().unwrap(), None);
api.post_tx(None, slate, dandelion)?;
// Setup transaction repost height and posting flag.
let mut slate = slate.clone();
if slate.state == SlateState::Invoice2 {
slate.state = SlateState::Invoice3
} else if slate.state == SlateState::Standard2 {
slate.state = SlateState::Standard3
};
if let Some(tx) = self.tx_by_slate(&slate) {
let mut w_data = self.data.write().unwrap();
let mut data = w_data.clone().unwrap();
for t in &mut data.txs {
if t.data.id == tx.data.id {
t.repost_height = Some(data.info.last_confirmed_height);
t.posting = true;
}
}
*w_data = Some(data);
}
// Sync wallet info.
self.sync();
Ok(())
@ -922,7 +945,7 @@ fn sync_wallet_data(wallet: &Wallet) {
});
let txs_args = RetrieveTxQueryArgs {
exclude_cancelled: Some(true),
exclude_cancelled: Some(false),
sort_field: Some(RetrieveTxQuerySortField::CreationTimestamp),
sort_order: Some(RetrieveTxQuerySortOrder::Desc),
..Default::default()
@ -956,9 +979,10 @@ fn sync_wallet_data(wallet: &Wallet) {
}).collect::<Vec<TxLogEntry>>();
// Create wallet txs.
let mut txs: Vec<WalletTransaction> = vec![];
let mut new_txs: Vec<WalletTransaction> = vec![];
for tx in &filter_txs {
println!("{}", serde_json::to_string(tx).unwrap());
// Setup transaction amount.
let amount = if tx.amount_debited > tx.amount_credited {
tx.amount_debited - tx.amount_credited
} else {
@ -979,7 +1003,7 @@ fn sync_wallet_data(wallet: &Wallet) {
// Setup posting status if we have other tx with same slate id.
let mut same_tx_posting = false;
for t in &mut txs {
for t in &mut new_txs {
if t.data.tx_slate_id == tx.tx_slate_id &&
tx.tx_type != t.data.tx_type {
same_tx_posting = t.posting ||
@ -995,16 +1019,30 @@ fn sync_wallet_data(wallet: &Wallet) {
false
};
txs.push(WalletTransaction {
// Setup reposting height.
let mut repost_height = None;
if posting {
if let Some(mut data) = wallet.get_data() {
for t in data.txs {
if t.data.id == tx.id {
repost_height = t.repost_height;
break;
}
}
}
}
new_txs.push(WalletTransaction {
data: tx.clone(),
amount,
posting,
repost_height,
})
}
// Update wallet data.
let mut w_data = wallet.data.write().unwrap();
*w_data = Some(WalletData { info: info.1, txs });
*w_data = Some(WalletData { info: info.1, txs: new_txs });
return;
}
}