diff --git a/locales/en.yml b/locales/en.yml index 67fa5c7..ead0146 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -64,19 +64,27 @@ wallets: tx_cancelling: Cancelling tx_canceled: Canceled tx_confirmed: Confirmed - manually: Manually - receive_slatepack_desc: 'Enter Slatepack message received from the sender to create response or finalize the transaction:' - receive_send_slatepack: 'Send Slatepack message to the sender to finalize the transaction:' - receive_slatepack_err: 'An error occurred during creation of the response, check input data:' - create_response: Create response - invoice: Invoice - issue_invoice: Issue invoice - issue_invoice_desc: 'Create a request to receive funds by entering the required amount:' - invoice_desc: 'You have created a request to receive %{amount} ツ. Send Slatepack message to the sender:' + txs: Transactions + messages: Messages + transport: Transport + input_slatepack_desc: 'Enter received message to create a response or finalize the transaction:' + send_slatepack_desc: 'Send message to the receiver to finalize the transaction:' + parse_slatepack_err: 'An error occurred during handling of the message, check input data:' + parse_i1_slatepack_desc: 'To pay %{amount} ツ send message to the receiver:' + parse_i2_slatepack_desc: 'Finalize transaction to receive %{amount} ツ' + parse_s1_slatepack_desc: 'To receive %{amount} ツ send message to the sender:' + parse_s2_slatepack_desc: 'Finalize transaction to send %{amount} ツ' + response_slatepack_err: 'An error occurred during creation of the response, check input data:' + create_request_desc: 'Create a request to send or receive the funds:' + send_request_desc: 'You have created a request to send %{amount} ツ. Send message to the receiver of the funds:' + send_slatepack_err: An error occurred during creation of request to send funds, check input data. + invoice_desc: 'You have created a request to receive %{amount} ツ. Send message to the sender of the funds:' invoice_slatepack_err: An error occurred during issuing of the invoice, check input data. - finalize_slatepack_err: 'An error occurred during finalization of the transaction, check input data:' + finalize_slatepack_err: 'An error occurred during finalization, check input data:' finalize: Finalize - enter_amount: 'Enter amount:' + use_dandelion: Use Dandelion + enter_amount_send: 'You have %{amount} ツ. Enter amount to send:' + enter_amount_receive: 'Enter amount to receive:' recovery: Recovery repair_wallet: Repair wallet repair_desc: Check a wallet, repairing and restoring missing outputs if required. This operation will take time. diff --git a/locales/ru.yml b/locales/ru.yml index 1427e5f..a32f4e1 100644 --- a/locales/ru.yml +++ b/locales/ru.yml @@ -64,19 +64,27 @@ wallets: tx_cancelling: Отмена tx_canceled: Отменено tx_confirmed: Подтверждено - manually: Вручную - receive_slatepack_desc: 'Введите Slatepack сообщение, полученное от отправителя, для создания ответа или завершения транзакции:' - receive_send_slatepack: 'Отправьте Slatepack сообщение отправителю для завершения транзакции:' - receive_slatepack_err: 'Во время создания ответа произошла ошибка, проверьте входные данные:' - create_response: Создать ответ - invoice: Инвойс - issue_invoice: Выставить счёт - issue_invoice_desc: 'Создайте запрос на получение средств, введя требуемое количество:' - invoice_desc: 'Вы создали запрос на получение %{amount} ツ. Отправьте Slatepack сообщение отправителю:' + txs: Транзакции + messages: Сообщения + transport: Транспорт + input_slatepack_desc: 'Введите полученное сообщение для создания ответа или завершения транзакции:' + send_slatepack_desc: 'Отправьте сообщение получателю средств для завершения транзакции:' + parse_slatepack_err: 'Во время обработки сообщения произошла ошибка, проверьте входные данные:' + parse_i1_slatepack_desc: 'Для оплаты %{amount} ツ отправьте сообщение получателю:' + parse_i2_slatepack_desc: 'Завершите транзакцию для получения %{amount} ツ' + parse_s1_slatepack_desc: 'Для получения %{amount} ツ отправьте сообщение отправителю:' + parse_s2_slatepack_desc: 'Завершите транзакцию для отправки %{amount} ツ' + response_slatepack_err: 'Во время создания ответа произошла ошибка, проверьте входные данные:' + create_request_desc: 'Cоздать запрос на получение или отправку средств:' + send_request_desc: 'Вы создали запрос на отправку %{amount} ツ. Отправьте сообщение получателю средств:' + send_slatepack_err: Во время создания запроса на отправку средств произошла ошибка, проверьте входные данные. + invoice_desc: 'Вы создали запрос на получение %{amount} ツ. Отправьте сообщение отправителю средств:' invoice_slatepack_err: Во время выставления счёта произошла ошибка, проверьте входные данные. - finalize_slatepack_err: 'Во время завершения транзакции произошла ошибка, проверьте входные данные:' + finalize_slatepack_err: 'Во время завершения произошла ошибка, проверьте входные данные:' finalize: Завершить - enter_amount: 'Введите количество:' + use_dandelion: Использовать Dandelion + enter_amount_send: 'У вас есть %{amount} ツ. Введите количество для отправки:' + enter_amount_receive: 'Введите количество для получения:' recovery: Восстановление repair_wallet: Починить кошелёк repair_desc: Проверить кошелёк, исправляя и восстанавливая недостающие выходы, если это необходимо. Эта операция займёт время. diff --git a/src/gui/views/network/settings.rs b/src/gui/views/network/settings.rs index 34dca7f..13c8403 100644 --- a/src/gui/views/network/settings.rs +++ b/src/gui/views/network/settings.rs @@ -40,8 +40,6 @@ pub struct NetworkSettings { modal_ids: Vec<&'static str> } -/// Identifier for node restart confirmation [`Modal`]. -pub const NODE_RESTART_REQUIRED_MODAL: &'static str = "node_restart_required"; /// Identifier for settings reset confirmation [`Modal`]. pub const RESET_SETTINGS_MODAL: &'static str = "reset_settings"; @@ -54,7 +52,6 @@ impl Default for NetworkSettings { pool: PoolSetup::default(), dandelion: DandelionSetup::default(), modal_ids: vec![ - NODE_RESTART_REQUIRED_MODAL, RESET_SETTINGS_MODAL ] } @@ -72,7 +69,6 @@ impl ModalContainer for NetworkSettings { modal: &Modal, _: &dyn PlatformCallbacks) { match modal.id { - NODE_RESTART_REQUIRED_MODAL => node_restart_required_modal(ui, modal), RESET_SETTINGS_MODAL => reset_settings_confirmation_modal(ui, modal), _ => {} } @@ -147,17 +143,6 @@ impl NetworkSettings { } } - /// Show [`Modal`] to ask node restart if setting is changed on enabled node. - pub fn show_node_restart_required_modal() { - if Node::is_running() { - // Show modal to apply changes by node restart. - Modal::new(NODE_RESTART_REQUIRED_MODAL) - .position(ModalPosition::Center) - .title(t!("network.settings")) - .show(); - } - } - /// Draw IP addresses as radio buttons. pub fn ip_addrs_ui(ui: &mut egui::Ui, saved_ip: &String, @@ -209,38 +194,6 @@ impl NetworkSettings { } } -/// Node restart reminder modal content. -fn node_restart_required_modal(ui: &mut egui::Ui, modal: &Modal) { - ui.add_space(6.0); - ui.vertical_centered(|ui| { - ui.label(RichText::new(t!("network_settings.restart_node_required")) - .size(17.0) - .color(Colors::GRAY)); - ui.add_space(8.0); - }); - - // Show modal buttons. - ui.scope(|ui| { - // 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| { - View::button(ui, t!("network_settings.restart"), Colors::WHITE, || { - Node::restart(); - modal.close(); - }); - }); - columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("modal.cancel"), Colors::WHITE, || { - modal.close(); - }); - }); - }); - ui.add_space(6.0); - }); -} - /// Draw button to reset integrated node settings to default values. fn reset_settings_ui(ui: &mut egui::Ui) { ui.vertical_centered(|ui| { diff --git a/src/gui/views/network/setup/node.rs b/src/gui/views/network/setup/node.rs index 37ad76e..39a6a1d 100644 --- a/src/gui/views/network/setup/node.rs +++ b/src/gui/views/network/setup/node.rs @@ -243,7 +243,9 @@ impl NodeSetup { if saved_chain_type != selected_chain_type { AppConfig::change_chain_type(&selected_chain_type); - NetworkSettings::show_node_restart_required_modal(); + if Node::is_running() { + Node::restart(); + } } } @@ -520,7 +522,9 @@ impl NodeSetup { let validate = NodeConfig::is_full_chain_validation(); View::checkbox(ui, validate, t!("network_settings.full_validation"), || { NodeConfig::toggle_full_chain_validation(); - NetworkSettings::show_node_restart_required_modal(); + if Node::is_running() { + Node::restart(); + } }); ui.add_space(4.0); ui.label(RichText::new(t!("network_settings.full_validation_description")) @@ -534,7 +538,9 @@ impl NodeSetup { let archive_mode = NodeConfig::is_archive_mode(); View::checkbox(ui, archive_mode, t!("network_settings.archive_mode"), || { NodeConfig::toggle_archive_mode(); - NetworkSettings::show_node_restart_required_modal(); + if Node::is_running() { + Node::restart(); + } }); ui.add_space(4.0); ui.label(RichText::new(t!("network_settings.archive_mode_desc")) diff --git a/src/gui/views/views.rs b/src/gui/views/views.rs index 05924c5..1a3c5cf 100644 --- a/src/gui/views/views.rs +++ b/src/gui/views/views.rs @@ -363,13 +363,10 @@ impl View { let mut r = range.clone(); let mut index = r.primary.index; - println!("insert_str {} {}", index, w_input.as_str()); value.insert_text(w_input.as_str(), index); index = index + 1; - println!("12345 {} {}", value, r.primary.index); - if index == 0 { r.primary.index = value.len(); r.secondary.index = r.primary.index; diff --git a/src/gui/views/wallets/content.rs b/src/gui/views/wallets/content.rs index 122d484..241c432 100644 --- a/src/gui/views/wallets/content.rs +++ b/src/gui/views/wallets/content.rs @@ -160,15 +160,15 @@ impl WalletsContent { }); // Flag to check if wallet list is hidden on the screen. - let list_hidden = content_width == 0.0 + let list_hidden = content_width == 0.0 || empty_list || create_wallet || (dual_panel && show_wallet && !self.show_wallets_at_dual_panel) || (!dual_panel && show_wallet); // Setup flag to show wallets bottom panel if wallet is not showing // at non-dual panel mode and network is no open or showing at dual panel mode. - let show_bottom_panel = - (!show_wallet && !dual_panel && !Root::is_network_panel_open()) || - (dual_panel && show_wallet); + let show_bottom_panel = !list_hidden && + ((!show_wallet && !dual_panel && !Root::is_network_panel_open()) || + (dual_panel && show_wallet)); // Show wallets bottom panel. egui::TopBottomPanel::bottom("wallets_bottom_panel") @@ -183,7 +183,7 @@ impl WalletsContent { }, ..Default::default() }) - .show_animated_inside(ui, !create_wallet && !list_hidden && show_bottom_panel, |ui| { + .show_animated_inside(ui, show_bottom_panel, |ui| { // Setup vertical padding inside buttons. ui.style_mut().spacing.button_padding = egui::vec2(10.0, 4.0); @@ -195,8 +195,8 @@ impl WalletsContent { }); }); - // Show non-empty list if wallet is not creating. - if !empty_list && !create_wallet { + // Show non-empty list if wallet is not creating and list not hidden. + if !list_hidden { // Show wallet list panel. egui::CentralPanel::default() .frame(egui::Frame { @@ -219,10 +219,6 @@ impl WalletsContent { ..Default::default() }) .show_inside(ui, |ui| { - // Do not draw content when list is hidden. - if list_hidden { - return; - } // Show list of wallets. self.wallet_list_ui(ui, dual_panel, cb); }); @@ -336,7 +332,7 @@ impl WalletsContent { ui.style_mut().visuals.widgets.hovered.bg_fill = Colors::STROKE; // Draw list of wallets. - let scroll = ScrollArea::vertical() + ScrollArea::vertical() .id_source("wallet_list") .auto_shrink([false; 2]) .show(ui, |ui| { diff --git a/src/gui/views/wallets/wallet/content.rs b/src/gui/views/wallets/wallet/content.rs index b97fa27..c6ed10a 100644 --- a/src/gui/views/wallets/wallet/content.rs +++ b/src/gui/views/wallets/wallet/content.rs @@ -20,11 +20,11 @@ use grin_core::core::amount_to_hr_string; use crate::AppConfig; use crate::gui::Colors; -use crate::gui::icons::{CHECK, CHECK_FAT, DOWNLOAD, FILE_ARCHIVE, GEAR_FINE, LIST, PACKAGE, PLUS, POWER, REPEAT, UPLOAD, WALLET}; +use crate::gui::icons::{BRIDGE, CHAT_CIRCLE_TEXT, CHECK, CHECK_FAT, FILE_ARCHIVE, GEAR_FINE, LIST, PACKAGE, PLUS, POWER, REPEAT, WALLET}; use crate::gui::platform::PlatformCallbacks; use crate::gui::views::{Modal, Root, View}; use crate::gui::views::types::{ModalPosition, TextEditOptions}; -use crate::gui::views::wallets::{WalletInfo, WalletReceive, WalletSend, WalletSettings}; +use crate::gui::views::wallets::{WalletInfo, WalletMessages, WalletTransport, WalletSettings}; use crate::gui::views::wallets::types::{GRIN, WalletTab, WalletTabType}; use crate::node::Node; use crate::wallet::{Wallet, WalletConfig}; @@ -351,18 +351,18 @@ impl WalletContent { let current_type = self.current_tab.get_type(); ui.columns(4, |columns| { columns[0].vertical_centered_justified(|ui| { - View::tab_button(ui, WALLET, current_type == WalletTabType::Info, || { + View::tab_button(ui, WALLET, current_type == WalletTabType::Txs, || { self.current_tab = Box::new(WalletInfo::default()); }); }); columns[1].vertical_centered_justified(|ui| { - View::tab_button(ui, DOWNLOAD, current_type == WalletTabType::Receive, || { - self.current_tab = Box::new(WalletReceive::default()); + View::tab_button(ui, CHAT_CIRCLE_TEXT, current_type == WalletTabType::Messages, || { + self.current_tab = Box::new(WalletMessages::default()); }); }); columns[2].vertical_centered_justified(|ui| { - View::tab_button(ui, UPLOAD, current_type == WalletTabType::Send, || { - self.current_tab = Box::new(WalletSend::default()); + View::tab_button(ui, BRIDGE, current_type == WalletTabType::Transport, || { + self.current_tab = Box::new(WalletTransport::default()); }); }); columns[3].vertical_centered_justified(|ui| { diff --git a/src/gui/views/wallets/wallet/receive.rs b/src/gui/views/wallets/wallet/messages.rs similarity index 51% rename from src/gui/views/wallets/wallet/receive.rs rename to src/gui/views/wallets/wallet/messages.rs index 48dd3ed..b2df37d 100644 --- a/src/gui/views/wallets/wallet/receive.rs +++ b/src/gui/views/wallets/wallet/messages.rs @@ -15,9 +15,10 @@ use egui::{Id, Margin, RichText, ScrollArea}; use egui::scroll_area::ScrollBarVisibility; use grin_core::core::{amount_from_hr_string, amount_to_hr_string}; +use grin_wallet_libwallet::{Slate, SlateState, TxLogEntry}; use crate::gui::Colors; -use crate::gui::icons::{BROOM, CLIPBOARD_TEXT, COPY, HAND_COINS, RECEIPT}; +use crate::gui::icons::{BROOM, CLIPBOARD_TEXT, COPY, DOWNLOAD, UPLOAD}; use crate::gui::platform::PlatformCallbacks; use crate::gui::views::{Modal, Root, View}; use crate::gui::views::types::{ModalPosition, TextEditOptions}; @@ -25,52 +26,58 @@ use crate::gui::views::wallets::wallet::types::{SLATEPACK_MESSAGE_HINT, WalletTa use crate::gui::views::wallets::wallet::WalletContent; use crate::wallet::Wallet; -/// Receiving tab content. -pub struct WalletReceive { - /// Flag to check if there is invoice transaction type. - is_invoice: bool, +/// Slatepacks messages interaction tab content. +pub struct WalletMessages { + /// Flag to check if send or receive request was opened. + send_request: bool, - /// Slatepack message from sender to create response message. + /// Slatepack message to create response message. message_edit: String, - /// Generated Slatepack response message for sender. + /// Parsed Slatepack message. + message_slate: Option, + /// Flag to check if there is an error happened on response creation. + parse_error: bool, + /// Generated Slatepack response message. response_edit: String, /// Flag to check if there is an error happened on response creation. response_error: bool, + /// Flag to check if there is an error happened on transaction finalization. + finalize_error: bool, + /// Flag to check if Dandelion is needed to finalize transaction. + use_dandelion: Option, - /// Amount to receive for invoice transaction type. + /// Amount to send or receive. amount_edit: String, - /// Generated Slatepack message for invoice transaction. + /// Generated Slatepack message as request to send or receive funds. request_edit: String, /// Flag to check if there is an error happened on invoice creation. request_error: bool, - /// Slatepack message from sender to finalize transaction. - finalization_edit: String, - /// Flag to check if there is an error happened on transaction finalization. - finalization_error: bool, } /// Identifier for invoice amount [`Modal`]. -const INVOICE_AMOUNT_MODAL: &'static str = "invoice_amount_modal"; +const AMOUNT_MODAL: &'static str = "amount_modal"; -impl Default for WalletReceive { +impl Default for WalletMessages { fn default() -> Self { Self { - is_invoice: false, + send_request: false, message_edit: "".to_string(), + message_slate: None, + parse_error: false, response_edit: "".to_string(), response_error: false, + finalize_error: false, + use_dandelion: None, amount_edit: "".to_string(), request_edit: "".to_string(), request_error: false, - finalization_edit: "".to_string(), - finalization_error: false, } } } -impl WalletTab for WalletReceive { +impl WalletTab for WalletMessages { fn get_type(&self) -> WalletTabType { - WalletTabType::Receive + WalletTabType::Messages } fn ui(&mut self, @@ -85,7 +92,7 @@ impl WalletTab for WalletReceive { // Show modal content for this ui container. self.modal_content_ui(ui, wallet, cb); - // Show receiving content panel. + // Show manual wallet content panel. egui::CentralPanel::default() .frame(egui::Frame { stroke: View::ITEM_STROKE, @@ -101,12 +108,12 @@ impl WalletTab for WalletReceive { .show_inside(ui, |ui| { ScrollArea::vertical() .scroll_bar_visibility(ScrollBarVisibility::AlwaysVisible) - .id_source(Id::from("wallet_receive").with(wallet.get_config().id)) + .id_source(Id::from("wallet_manual").with(wallet.get_config().id)) .auto_shrink([false; 2]) .show(ui, |ui| { ui.vertical_centered(|ui| { View::max_width_ui(ui, Root::SIDE_PANEL_WIDTH * 1.3, |ui| { - self.receive_ui(ui, wallet, cb); + self.ui(ui, wallet, cb); }); }); }); @@ -114,18 +121,25 @@ impl WalletTab for WalletReceive { } } -impl WalletReceive { - /// Draw receiving content. - pub fn receive_ui(&mut self, - ui: &mut egui::Ui, - wallet: &mut Wallet, - cb: &dyn PlatformCallbacks) { - ui.add_space(2.0); - View::sub_title(ui, format!("{} {}", HAND_COINS, t!("wallets.manually"))); +impl WalletMessages { + /// Draw manual wallet transaction interaction content. + pub fn ui(&mut self, + ui: &mut egui::Ui, + wallet: &mut Wallet, + cb: &dyn PlatformCallbacks) { + ui.add_space(4.0); + + // Show creation of request to send or receive funds. + self.request_ui(ui, cb); + + ui.add_space(12.0); View::horizontal_line(ui, Colors::ITEM_STROKE); - ui.add_space(3.0); - // Show manual receiving content. - self.manual_ui(ui, wallet, cb); + ui.add_space(8.0); + + // Show Slatepack message input field. + self.input_slatepack_ui(ui, wallet, cb); + + ui.add_space(6.0); } /// Draw [`Modal`] content for this ui container. @@ -137,9 +151,9 @@ impl WalletReceive { None => {} Some(id) => { match id { - INVOICE_AMOUNT_MODAL => { + AMOUNT_MODAL => { Modal::ui(ui.ctx(), |ui, modal| { - self.invoice_amount_modal(ui, wallet, modal, cb); + self.amount_modal_ui(ui, wallet, modal, cb); }); } _ => {} @@ -148,73 +162,67 @@ impl WalletReceive { } } - /// Draw manual receiving content. - fn manual_ui(&mut self, ui: &mut egui::Ui, wallet: &mut Wallet, cb: &dyn PlatformCallbacks) { - ui.add_space(10.0); - ui.columns(2, |columns| { - let mut is_invoice = self.is_invoice; - columns[0].vertical_centered(|ui| { - View::radio_value(ui, &mut is_invoice, false, t!("wallets.receive")); - }); - columns[1].vertical_centered(|ui| { - View::radio_value(ui, &mut is_invoice, true, t!("wallets.invoice")); - }); - if is_invoice != self.is_invoice { - self.is_invoice = is_invoice; - // Reset fields to default values on mode change. - if is_invoice { - self.amount_edit = "".to_string(); - self.request_edit = "".to_string(); - self.request_error = false; - self.finalization_edit = "".to_string(); - self.finalization_error = false; - } else { - self.message_edit = "".to_string(); - self.response_edit = "".to_string(); - self.response_error = false; - } - } - }); - ui.add_space(10.0); - - if self.is_invoice { - // Show invoice creation content. - self.manual_invoice_ui(ui, wallet, cb); - } else { - // Show manual transaction receiving content. - self.manual_receive_ui(ui, wallet, cb); - } - } - - /// Draw manual receiving content. - fn manual_receive_ui(&mut self, - ui: &mut egui::Ui, - wallet: &mut Wallet, - cb: &dyn PlatformCallbacks) { + /// Draw Slatepack message input content. + fn input_slatepack_ui(&mut self, + ui: &mut egui::Ui, + wallet: &mut Wallet, + cb: &dyn PlatformCallbacks) { // Setup description. let response_empty = self.response_edit.is_empty(); - - if self.response_error { - ui.label(RichText::new(t!("wallets.receive_slatepack_err")) + if self.parse_error { + ui.label(RichText::new(t!("wallets.parse_slatepack_err")) + .size(16.0) + .color(Colors::RED)); + } else if self.response_error { + ui.label(RichText::new(t!("wallets.response_slatepack_err")) + .size(16.0) + .color(Colors::RED)); + } else if self.finalize_error { + ui.label(RichText::new(t!("wallets.finalize_slatepack_err")) .size(16.0) .color(Colors::RED)); } else { - let desc_text = if response_empty { - t!("wallets.receive_slatepack_desc") + let desc_text = if response_empty && self.message_slate.is_none() { + t!("wallets.input_slatepack_desc") } else { - t!("wallets.receive_send_slatepack") + let slate = self.message_slate.as_ref().unwrap(); + let amount = amount_to_hr_string(slate.amount, true); + match slate.state { + SlateState::Standard1 => { + t!("wallets.parse_s1_slatepack_desc","amount" => amount) + } + SlateState::Standard2 => { + t!("wallets.parse_s2_slatepack_desc","amount" => amount) + } + SlateState::Standard3 => {t!("wallets.input_slatepack_desc")} + SlateState::Invoice1 => { + let a_f = u64::from(slate.fee_fields) + slate.amount; + let a = amount_to_hr_string(a_f, true); + t!("wallets.parse_i1_slatepack_desc","amount" => a) + } + SlateState::Invoice2 => { + t!("wallets.parse_i2_slatepack_desc","amount" => amount) + } + SlateState::Invoice3 => {t!("wallets.input_slatepack_desc")} + _ => { + t!("wallets.input_slatepack_desc") + } + } }; ui.label(RichText::new(desc_text).size(16.0).color(Colors::INACTIVE_TEXT)); } - ui.add_space(6.0); + ui.add_space(7.0); // Setup Slatepack message text input. - let message = if response_empty { + let mut message = if response_empty { &mut self.message_edit } else { &mut self.response_edit }; + // Save message to check for changes. + let message_before = message.clone(); + View::horizontal_line(ui, Colors::ITEM_STROKE); ui.add_space(3.0); ScrollArea::vertical() @@ -223,7 +231,6 @@ impl WalletReceive { .auto_shrink([false; 2]) .show(ui, |ui| { ui.add_space(7.0); - let message_before = message.clone(); egui::TextEdit::multiline(message) .font(egui::TextStyle::Small) .desired_rows(5) @@ -231,10 +238,6 @@ impl WalletReceive { .hint_text(SLATEPACK_MESSAGE_HINT) .desired_width(f32::INFINITY) .show(ui); - // Clear an error when message changed. - if &message_before != message { - self.response_error = false; - } ui.add_space(6.0); }); ui.add_space(2.0); @@ -242,26 +245,21 @@ impl WalletReceive { ui.add_space(10.0); // Draw buttons to clear/copy/paste. - let field_is_empty = self.message_edit.is_empty() && self.response_edit.is_empty(); - let columns_num = if !field_is_empty { 2 } else { 1 }; + let fields_empty = self.message_edit.is_empty() && self.response_edit.is_empty(); + let columns_num = if fields_empty { 1 } else { 2 }; + let mut show_dandelion = false; ui.scope(|ui| { // Setup spacing between buttons. ui.spacing_mut().item_spacing = egui::Vec2::new(8.0, 0.0); ui.columns(columns_num, |columns| { let first_column_content = |ui: &mut egui::Ui| { - if !self.response_edit.is_empty() && !self.response_error { - let clear_text = format!("{} {}", BROOM, t!("clear")); - View::button(ui, clear_text, Colors::BUTTON, || { - self.response_error = false; - self.message_edit.clear(); - self.response_edit.clear(); - }); + if self.message_slate.is_some() && !self.response_error && !self.parse_error { + self.clear_message_button_ui(ui); } else { let paste_text = format!("{} {}", CLIPBOARD_TEXT, t!("paste")); View::button(ui, paste_text, Colors::BUTTON, || { self.message_edit = cb.get_string_from_buffer(); - self.response_error = false; }); } }; @@ -270,30 +268,25 @@ impl WalletReceive { } else { columns[0].vertical_centered_justified(first_column_content); columns[1].vertical_centered_justified(|ui| { - if self.response_error { - let clear_text = format!("{} {}", BROOM, t!("clear")); - View::button(ui, clear_text, Colors::BUTTON, || { - self.response_error = false; - self.message_edit.clear(); - self.response_edit.clear(); - }); + if self.finalize_error || self.response_error || self.parse_error { + self.clear_message_button_ui(ui); } else if !self.response_edit.is_empty() { let copy_text = format!("{} {}", COPY, t!("copy")); View::button(ui, copy_text, Colors::BUTTON, || { cb.copy_string_to_buffer(self.response_edit.clone()); }); } else { - View::button(ui, t!("wallets.create_response"), Colors::GOLD, || { - match wallet.receive(self.message_edit.clone()) { - Ok(response) => { - self.response_edit = response.trim().to_string(); + show_dandelion = true; + View::button(ui, t!("wallets.finalize"), Colors::GOLD, || { + let message = self.message_edit.clone(); + match wallet.finalize(message, self.use_dandelion.unwrap()) { + Ok(_) => { self.message_edit.clear(); - cb.copy_string_to_buffer(response); + self.message_slate = None; }, Err(e) => { - wallet.sync(); println!("error {}", e); - self.response_error = true + self.finalize_error = true } } }); @@ -302,108 +295,171 @@ impl WalletReceive { } }); }); + + // Draw setup of ability to post transaction with Dandelion. + if show_dandelion { + if self.use_dandelion.is_none() { + self.use_dandelion = if let Some(u) = wallet.get_config().use_dandelion { + Some(u) + } else { + Some(true) + }; + } + let use_dandelion = self.use_dandelion.unwrap(); + View::checkbox(ui, use_dandelion, t!("wallets.use_dandelion"), || { + self.use_dandelion = Some(!use_dandelion); + wallet.update_use_dandelion(use_dandelion); + }); + } + + // Parse Slatepack message if input field was changed to setup response input. + message = if response_empty { + &mut self.message_edit + } else { + &mut self.response_edit + }; + if &message_before != message { + if message.is_empty() { + self.message_slate = None; + } + + self.response_error = false; + self.parse_error = false; + if !self.message_edit.is_empty() { + match wallet.parse_slatepack(self.message_edit.clone()) { + Ok(mut slate) => { + // Try to get amount from transaction by id. + if slate.amount == 0 { + let _ = wallet.get_data().unwrap().txs.clone().iter().map(|tx| { + if tx.tx_slate_id == Some(slate.id) { + slate.amount = if tx.amount_debited > tx.amount_credited { + tx.amount_debited - tx.amount_credited + } else { + tx.amount_credited - tx.amount_debited + } + } + tx + }).collect::>(); + } + println!("SLATE: {}", slate); + self.message_slate = Some(slate.clone()); + match slate.state { + SlateState::Unknown => {} + SlateState::Standard1 => { + match wallet.receive(self.message_edit.clone()) { + Ok(resp) => { + self.response_edit = resp; + } + Err(_) => { + self.response_error = true; + } + } + } + SlateState::Standard2 => {} + SlateState::Standard3 => {} + SlateState::Invoice1 => { + match wallet.pay(self.message_edit.clone()) { + Ok(resp) => { + self.response_edit = resp; + } + Err(_) => { + self.response_error = true; + } + } + } + SlateState::Invoice2 => { + + } + SlateState::Invoice3 => {} + } + } + Err(_) => { + self.message_slate = None; + self.parse_error = true; + } + } + } + } } - /// Draw invoice creation content. - fn manual_invoice_ui(&mut self, - ui: &mut egui::Ui, - wallet: &mut Wallet, - cb: &dyn PlatformCallbacks) { - ui.label(RichText::new(t!("wallets.issue_invoice_desc")) - .size(16.0) - .color(Colors::INACTIVE_TEXT)); - ui.add_space(6.0); - - // Draw invoice creation button. - let invoice_text = format!("{} {}", RECEIPT, t!("wallets.issue_invoice")); - View::button(ui, invoice_text, Colors::BUTTON, || { - // Reset modal values. - self.amount_edit = "".to_string(); - self.request_error = false; - // Show invoice amount modal. - Modal::new(INVOICE_AMOUNT_MODAL) - .position(ModalPosition::CenterTop) - .title(t!("wallets.issue_invoice")) - .show(); - cb.show_keyboard(); + /// Draw button to clear entered message, slate and errors. + fn clear_message_button_ui(&mut self, ui: &mut egui::Ui) { + let clear_text = format!("{} {}", BROOM, t!("clear")); + View::button(ui, clear_text, Colors::BUTTON, || { + self.response_error = false; + self.parse_error = false; + self.finalize_error = false; + self.message_edit.clear(); + self.response_edit.clear(); + self.message_slate = None; }); + } - ui.add_space(12.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); - ui.add_space(6.0); - ui.label(RichText::new(t!("wallets.receive_slatepack_desc")) + /// Draw creation of request to send or receive funds. + fn request_ui(&mut self, + ui: &mut egui::Ui, + cb: &dyn PlatformCallbacks) { + ui.label(RichText::new(t!("wallets.create_request_desc")) .size(16.0) .color(Colors::INACTIVE_TEXT)); - ui.add_space(6.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); - ui.add_space(3.0); + ui.add_space(7.0); - // Draw invoice finalization text input. - ScrollArea::vertical() - .max_height(128.0) - .id_source(Id::from("receive_input").with(wallet.get_config().id)) - .auto_shrink([false; 2]) - .show(ui, |ui| { - ui.add_space(7.0); - let finalization_before = self.finalization_edit.clone(); - egui::TextEdit::multiline(&mut self.finalization_edit) - .font(egui::TextStyle::Small) - .desired_rows(5) - .interactive(true) - .hint_text(SLATEPACK_MESSAGE_HINT) - .desired_width(f32::INFINITY) - .show(ui); - // Clear an error when message changed. - if finalization_before != self.finalization_edit { - self.finalization_error = false; - } - ui.add_space(6.0); - }); - ui.add_space(2.0); - View::horizontal_line(ui, Colors::ITEM_STROKE); - ui.add_space(10.0); + // Setup spacing between buttons. + ui.spacing_mut().item_spacing = egui::Vec2::new(8.0, 0.0); - // Draw buttons to clear/paste. - ui.scope(|ui| { - // Setup spacing between buttons. - ui.spacing_mut().item_spacing = egui::Vec2::new(8.0, 0.0); - - ui.columns(2, |columns| { - columns[0].vertical_centered_justified(|ui| { - let paste_text = format!("{} {}", CLIPBOARD_TEXT, t!("paste")); - View::button(ui, paste_text, Colors::BUTTON, || { - self.finalization_edit = cb.get_string_from_buffer(); - self.response_error = false; - }); + ui.columns(2, |columns| { + columns[0].vertical_centered_justified(|ui| { + // Draw send request creation button. + let send_text = format!("{} {}", UPLOAD, t!("wallets.send")); + View::button(ui, send_text.clone(), Colors::BUTTON, || { + // Setup modal values. + self.send_request = true; + self.amount_edit = "".to_string(); + self.request_error = false; + // Show send amount modal. + Modal::new(AMOUNT_MODAL) + .position(ModalPosition::CenterTop) + .title(t!("wallets.send")) + .show(); + cb.show_keyboard(); }); - columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("wallets.finalize"), Colors::GOLD, || { - wallet.finalize(); - //TODO: finalize - }); + }); + columns[1].vertical_centered_justified(|ui| { + // Draw invoice request creation button. + let receive_text = format!("{} {}", DOWNLOAD, t!("wallets.receive")); + View::button(ui, receive_text.clone(), Colors::BUTTON, || { + // Setup modal values. + self.send_request = false; + self.amount_edit = "".to_string(); + self.request_error = false; + // Show receive amount modal. + Modal::new(AMOUNT_MODAL) + .position(ModalPosition::CenterTop) + .title(t!("wallets.receive")) + .show(); + cb.show_keyboard(); }); }); }); - - if self.finalization_error { - ui.add_space(8.0); - ui.label(RichText::new(t!("wallets.finalize_slatepack_err")) - .size(16.0) - .color(Colors::RED)); - } - ui.add_space(8.0); } /// Draw invoice amount [`Modal`] content. - fn invoice_amount_modal(&mut self, - ui: &mut egui::Ui, - wallet: &mut Wallet, - modal: &Modal, - cb: &dyn PlatformCallbacks) { + fn amount_modal_ui(&mut self, + ui: &mut egui::Ui, + wallet: &mut Wallet, + modal: &Modal, + cb: &dyn PlatformCallbacks) { ui.add_space(6.0); if self.request_edit.is_empty() { ui.vertical_centered(|ui| { - ui.label(RichText::new(t!("wallets.enter_amount")) + let enter_text = if self.send_request { + let data = wallet.get_data().unwrap(); + let amount = amount_to_hr_string(data.info.amount_currently_spendable, true); + t!("wallets.enter_amount_send","amount" => amount) + } else { + t!("wallets.enter_amount_receive") + }; + ui.label(RichText::new(enter_text) .size(17.0) .color(Colors::GRAY)); }); @@ -447,10 +503,16 @@ impl WalletReceive { }); }); columns[1].vertical_centered_justified(|ui| { + // Button to create Slatepack message for request. View::button(ui, t!("continue"), Colors::WHITE, || { match amount_from_hr_string(self.amount_edit.as_str()) { Ok(amount) => { - match wallet.issue_invoice(amount) { + let message = if self.send_request { + wallet.send(amount) + } else { + wallet.issue_invoice(amount) + }; + match message { Ok(message) => { self.request_edit = message; cb.hide_keyboard(); @@ -473,16 +535,25 @@ impl WalletReceive { ui.vertical_centered(|ui| { let amount = amount_from_hr_string(self.amount_edit.as_str()).unwrap(); let amount_format = amount_to_hr_string(amount, true); - let desc_text = t!("wallets.invoice_desc","amount" => amount_format); + let desc_text = if self.send_request { + t!("wallets.send_request_desc","amount" => amount_format) + } else { + t!("wallets.invoice_desc","amount" => amount_format) + }; ui.label(RichText::new(desc_text).size(16.0).color(Colors::INACTIVE_TEXT)); ui.add_space(6.0); View::horizontal_line(ui, Colors::ITEM_STROKE); ui.add_space(3.0); - // Draw invoice request text. + // Draw output Slatepack message text. + let input_id = if self.send_request { + Id::from("send_request_output").with(wallet.get_config().id) + } else { + Id::from("receive_request_output").with(wallet.get_config().id) + }; ScrollArea::vertical() .max_height(128.0) - .id_source(Id::from("receive_input").with(wallet.get_config().id)) + .id_source(input_id) .auto_shrink([false; 2]) .show(ui, |ui| { ui.add_space(7.0); diff --git a/src/gui/views/wallets/wallet/mod.rs b/src/gui/views/wallets/wallet/mod.rs index 3251c69..6db373d 100644 --- a/src/gui/views/wallets/wallet/mod.rs +++ b/src/gui/views/wallets/wallet/mod.rs @@ -14,14 +14,14 @@ pub mod types; -mod info; -pub use info::WalletInfo; +mod txs; +pub use txs::WalletInfo; -mod receive; -pub use receive::WalletReceive; +mod messages; +pub use messages::WalletMessages; -mod send; -pub use send::WalletSend; +mod transport; +pub use transport::WalletTransport; mod settings; pub use settings::WalletSettings; diff --git a/src/gui/views/wallets/wallet/send.rs b/src/gui/views/wallets/wallet/transport.rs similarity index 84% rename from src/gui/views/wallets/wallet/send.rs rename to src/gui/views/wallets/wallet/transport.rs index 4c47bae..53f2adf 100644 --- a/src/gui/views/wallets/wallet/send.rs +++ b/src/gui/views/wallets/wallet/transport.rs @@ -22,11 +22,11 @@ use crate::wallet::Wallet; /// Sending tab content. #[derive(Default)] -pub struct WalletSend; +pub struct WalletTransport; -impl WalletTab for WalletSend { +impl WalletTab for WalletTransport { fn get_type(&self) -> WalletTabType { - WalletTabType::Send + WalletTabType::Transport } fn ui(&mut self, @@ -38,7 +38,7 @@ impl WalletTab for WalletSend { return; } - // Show sending content panel. + // Show transport content panel. egui::CentralPanel::default() .frame(egui::Frame { stroke: View::ITEM_STROKE, @@ -52,14 +52,14 @@ impl WalletTab for WalletSend { ..Default::default() }) .show_inside(ui, |ui| { - self.send_ui(ui, wallet); + self.transport_ui(ui, wallet); }); } } -impl WalletSend { - /// Draw sending content. - pub fn send_ui(&self, ui: &mut egui::Ui, wallet: &mut Wallet) { +impl WalletTransport { + /// Draw transport content. + pub fn transport_ui(&self, ui: &mut egui::Ui, wallet: &mut Wallet) { } } \ No newline at end of file diff --git a/src/gui/views/wallets/wallet/info.rs b/src/gui/views/wallets/wallet/txs.rs similarity index 96% rename from src/gui/views/wallets/wallet/info.rs rename to src/gui/views/wallets/wallet/txs.rs index c43af07..4e1847c 100644 --- a/src/gui/views/wallets/wallet/info.rs +++ b/src/gui/views/wallets/wallet/txs.rs @@ -32,7 +32,7 @@ pub struct WalletInfo; impl WalletTab for WalletInfo { fn get_type(&self) -> WalletTabType { - WalletTabType::Info + WalletTabType::Txs } fn ui(&mut self, @@ -203,11 +203,12 @@ fn tx_item_ui(ui: &mut egui::Ui, ui.vertical(|ui| { // Setup transaction amount. ui.add_space(3.0); - let amount = amount_to_hr_string(tx.amount_credited - tx.amount_debited, true); let amount_text = if tx.amount_credited > tx.amount_debited { - format!("+{}", amount) + format!("+{}", + amount_to_hr_string(tx.amount_credited - tx.amount_debited, true)) } else { - amount + format!("-{}", + amount_to_hr_string(tx.amount_debited - tx.amount_credited, true)) }; // Setup amount color. @@ -254,17 +255,17 @@ fn tx_item_ui(ui: &mut egui::Ui, } else { format!("{} {}", DOTS_THREE_CIRCLE, - t!("wallets.tx_awaiting_conf")) + t!("wallets.tx_confirming")) } }, TxLogEntryType::TxSent => { if last_height - tx_height > min_confirmations { - format!("{} {}", ARROW_CIRCLE_DOWN, t!("wallets.tx_sent")) + format!("{} {}", ARROW_CIRCLE_UP, t!("wallets.tx_sent")) } else { format!("{} {}", DOTS_THREE_CIRCLE, t!("wallets.tx_confirming")) } }, - _ => format!("{} {}", ARROW_CIRCLE_UP, t!("wallets.canceled")) + _ => format!("{} {}", X_CIRCLE, t!("wallets.canceled")) } }; diff --git a/src/gui/views/wallets/wallet/types.rs b/src/gui/views/wallets/wallet/types.rs index 751eee8..d94d6be 100644 --- a/src/gui/views/wallets/wallet/types.rs +++ b/src/gui/views/wallets/wallet/types.rs @@ -33,9 +33,9 @@ pub trait WalletTab { /// Type of [`WalletTab`] content. #[derive(PartialEq)] pub enum WalletTabType { - Info, - Receive, - Send, + Txs, + Messages, + Transport, Settings } @@ -43,9 +43,9 @@ impl WalletTabType { /// Name of wallet tab to show at ui. pub fn name(&self) -> String { match *self { - WalletTabType::Info => t!("wallets.wallet"), - WalletTabType::Receive => t!("wallets.receive"), - WalletTabType::Send => t!("wallets.send"), + WalletTabType::Txs => t!("wallets.txs"), + WalletTabType::Messages => t!("wallets.messages"), + WalletTabType::Transport => t!("wallets.transport"), WalletTabType::Settings => t!("wallets.settings") } } diff --git a/src/lib.rs b/src/lib.rs index dad94d5..7a5205d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -214,6 +214,6 @@ fn setup_i18n() { locale.as_str() }; if _rust_i18n_available_locales().contains(&locale_str) { - rust_i18n::set_locale(locale_str); + rust_i18n::set_locale(DEFAULT_LOCALE); } } \ No newline at end of file diff --git a/src/wallet/config.rs b/src/wallet/config.rs index 63258ba..a1c9b05 100644 --- a/src/wallet/config.rs +++ b/src/wallet/config.rs @@ -36,7 +36,9 @@ pub struct WalletConfig { /// External connection identifier. pub ext_conn_id: Option, /// Minimal amount of confirmations. - pub min_confirmations: u64 + pub min_confirmations: u64, + /// Flag to use Dandelion to broadcast transactions. + pub use_dandelion: Option } /// Base wallets directory name. @@ -69,7 +71,8 @@ impl WalletConfig { ConnectionMethod::Integrated => None, ConnectionMethod::External(id) => Some(*id) }, - min_confirmations: MIN_CONFIRMATIONS_DEFAULT + min_confirmations: MIN_CONFIRMATIONS_DEFAULT, + use_dandelion: Some(true), }; Settings::write_to_file(&config, config_path); config diff --git a/src/wallet/wallet.rs b/src/wallet/wallet.rs index c1a4131..c7088f4 100644 --- a/src/wallet/wallet.rs +++ b/src/wallet/wallet.rs @@ -22,8 +22,8 @@ use std::sync::{Arc, mpsc, RwLock}; use std::sync::atomic::{AtomicBool, AtomicI64, AtomicU8, Ordering}; use std::thread::Thread; use std::time::Duration; - use futures::channel::oneshot; + use grin_api::{ApiServer, Router}; use grin_chain::SyncStatus; use grin_core::global; @@ -35,7 +35,7 @@ use grin_wallet_controller::command::parse_slatepack; use grin_wallet_controller::controller; use grin_wallet_controller::controller::ForeignAPIHandlerV2; use grin_wallet_impls::{DefaultLCProvider, DefaultWalletImpl, HTTPNodeClient}; -use grin_wallet_libwallet::{Error, InitTxArgs, IssueInvoiceTxArgs, NodeClient, RetrieveTxQueryArgs, Slate, StatusMessage, TxLogEntry, TxLogEntryType, WalletInst, WalletLCProvider}; +use grin_wallet_libwallet::{Error, InitTxArgs, IssueInvoiceTxArgs, NodeClient, Slate, SlatepackAddress, StatusMessage, TxLogEntry, TxLogEntryType, WalletInst, WalletLCProvider}; use grin_wallet_libwallet::api_impl::owner::{cancel_tx, retrieve_summary_info, retrieve_txs}; use crate::node::{Node, NodeConfig}; @@ -226,6 +226,13 @@ impl Wallet { w_config.save(); } + /// Update usage of Dandelion to broadcast 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); + w_config.save(); + } + /// Update minimal amount of confirmations. pub fn update_min_confirmations(&self, min_confirmations: u64) { let mut w_config = self.config.write().unwrap(); @@ -460,6 +467,19 @@ impl Wallet { } } + /// Parse Slatepack message into [`Slate`]. + pub fn parse_slatepack(&self, message: String) -> Result { + let mut api = Owner::new(self.instance.clone().unwrap(), None); + return match parse_slatepack(&mut api, None, None, Some(message.clone())) { + Ok((slate, _)) => { + Ok(slate) + } + Err(_) => { + Err(Error::SlatepackDeser("Slatepack parse error".to_string())) + } + } + } + /// Create Slatepack message from provided slate. fn create_slatepack_message(&self, slate: Slate) -> Result { let mut message = "".to_string(); @@ -481,60 +501,33 @@ impl Wallet { Ok(message) } - /// Receive transaction via Slatepack message, return response to sender. - pub fn receive(&self, message: String) -> Result { + /// Initialize a transaction to send amount, return request for funds receiver. + pub fn send(&self, amount: u64) -> Result { + let config = self.get_config(); + let args = InitTxArgs { + src_acct_name: Some(config.account), + amount, + minimum_confirmations: config.min_confirmations, + num_change_outputs: 1, + selection_strategy_is_use_all: false, + ..Default::default() + }; let mut api = Owner::new(self.instance.clone().unwrap(), None); - match parse_slatepack(&mut api, None, None, Some(message.clone())) { - Ok((mut slate, _)) => { - let config = self.get_config(); - controller::foreign_single_use(api.wallet_inst.clone(), None, |api| { - slate = api.receive_tx(&slate, Some(config.account.as_str()), None)?; - Ok(()) - })?; - // Create Slatepack message response. - let response = self.create_slatepack_message(slate)?; + let slate = api.init_send_tx(None, args)?; - // Sync wallet info. - self.sync(); - Ok(response) - } - Err(_) => { - Err(Error::GenericError("Parsing error".to_string())) - } - } + // Lock outputs to for this transaction. + api.tx_lock_outputs(None, &slate)?; + + // Create Slatepack message response. + let response = self.create_slatepack_message(slate)?; + + // Sync wallet info. + self.sync(); + + Ok(response) } - /// S transaction via Slatepack message and return response to sender. - pub fn pay(&self, message: String) -> Result { - let mut api = Owner::new(self.instance.clone().unwrap(), None); - match parse_slatepack(&mut api, None, None, Some(message.clone())) { - Ok((mut slate, _)) => { - let config = self.get_config(); - let args = InitTxArgs { - src_acct_name: None, - amount: slate.amount, - minimum_confirmations: config.min_confirmations, - selection_strategy_is_use_all: false, - ..Default::default() - }; - let mut api = Owner::new(self.instance.clone().unwrap(), None); - let slate = api.process_invoice_tx(None, &slate, args)?; - - // Create Slatepack message response. - let response = self.create_slatepack_message(slate)?; - - // Sync wallet info. - self.sync(); - - Ok(response) - } - Err(_) => { - Err(Error::GenericError("Parsing error".to_string())) - } - } - } - - /// Initialize an invoice transaction. + /// Initialize an invoice transaction to receive amount, return request for funds sender. pub fn issue_invoice(&self, amount: u64) -> Result { let args = IssueInvoiceTxArgs { dest_acct_name: None, @@ -553,8 +546,57 @@ impl Wallet { Ok(response) } - pub fn send(&self) { + /// Handle message from the invoice issuer to send founds, return response for funds receiver. + pub fn pay(&self, message: String) -> Result { + let slate = self.parse_slatepack(message)?; + let config = self.get_config(); + let args = InitTxArgs { + src_acct_name: None, + amount: slate.amount, + minimum_confirmations: config.min_confirmations, + selection_strategy_is_use_all: false, + ..Default::default() + }; + let mut api = Owner::new(self.instance.clone().unwrap(), None); + let slate = api.process_invoice_tx(None, &slate, args)?; + api.tx_lock_outputs(None, &slate)?; + // Create Slatepack message response. + let response = self.create_slatepack_message(slate)?; + + // Sync wallet info. + self.sync(); + + Ok(response) + } + + /// Handle message to receive funds, return response to sender. + pub fn receive(&self, message: String) -> Result { + let mut slate = self.parse_slatepack(message)?; + let mut api = Owner::new(self.instance.clone().unwrap(), None); + controller::foreign_single_use(api.wallet_inst.clone(), None, |api| { + slate = api.receive_tx(&slate, Some(self.get_config().account.as_str()), None)?; + Ok(()) + })?; + // Create Slatepack message response. + let response = self.create_slatepack_message(slate)?; + + // Sync wallet info. + self.sync(); + + Ok(response) + } + + /// Finalize transaction from provided message as sender or invoice issuer with Dandelion. + pub fn finalize(&self, message: String, dandelion: bool) -> Result { + let mut slate = self.parse_slatepack(message)?; + let mut api = Owner::new(self.instance.clone().unwrap(), None); + slate = api.finalize_tx(None, &slate)?; + api.post_tx(None, &slate, dandelion)?; + // Sync wallet info. + self.sync(); + + Ok(slate) } /// Cancel transaction. @@ -581,11 +623,6 @@ impl Wallet { cancelling_r.contains(id) } - /// Finalize transaction from provided Slatepack message. - pub fn finalize(&self) { - - } - /// Change wallet password. pub fn change_password(&self, old: String, new: String) -> Result<(), Error> { let instance = self.instance.clone().unwrap(); @@ -889,6 +926,7 @@ fn sync_wallet_data(wallet: &Wallet) { }).collect::>(); // Update txs statuses. for tx in &txs { + println!("{}", serde_json::to_string(tx).unwrap()); if tx.tx_type == TxLogEntryType::TxSentCancelled || tx.tx_type == TxLogEntryType::TxReceivedCancelled { // Remove cancelling status. @@ -903,15 +941,11 @@ fn sync_wallet_data(wallet: &Wallet) { return; } } - Err(e) => { - println!("error on retrieve_txs {}", e); - } + Err(e) => println!("error on retrieve_txs {}", e), } } } - Err(e) => { - println!("error on retrieve_summary_info {}", e); - } + Err(e) => println!("error on retrieve_summary_info {}", e), } }