wallet: fix for already canceled invoice, transaction info modal, ability to finalize from list
This commit is contained in:
parent
92e1da511d
commit
01b5b21488
10 changed files with 591 additions and 157 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
@ -2808,7 +2808,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grin_wallet_api"
|
name = "grin_wallet_api"
|
||||||
version = "5.2.0-beta.1"
|
version = "5.2.0-beta.1"
|
||||||
source = "git+https://github.com/mimblewimble/grin-wallet?branch=master#75363a9a258bc1fb0cf60bfb4c88a8a653b122f2"
|
source = "git+https://github.com/yeastplume/grin-wallet?branch=prevent_double_pay#6e6b16a61c53825447f27ad49ba654c922cf9702"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.12.3",
|
"base64 0.12.3",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
@ -2833,7 +2833,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grin_wallet_config"
|
name = "grin_wallet_config"
|
||||||
version = "5.2.0-beta.1"
|
version = "5.2.0-beta.1"
|
||||||
source = "git+https://github.com/mimblewimble/grin-wallet?branch=master#75363a9a258bc1fb0cf60bfb4c88a8a653b122f2"
|
source = "git+https://github.com/yeastplume/grin-wallet?branch=prevent_double_pay#6e6b16a61c53825447f27ad49ba654c922cf9702"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dirs 2.0.2",
|
"dirs 2.0.2",
|
||||||
"grin_core",
|
"grin_core",
|
||||||
|
@ -2848,7 +2848,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grin_wallet_controller"
|
name = "grin_wallet_controller"
|
||||||
version = "5.2.0-beta.1"
|
version = "5.2.0-beta.1"
|
||||||
source = "git+https://github.com/mimblewimble/grin-wallet?branch=master#75363a9a258bc1fb0cf60bfb4c88a8a653b122f2"
|
source = "git+https://github.com/yeastplume/grin-wallet?branch=prevent_double_pay#6e6b16a61c53825447f27ad49ba654c922cf9702"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"easy-jsonrpc-mw",
|
"easy-jsonrpc-mw",
|
||||||
|
@ -2882,7 +2882,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grin_wallet_impls"
|
name = "grin_wallet_impls"
|
||||||
version = "5.2.0-beta.1"
|
version = "5.2.0-beta.1"
|
||||||
source = "git+https://github.com/mimblewimble/grin-wallet?branch=master#75363a9a258bc1fb0cf60bfb4c88a8a653b122f2"
|
source = "git+https://github.com/yeastplume/grin-wallet?branch=prevent_double_pay#6e6b16a61c53825447f27ad49ba654c922cf9702"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.12.3",
|
"base64 0.12.3",
|
||||||
"blake2-rfc",
|
"blake2-rfc",
|
||||||
|
@ -2921,7 +2921,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grin_wallet_libwallet"
|
name = "grin_wallet_libwallet"
|
||||||
version = "5.2.0-beta.1"
|
version = "5.2.0-beta.1"
|
||||||
source = "git+https://github.com/mimblewimble/grin-wallet?branch=master#75363a9a258bc1fb0cf60bfb4c88a8a653b122f2"
|
source = "git+https://github.com/yeastplume/grin-wallet?branch=prevent_double_pay#6e6b16a61c53825447f27ad49ba654c922cf9702"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"age",
|
"age",
|
||||||
"base64 0.9.3",
|
"base64 0.9.3",
|
||||||
|
@ -2958,7 +2958,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grin_wallet_util"
|
name = "grin_wallet_util"
|
||||||
version = "5.2.0-beta.1"
|
version = "5.2.0-beta.1"
|
||||||
source = "git+https://github.com/mimblewimble/grin-wallet?branch=master#75363a9a258bc1fb0cf60bfb4c88a8a653b122f2"
|
source = "git+https://github.com/yeastplume/grin-wallet?branch=prevent_double_pay#6e6b16a61c53825447f27ad49ba654c922cf9702"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
"ed25519-dalek",
|
"ed25519-dalek",
|
||||||
|
|
10
Cargo.toml
10
Cargo.toml
|
@ -26,11 +26,11 @@ grin_keychain = { git = "https://github.com/mimblewimble/grin", branch = "master
|
||||||
grin_util = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
grin_util = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||||
|
|
||||||
## wallet
|
## wallet
|
||||||
grin_wallet_impls = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
|
grin_wallet_impls = { git = "https://github.com/yeastplume/grin-wallet", branch = "prevent_double_pay" }
|
||||||
grin_wallet_api = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
|
grin_wallet_api = { git = "https://github.com/yeastplume/grin-wallet", branch = "prevent_double_pay" }
|
||||||
grin_wallet_libwallet = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
|
grin_wallet_libwallet = { git = "https://github.com/yeastplume/grin-wallet", branch = "prevent_double_pay" }
|
||||||
grin_wallet_util = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
|
grin_wallet_util = { git = "https://github.com/yeastplume/grin-wallet", branch = "prevent_double_pay" }
|
||||||
grin_wallet_controller = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" }
|
grin_wallet_controller = { git = "https://github.com/yeastplume/grin-wallet", branch = "prevent_double_pay" }
|
||||||
|
|
||||||
## ui
|
## ui
|
||||||
egui = { version = "0.27.2", default-features = false }
|
egui = { version = "0.27.2", default-features = false }
|
||||||
|
|
|
@ -10,6 +10,8 @@ show: Show
|
||||||
delete: Delete
|
delete: Delete
|
||||||
clear: Clear
|
clear: Clear
|
||||||
create: Create
|
create: Create
|
||||||
|
id: Identifier
|
||||||
|
kernel: Kernel
|
||||||
wallets:
|
wallets:
|
||||||
await_conf_amount: Awaiting confirmation
|
await_conf_amount: Awaiting confirmation
|
||||||
await_fin_amount: Awaiting finalization
|
await_fin_amount: Awaiting finalization
|
||||||
|
@ -65,11 +67,11 @@ wallets:
|
||||||
tx_finalizing: Finalizing
|
tx_finalizing: Finalizing
|
||||||
tx_confirmed: Confirmed
|
tx_confirmed: Confirmed
|
||||||
txs: Transactions
|
txs: Transactions
|
||||||
|
input_finalize_desc: 'Enter message to finalize the transaction:'
|
||||||
messages: Messages
|
messages: Messages
|
||||||
transport: Transport
|
transport: Transport
|
||||||
input_slatepack_desc: 'Enter message to create response or finalize the transaction:'
|
input_slatepack_desc: 'Enter message to create response or finalize the transaction:'
|
||||||
send_slatepack_desc: 'Send message to receiver of funds to finalize the transaction:'
|
parse_slatepack_err: 'An error occurred during reading of the message, check input data:'
|
||||||
parse_slatepack_err: 'An error occurred during handling of the message, check input data:'
|
|
||||||
pay_balance_error: 'Account balance is insufficient to pay %{amount} ツ and network fee.'
|
pay_balance_error: 'Account balance is insufficient to pay %{amount} ツ and network fee.'
|
||||||
parse_i1_slatepack_desc: 'To pay %{amount} ツ send this message to the receiver:'
|
parse_i1_slatepack_desc: 'To pay %{amount} ツ send this message to the receiver:'
|
||||||
parse_i2_slatepack_desc: 'Finalize transaction to receive %{amount} ツ'
|
parse_i2_slatepack_desc: 'Finalize transaction to receive %{amount} ツ'
|
||||||
|
@ -78,7 +80,8 @@ wallets:
|
||||||
parse_s2_slatepack_desc: 'Finalize transaction to send %{amount} ツ'
|
parse_s2_slatepack_desc: 'Finalize transaction to send %{amount} ツ'
|
||||||
parse_s3_slatepack_desc: 'Post transaction to finalize sending of %{amount} ツ'
|
parse_s3_slatepack_desc: 'Post transaction to finalize sending of %{amount} ツ'
|
||||||
resp_slatepack_err: 'An error occurred during creation of the response, check input data:'
|
resp_slatepack_err: 'An error occurred during creation of the response, check input data:'
|
||||||
resp_exists_err: 'Such transaction already exists.'
|
resp_exists_err: Such transaction already exists.
|
||||||
|
resp_canceled_err: Such transaction was already canceled.
|
||||||
create_request_desc: 'Create request to send or receive the funds:'
|
create_request_desc: 'Create request to send or receive the funds:'
|
||||||
send_request_desc: 'You have created a request to send %{amount} ツ. Send this message to the receiver:'
|
send_request_desc: 'You have created a request to send %{amount} ツ. Send this message to the receiver:'
|
||||||
send_slatepack_err: An error occurred during creation of request to send funds, check input data.
|
send_slatepack_err: An error occurred during creation of request to send funds, check input data.
|
||||||
|
|
|
@ -10,6 +10,8 @@ show: Показать
|
||||||
delete: Удалить
|
delete: Удалить
|
||||||
clear: Очистить
|
clear: Очистить
|
||||||
create: Создать
|
create: Создать
|
||||||
|
id: Идентификатор
|
||||||
|
kernel: Ядро
|
||||||
wallets:
|
wallets:
|
||||||
await_conf_amount: Ожидает подтверждения
|
await_conf_amount: Ожидает подтверждения
|
||||||
await_fin_amount: Ожидает завершения
|
await_fin_amount: Ожидает завершения
|
||||||
|
@ -65,11 +67,11 @@ wallets:
|
||||||
tx_finalizing: Завершение
|
tx_finalizing: Завершение
|
||||||
tx_confirmed: Подтверждено
|
tx_confirmed: Подтверждено
|
||||||
txs: Транзакции
|
txs: Транзакции
|
||||||
|
input_finalize_desc: 'Введите полученное сообщение для завершения транзакции:'
|
||||||
messages: Сообщения
|
messages: Сообщения
|
||||||
transport: Транспорт
|
transport: Транспорт
|
||||||
input_slatepack_desc: 'Введите полученное сообщение для создания ответа или завершения транзакции:'
|
input_slatepack_desc: 'Введите полученное сообщение для создания ответа или завершения транзакции:'
|
||||||
send_slatepack_desc: 'Отправьте сообщение получателю средств для завершения транзакции:'
|
parse_slatepack_err: 'Во время чтения сообщения произошла ошибка, проверьте входные данные:'
|
||||||
parse_slatepack_err: 'Во время обработки сообщения произошла ошибка, проверьте входные данные:'
|
|
||||||
pay_balance_error: 'Средств на аккаунте недостаточно для оплаты %{amount} ツ и комиссии сети.'
|
pay_balance_error: 'Средств на аккаунте недостаточно для оплаты %{amount} ツ и комиссии сети.'
|
||||||
parse_i1_slatepack_desc: 'Для оплаты %{amount} ツ отправьте это сообщение получателю:'
|
parse_i1_slatepack_desc: 'Для оплаты %{amount} ツ отправьте это сообщение получателю:'
|
||||||
parse_i2_slatepack_desc: 'Завершите транзакцию для получения %{amount} ツ'
|
parse_i2_slatepack_desc: 'Завершите транзакцию для получения %{amount} ツ'
|
||||||
|
@ -78,8 +80,9 @@ wallets:
|
||||||
parse_s2_slatepack_desc: 'Завершите транзакцию для отправки %{amount} ツ'
|
parse_s2_slatepack_desc: 'Завершите транзакцию для отправки %{amount} ツ'
|
||||||
parse_s3_slatepack_desc: 'Опубликуйте транзакцию для завершения отправки %{amount} ツ'
|
parse_s3_slatepack_desc: 'Опубликуйте транзакцию для завершения отправки %{amount} ツ'
|
||||||
resp_slatepack_err: 'Во время создания ответа произошла ошибка, проверьте входные данные:'
|
resp_slatepack_err: 'Во время создания ответа произошла ошибка, проверьте входные данные:'
|
||||||
resp_exists_err: 'Такая транзакция уже существует.'
|
resp_exists_err: Такая транзакция уже существует.
|
||||||
create_request_desc: 'Cоздать запрос на отправку или получение средств:'
|
resp_canceled_err: Такая транзакция уже была отменена.
|
||||||
|
create_request_desc: 'Создайте запрос на отправку или получение средств:'
|
||||||
send_request_desc: 'Вы создали запрос на отправку %{amount} ツ. Отправьте это сообщение получателю:'
|
send_request_desc: 'Вы создали запрос на отправку %{amount} ツ. Отправьте это сообщение получателю:'
|
||||||
send_slatepack_err: Во время создания запроса на отправку средств произошла ошибка, проверьте входные данные.
|
send_slatepack_err: Во время создания запроса на отправку средств произошла ошибка, проверьте входные данные.
|
||||||
invoice_desc: 'Вы создали запрос на получение %{amount} ツ. Отправьте это сообщение отправителю:'
|
invoice_desc: 'Вы создали запрос на получение %{amount} ツ. Отправьте это сообщение отправителю:'
|
||||||
|
|
|
@ -23,7 +23,7 @@ use crate::gui::icons::{BRIDGE, CHAT_CIRCLE_TEXT, CHECK, CHECK_FAT, FOLDER_USER,
|
||||||
use crate::gui::platform::PlatformCallbacks;
|
use crate::gui::platform::PlatformCallbacks;
|
||||||
use crate::gui::views::{Modal, Root, View};
|
use crate::gui::views::{Modal, Root, View};
|
||||||
use crate::gui::views::types::{ModalPosition, TextEditOptions};
|
use crate::gui::views::types::{ModalPosition, TextEditOptions};
|
||||||
use crate::gui::views::wallets::{WalletInfo, WalletMessages, WalletTransport, WalletSettings};
|
use crate::gui::views::wallets::{WalletTransactions, WalletMessages, WalletTransport, WalletSettings};
|
||||||
use crate::gui::views::wallets::types::{GRIN, WalletTab, WalletTabType};
|
use crate::gui::views::wallets::types::{GRIN, WalletTab, WalletTabType};
|
||||||
use crate::node::Node;
|
use crate::node::Node;
|
||||||
use crate::wallet::{Wallet, WalletConfig};
|
use crate::wallet::{Wallet, WalletConfig};
|
||||||
|
@ -52,7 +52,7 @@ impl Default for WalletContent {
|
||||||
account_creating: false,
|
account_creating: false,
|
||||||
account_label_edit: "".to_string(),
|
account_label_edit: "".to_string(),
|
||||||
account_creation_error: false,
|
account_creation_error: false,
|
||||||
current_tab: Box::new(WalletInfo::default())
|
current_tab: Box::new(WalletTransactions::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -349,7 +349,7 @@ impl WalletContent {
|
||||||
ui.columns(4, |columns| {
|
ui.columns(4, |columns| {
|
||||||
columns[0].vertical_centered_justified(|ui| {
|
columns[0].vertical_centered_justified(|ui| {
|
||||||
View::tab_button(ui, GRAPH, current_type == WalletTabType::Txs, || {
|
View::tab_button(ui, GRAPH, current_type == WalletTabType::Txs, || {
|
||||||
self.current_tab = Box::new(WalletInfo::default());
|
self.current_tab = Box::new(WalletTransactions::default());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
columns[1].vertical_centered_justified(|ui| {
|
columns[1].vertical_centered_justified(|ui| {
|
||||||
|
|
|
@ -146,14 +146,14 @@ impl WalletMessages {
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
wallet: &mut Wallet,
|
wallet: &mut Wallet,
|
||||||
cb: &dyn PlatformCallbacks) {
|
cb: &dyn PlatformCallbacks) {
|
||||||
ui.add_space(4.0);
|
ui.add_space(3.0);
|
||||||
|
|
||||||
// Show creation of request to send or receive funds.
|
// Show creation of request to send or receive funds.
|
||||||
self.request_ui(ui, cb);
|
self.request_ui(ui, cb);
|
||||||
|
|
||||||
ui.add_space(12.0);
|
ui.add_space(12.0);
|
||||||
View::horizontal_line(ui, Colors::ITEM_STROKE);
|
View::horizontal_line(ui, Colors::ITEM_STROKE);
|
||||||
ui.add_space(8.0);
|
ui.add_space(6.0);
|
||||||
|
|
||||||
// Show Slatepack message input field.
|
// Show Slatepack message input field.
|
||||||
self.input_slatepack_ui(ui, wallet, cb);
|
self.input_slatepack_ui(ui, wallet, cb);
|
||||||
|
@ -326,11 +326,10 @@ impl WalletMessages {
|
||||||
} else {
|
} else {
|
||||||
show_dandelion = true;
|
show_dandelion = true;
|
||||||
View::button(ui, t!("wallets.finalize"), Colors::GOLD, || {
|
View::button(ui, t!("wallets.finalize"), Colors::GOLD, || {
|
||||||
let message = self.message_edit.clone();
|
|
||||||
let slate = self.message_slate.clone().unwrap();
|
let slate = self.message_slate.clone().unwrap();
|
||||||
if slate.state == SlateState::Invoice3 ||
|
if slate.state == SlateState::Invoice3 ||
|
||||||
slate.state == SlateState::Standard3 {
|
slate.state == SlateState::Standard3 {
|
||||||
if let Ok(_) = wallet.post(&slate, self.dandelion) {
|
if wallet.post(&slate, self.dandelion).is_ok() {
|
||||||
self.message_edit.clear();
|
self.message_edit.clear();
|
||||||
self.message_slate = None;
|
self.message_slate = None;
|
||||||
} else {
|
} else {
|
||||||
|
@ -341,7 +340,8 @@ impl WalletMessages {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let Ok(_) = wallet.finalize(message, self.dandelion) {
|
let r = wallet.finalize(&self.message_edit, self.dandelion);
|
||||||
|
if r.is_ok() {
|
||||||
self.message_edit.clear();
|
self.message_edit.clear();
|
||||||
self.message_slate = None;
|
self.message_slate = None;
|
||||||
} else {
|
} else {
|
||||||
|
@ -397,7 +397,7 @@ impl WalletMessages {
|
||||||
if self.message_edit.is_empty() {
|
if self.message_edit.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Ok(mut slate) = wallet.parse_slatepack(self.message_edit.clone()) {
|
if let Ok(mut slate) = wallet.parse_slatepack(&self.message_edit) {
|
||||||
println!("parse_message: {}", slate);
|
println!("parse_message: {}", slate);
|
||||||
|
|
||||||
// Try to setup empty amount from transaction by id.
|
// Try to setup empty amount from transaction by id.
|
||||||
|
@ -423,13 +423,23 @@ impl WalletMessages {
|
||||||
match slate.state {
|
match slate.state {
|
||||||
SlateState::Standard1 | SlateState::Invoice1 => {
|
SlateState::Standard1 | SlateState::Invoice1 => {
|
||||||
let resp = if slate.state == SlateState::Standard1 {
|
let resp = if slate.state == SlateState::Standard1 {
|
||||||
wallet.receive(self.message_edit.clone())
|
wallet.receive(&self.message_edit)
|
||||||
} else {
|
} else {
|
||||||
wallet.pay(self.message_edit.clone())
|
wallet.pay(&self.message_edit)
|
||||||
};
|
};
|
||||||
if resp.is_ok() {
|
if resp.is_ok() {
|
||||||
self.response_edit = resp.unwrap();
|
self.response_edit = resp.unwrap();
|
||||||
} else {
|
} else {
|
||||||
|
match resp.err().unwrap() {
|
||||||
|
grin_wallet_libwallet::Error::TransactionWasCancelled {..} => {
|
||||||
|
// Set already canceled transaction error message.
|
||||||
|
self.message_error = Some(
|
||||||
|
MessageError::Response(t!("wallets.resp_canceled_err"))
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
// Check if tx with same slate id already exists.
|
// Check if tx with same slate id already exists.
|
||||||
let exists_tx = wallet.tx_by_slate(&slate).is_some();
|
let exists_tx = wallet.tx_by_slate(&slate).is_some();
|
||||||
if exists_tx {
|
if exists_tx {
|
||||||
|
@ -726,7 +736,7 @@ impl WalletMessages {
|
||||||
// Button to cancel transaction.
|
// Button to cancel transaction.
|
||||||
let cancel = format!("{} {}", PROHIBIT, t!("modal.cancel"));
|
let cancel = format!("{} {}", PROHIBIT, t!("modal.cancel"));
|
||||||
View::colored_text_button(ui, cancel, Colors::RED, Colors::BUTTON, || {
|
View::colored_text_button(ui, cancel, Colors::RED, Colors::BUTTON, || {
|
||||||
if let Ok(slate) = wallet.parse_slatepack(self.request_edit.clone()) {
|
if let Ok(slate) = wallet.parse_slatepack(&self.request_edit) {
|
||||||
if let Some(tx) = wallet.tx_by_slate(&slate) {
|
if let Some(tx) = wallet.tx_by_slate(&slate) {
|
||||||
wallet.cancel(tx.data.id);
|
wallet.cancel(tx.data.id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
mod txs;
|
mod txs;
|
||||||
pub use txs::WalletInfo;
|
pub use txs::WalletTransactions;
|
||||||
|
|
||||||
mod messages;
|
mod messages;
|
||||||
pub use messages::WalletMessages;
|
pub use messages::WalletMessages;
|
||||||
|
|
|
@ -15,24 +15,50 @@
|
||||||
use egui::{Align, Id, Layout, Margin, RichText, Rounding, ScrollArea};
|
use egui::{Align, Id, Layout, Margin, RichText, Rounding, ScrollArea};
|
||||||
use egui::scroll_area::ScrollBarVisibility;
|
use egui::scroll_area::ScrollBarVisibility;
|
||||||
use grin_core::core::amount_to_hr_string;
|
use grin_core::core::amount_to_hr_string;
|
||||||
|
use grin_util::ToHex;
|
||||||
use grin_wallet_libwallet::{Slate, SlateState, TxLogEntryType};
|
use grin_wallet_libwallet::{Slate, SlateState, TxLogEntryType};
|
||||||
|
|
||||||
use crate::gui::Colors;
|
use crate::gui::Colors;
|
||||||
use crate::gui::icons::{ARROW_CIRCLE_DOWN, ARROW_CIRCLE_UP, ARROW_CLOCKWISE, ARROWS_CLOCKWISE, 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, ARROW_CIRCLE_UP, ARROW_CLOCKWISE, BRIDGE, CALENDAR_CHECK, CHAT_CIRCLE_TEXT, CHECK, CHECK_CIRCLE, CLIPBOARD_TEXT, COPY, DOTS_THREE_CIRCLE, FILE_ARCHIVE, FILE_TEXT, GEAR_FINE, HASH_STRAIGHT, PROHIBIT, X_CIRCLE};
|
||||||
use crate::gui::platform::PlatformCallbacks;
|
use crate::gui::platform::PlatformCallbacks;
|
||||||
use crate::gui::views::{Root, View};
|
use crate::gui::views::{Modal, Root, View};
|
||||||
|
use crate::gui::views::types::ModalPosition;
|
||||||
use crate::gui::views::wallets::types::WalletTab;
|
use crate::gui::views::wallets::types::WalletTab;
|
||||||
use crate::gui::views::wallets::wallet::types::{GRIN, WalletTabType};
|
use crate::gui::views::wallets::wallet::types::{GRIN, SLATEPACK_MESSAGE_HINT, WalletTabType};
|
||||||
use crate::gui::views::wallets::wallet::WalletContent;
|
use crate::gui::views::wallets::wallet::WalletContent;
|
||||||
use crate::wallet::types::{WalletData, WalletTransaction};
|
use crate::wallet::types::{WalletData, WalletTransaction};
|
||||||
use crate::wallet::Wallet;
|
use crate::wallet::Wallet;
|
||||||
|
|
||||||
|
/// Wallet transactions tab content.
|
||||||
|
pub struct WalletTransactions {
|
||||||
|
/// Transaction identifier to user at [`Modal`].
|
||||||
|
tx_info_id: Option<u32>,
|
||||||
|
/// Transaction [`Slate`] to use at [`Modal`].
|
||||||
|
tx_info_slate: Option<Slate>,
|
||||||
|
/// Response Slatepack message input value at [`Modal`].
|
||||||
|
tx_info_response_edit: String,
|
||||||
|
/// Finalization Slatepack message input value at [`Modal`].
|
||||||
|
tx_info_finalize_edit: String,
|
||||||
|
/// Flag to check if error happened during transaction finalization at [`Modal`].
|
||||||
|
tx_info_finalize_error: bool,
|
||||||
|
/// Flag to check if tx finalization requested at [`Modal`].
|
||||||
|
tx_info_finalize: bool,
|
||||||
|
}
|
||||||
|
|
||||||
/// Wallet info tab content.
|
impl Default for WalletTransactions {
|
||||||
#[derive(Default)]
|
fn default() -> Self {
|
||||||
pub struct WalletInfo;
|
Self {
|
||||||
|
tx_info_id: None,
|
||||||
|
tx_info_slate: None,
|
||||||
|
tx_info_response_edit: "".to_string(),
|
||||||
|
tx_info_finalize_edit: "".to_string(),
|
||||||
|
tx_info_finalize_error: false,
|
||||||
|
tx_info_finalize: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl WalletTab for WalletInfo {
|
impl WalletTab for WalletTransactions {
|
||||||
fn get_type(&self) -> WalletTabType {
|
fn get_type(&self) -> WalletTabType {
|
||||||
WalletTabType::Txs
|
WalletTabType::Txs
|
||||||
}
|
}
|
||||||
|
@ -41,11 +67,14 @@ impl WalletTab for WalletInfo {
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
_: &mut eframe::Frame,
|
_: &mut eframe::Frame,
|
||||||
wallet: &mut Wallet,
|
wallet: &mut Wallet,
|
||||||
_: &dyn PlatformCallbacks) {
|
cb: &dyn PlatformCallbacks) {
|
||||||
if WalletContent::sync_ui(ui, wallet) {
|
if WalletContent::sync_ui(ui, wallet) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show modal content for this ui container.
|
||||||
|
self.modal_content_ui(ui, wallet, cb);
|
||||||
|
|
||||||
// Show wallet transactions panel.
|
// Show wallet transactions panel.
|
||||||
egui::CentralPanel::default()
|
egui::CentralPanel::default()
|
||||||
.frame(egui::Frame {
|
.frame(egui::Frame {
|
||||||
|
@ -62,23 +91,32 @@ impl WalletTab for WalletInfo {
|
||||||
.show_inside(ui, |ui| {
|
.show_inside(ui, |ui| {
|
||||||
ui.vertical_centered(|ui| {
|
ui.vertical_centered(|ui| {
|
||||||
let data = wallet.get_data().unwrap();
|
let data = wallet.get_data().unwrap();
|
||||||
self.txs_ui(ui, wallet, &data);
|
self.txs_ui(ui, wallet, &data, cb);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WalletInfo {
|
/// Identifier for transaction information [`Modal`].
|
||||||
/// Draw transactions content.
|
const TX_INFO_MODAL: &'static str = "tx_info_modal";
|
||||||
fn txs_ui(&self, ui: &mut egui::Ui, wallet: &mut Wallet, data: &WalletData) {
|
|
||||||
let txs_size = data.txs.len();
|
|
||||||
|
|
||||||
// Show transactions info.
|
/// Height of transaction list item.
|
||||||
View::max_width_ui(ui, Root::SIDE_PANEL_WIDTH * 1.3, |ui| {
|
const TX_ITEM_HEIGHT: f32 = 76.0;
|
||||||
|
|
||||||
|
impl WalletTransactions {
|
||||||
|
/// Draw transactions content.
|
||||||
|
fn txs_ui(&mut self,
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
wallet: &mut Wallet,
|
||||||
|
data: &WalletData,
|
||||||
|
cb: &dyn PlatformCallbacks) {
|
||||||
let amount_awaiting_conf = data.info.amount_awaiting_confirmation;
|
let amount_awaiting_conf = data.info.amount_awaiting_confirmation;
|
||||||
let amount_awaiting_fin = data.info.amount_awaiting_finalization;
|
let amount_awaiting_fin = data.info.amount_awaiting_finalization;
|
||||||
let amount_locked = data.info.amount_locked;
|
let amount_locked = data.info.amount_locked;
|
||||||
|
|
||||||
|
// Show transactions info.
|
||||||
|
View::max_width_ui(ui, Root::SIDE_PANEL_WIDTH * 1.3, |ui| {
|
||||||
|
|
||||||
// Show non-zero awaiting confirmation amount.
|
// Show non-zero awaiting confirmation amount.
|
||||||
if amount_awaiting_conf != 0 {
|
if amount_awaiting_conf != 0 {
|
||||||
let awaiting_conf = amount_to_hr_string(amount_awaiting_conf, true);
|
let awaiting_conf = amount_to_hr_string(amount_awaiting_conf, true);
|
||||||
|
@ -117,7 +155,7 @@ impl WalletInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show message when wallet txs are empty.
|
// Show message when wallet txs are empty.
|
||||||
if txs_size == 0 {
|
if data.txs.is_empty() {
|
||||||
View::center_content(ui, 96.0, |ui| {
|
View::center_content(ui, 96.0, |ui| {
|
||||||
let empty_text = t!(
|
let empty_text = t!(
|
||||||
"wallets.txs_empty",
|
"wallets.txs_empty",
|
||||||
|
@ -137,36 +175,51 @@ impl WalletInfo {
|
||||||
.scroll_bar_visibility(ScrollBarVisibility::AlwaysVisible)
|
.scroll_bar_visibility(ScrollBarVisibility::AlwaysVisible)
|
||||||
.id_source(Id::from("txs_content").with(wallet.get_config().id))
|
.id_source(Id::from("txs_content").with(wallet.get_config().id))
|
||||||
.auto_shrink([false; 2])
|
.auto_shrink([false; 2])
|
||||||
.show_rows(ui, TX_ITEM_HEIGHT, txs_size, |ui, row_range| {
|
.show_rows(ui, TX_ITEM_HEIGHT, data.txs.len(), |ui, row_range| {
|
||||||
ui.add_space(3.0);
|
ui.add_space(3.0);
|
||||||
View::max_width_ui(ui, Root::SIDE_PANEL_WIDTH * 1.3, |ui| {
|
View::max_width_ui(ui, Root::SIDE_PANEL_WIDTH * 1.3, |ui| {
|
||||||
let amount_awaiting_conf = data.info.amount_awaiting_confirmation;
|
|
||||||
let amount_awaiting_fin = data.info.amount_awaiting_finalization;
|
|
||||||
let amount_locked = data.info.amount_locked;
|
|
||||||
let extra_padding = amount_awaiting_conf != 0 || amount_awaiting_fin != 0 ||
|
let extra_padding = amount_awaiting_conf != 0 || amount_awaiting_fin != 0 ||
|
||||||
amount_locked != 0;
|
amount_locked != 0;
|
||||||
for index in row_range {
|
for index in row_range {
|
||||||
let tx = data.txs.get(index).unwrap();
|
|
||||||
// Setup item rounding.
|
|
||||||
let item_rounding = View::item_rounding(index, txs_size, false);
|
|
||||||
// Show transaction item.
|
// Show transaction item.
|
||||||
tx_item_ui(ui, tx, item_rounding, extra_padding, &data, wallet);
|
let tx = data.txs.get(index).unwrap();
|
||||||
|
let rounding = View::item_rounding(index, data.txs.len(), false);
|
||||||
|
self.tx_item_ui(ui, tx, rounding, extra_padding, true, &data, wallet, cb);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Height of transaction list item.
|
/// Draw [`Modal`] content for this ui container.
|
||||||
const TX_ITEM_HEIGHT: f32 = 76.0;
|
fn modal_content_ui(&mut self,
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
wallet: &mut Wallet,
|
||||||
|
cb: &dyn PlatformCallbacks) {
|
||||||
|
match Modal::opened() {
|
||||||
|
None => {}
|
||||||
|
Some(id) => {
|
||||||
|
match id {
|
||||||
|
TX_INFO_MODAL => {
|
||||||
|
Modal::ui(ui.ctx(), |ui, modal| {
|
||||||
|
self.tx_info_modal_ui(ui, wallet, modal, cb);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Draw transaction item.
|
/// Draw transaction item.
|
||||||
fn tx_item_ui(ui: &mut egui::Ui,
|
fn tx_item_ui(&mut self,
|
||||||
|
ui: &mut egui::Ui,
|
||||||
tx: &WalletTransaction,
|
tx: &WalletTransaction,
|
||||||
mut rounding: Rounding,
|
mut rounding: Rounding,
|
||||||
extra_padding: bool,
|
extra_padding: bool,
|
||||||
|
can_show_info: bool,
|
||||||
data: &WalletData,
|
data: &WalletData,
|
||||||
wallet: &mut Wallet) {
|
wallet: &mut Wallet,
|
||||||
|
cb: &dyn PlatformCallbacks) {
|
||||||
// Setup layout size.
|
// Setup layout size.
|
||||||
let mut rect = ui.available_rect_before_wrap();
|
let mut rect = ui.available_rect_before_wrap();
|
||||||
if extra_padding {
|
if extra_padding {
|
||||||
|
@ -177,38 +230,61 @@ fn tx_item_ui(ui: &mut egui::Ui,
|
||||||
|
|
||||||
// Draw round background.
|
// Draw round background.
|
||||||
let bg_rect = rect.clone();
|
let bg_rect = rect.clone();
|
||||||
ui.painter().rect(bg_rect, rounding, Colors::BUTTON, View::ITEM_STROKE);
|
let color = if can_show_info {
|
||||||
|
Colors::BUTTON
|
||||||
|
} else {
|
||||||
|
Colors::FILL
|
||||||
|
};
|
||||||
|
ui.painter().rect(bg_rect, rounding, color, View::ITEM_STROKE);
|
||||||
|
|
||||||
ui.vertical(|ui| {
|
|
||||||
ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| {
|
ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| {
|
||||||
if extra_padding {
|
|
||||||
ui.add_space(-6.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw button to show transaction info.
|
// Draw button to show transaction info.
|
||||||
|
if can_show_info {
|
||||||
rounding.nw = 0.0;
|
rounding.nw = 0.0;
|
||||||
rounding.sw = 0.0;
|
rounding.sw = 0.0;
|
||||||
View::item_button(ui, rounding, FILE_TEXT, None, || {
|
View::item_button(ui, rounding, FILE_TEXT, None, || {
|
||||||
//TODO: Show tx info
|
self.tx_info_finalize = false;
|
||||||
|
self.show_tx_info_modal(wallet, tx);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Setup flag to repost unconfirmed posting transaction after min confirmation time.
|
// Draw cancel button for tx that can be reposted and canceled.
|
||||||
let last_height = data.info.last_confirmed_height;
|
if tx.can_repost(data) || tx.can_cancel() {
|
||||||
let min_conf = data.info.minimum_confirmations;
|
let cancel_rounding = if can_show_info {
|
||||||
let can_repost = tx.posting && tx.repost_height.is_some() &&
|
Rounding::default()
|
||||||
last_height - tx.repost_height.unwrap() > min_conf;
|
} else {
|
||||||
|
rounding.nw = 0.0;
|
||||||
// Draw cancel button for txs to repost or also non-cancelled, non-posting.
|
rounding.sw = 0.0;
|
||||||
if can_repost || (!tx.posting && !tx.data.confirmed &&
|
rounding
|
||||||
tx.data.tx_type != TxLogEntryType::TxReceivedCancelled
|
};
|
||||||
&& tx.data.tx_type != TxLogEntryType::TxSentCancelled) {
|
View::item_button(ui, cancel_rounding, PROHIBIT, Some(Colors::RED), || {
|
||||||
View::item_button(ui, Rounding::default(), PROHIBIT, Some(Colors::RED), || {
|
|
||||||
wallet.cancel(tx.data.id);
|
wallet.cancel(tx.data.id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw finalization button for tx that can be finalized.
|
||||||
|
if tx.can_finalize {
|
||||||
|
let (icon, color) = if !can_show_info && self.tx_info_finalize {
|
||||||
|
(FILE_TEXT, None)
|
||||||
|
} else {
|
||||||
|
(CHECK, Some(Colors::GREEN))
|
||||||
|
};
|
||||||
|
View::item_button(ui, Rounding::default(), icon, color, || {
|
||||||
|
if !can_show_info && self.tx_info_finalize {
|
||||||
|
self.tx_info_finalize = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.tx_info_finalize = true;
|
||||||
|
// Show transaction information modal.
|
||||||
|
if can_show_info {
|
||||||
|
self.show_tx_info_modal(wallet, tx);
|
||||||
|
cb.show_keyboard();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Draw button to repost transaction.
|
// Draw button to repost transaction.
|
||||||
if can_repost {
|
if tx.can_repost(data) {
|
||||||
View::item_button(ui,
|
View::item_button(ui,
|
||||||
Rounding::default(),
|
Rounding::default(),
|
||||||
ARROW_CLOCKWISE,
|
ARROW_CLOCKWISE,
|
||||||
|
@ -222,7 +298,7 @@ fn tx_item_ui(ui: &mut egui::Ui,
|
||||||
};
|
};
|
||||||
// Post tx after getting slate from slatepack file.
|
// Post tx after getting slate from slatepack file.
|
||||||
if let Some(sp) = wallet.read_slatepack(&slate) {
|
if let Some(sp) = wallet.read_slatepack(&slate) {
|
||||||
if let Ok(s) = wallet.parse_slatepack(sp) {
|
if let Ok(s) = wallet.parse_slatepack(&sp) {
|
||||||
let _ = wallet.post(&s, wallet.can_use_dandelion());
|
let _ = wallet.post(&s, wallet.can_use_dandelion());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,11 +307,7 @@ fn tx_item_ui(ui: &mut egui::Ui,
|
||||||
|
|
||||||
let layout_size = ui.available_size();
|
let layout_size = ui.available_size();
|
||||||
ui.allocate_ui_with_layout(layout_size, Layout::left_to_right(Align::Center), |ui| {
|
ui.allocate_ui_with_layout(layout_size, Layout::left_to_right(Align::Center), |ui| {
|
||||||
if extra_padding {
|
|
||||||
ui.add_space(12.0);
|
|
||||||
} else {
|
|
||||||
ui.add_space(6.0);
|
ui.add_space(6.0);
|
||||||
}
|
|
||||||
ui.vertical(|ui| {
|
ui.vertical(|ui| {
|
||||||
ui.add_space(3.0);
|
ui.add_space(3.0);
|
||||||
|
|
||||||
|
@ -294,13 +366,14 @@ fn tx_item_ui(ui: &mut egui::Ui,
|
||||||
format!("{} {}", CHECK_CIRCLE, t!("wallets.tx_confirmed"))
|
format!("{} {}", CHECK_CIRCLE, t!("wallets.tx_confirmed"))
|
||||||
},
|
},
|
||||||
TxLogEntryType::TxSent | TxLogEntryType::TxReceived => {
|
TxLogEntryType::TxSent | TxLogEntryType::TxReceived => {
|
||||||
|
let min_conf = data.info.minimum_confirmations;
|
||||||
if data.info.last_confirmed_height - tx_height > min_conf {
|
if data.info.last_confirmed_height - tx_height > min_conf {
|
||||||
let (icon, text) = if tx.data.tx_type == TxLogEntryType::TxSent {
|
let (i, t) = if tx.data.tx_type == TxLogEntryType::TxSent {
|
||||||
(ARROW_CIRCLE_UP, t!("wallets.tx_sent"))
|
(ARROW_CIRCLE_UP, t!("wallets.tx_sent"))
|
||||||
} else {
|
} else {
|
||||||
(ARROW_CIRCLE_DOWN, t!("wallets.tx_received"))
|
(ARROW_CIRCLE_DOWN, t!("wallets.tx_received"))
|
||||||
};
|
};
|
||||||
format!("{} {}", icon, text)
|
format!("{} {}", i, t)
|
||||||
} else {
|
} else {
|
||||||
let h = data.info.last_confirmed_height;
|
let h = data.info.last_confirmed_height;
|
||||||
let left_conf = h - tx_height;
|
let left_conf = h - tx_height;
|
||||||
|
@ -343,8 +416,269 @@ fn tx_item_ui(ui: &mut egui::Ui,
|
||||||
let tx_time = View::format_time(tx.data.creation_ts.timestamp());
|
let tx_time = View::format_time(tx.data.creation_ts.timestamp());
|
||||||
let tx_time_text = format!("{} {}", CALENDAR_CHECK, tx_time);
|
let tx_time_text = format!("{} {}", CALENDAR_CHECK, tx_time);
|
||||||
ui.label(RichText::new(tx_time_text).size(15.0).color(Colors::GRAY));
|
ui.label(RichText::new(tx_time_text).size(15.0).color(Colors::GRAY));
|
||||||
|
ui.add_space(3.0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Show transaction information [`Modal`].
|
||||||
|
fn show_tx_info_modal(&mut self, wallet: &Wallet, tx: &WalletTransaction) {
|
||||||
|
self.tx_info_response_edit = "".to_string();
|
||||||
|
self.tx_info_finalize_edit = "".to_string();
|
||||||
|
self.tx_info_finalize_error = false;
|
||||||
|
self.tx_info_id = Some(tx.data.id);
|
||||||
|
// Setup slate and message from transaction.
|
||||||
|
if let Some((slate, message)) = wallet.read_slate_by_tx(tx) {
|
||||||
|
self.tx_info_response_edit = message;
|
||||||
|
self.tx_info_slate = Some(slate);
|
||||||
|
}
|
||||||
|
// Show transaction information modal.
|
||||||
|
Modal::new(TX_INFO_MODAL)
|
||||||
|
.position(ModalPosition::CenterTop)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw transaction info [`Modal`] content.
|
||||||
|
fn tx_info_modal_ui(&mut self,
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
wallet: &mut Wallet,
|
||||||
|
modal: &Modal,
|
||||||
|
cb: &dyn PlatformCallbacks) {
|
||||||
|
// Check values and setup transaction data.
|
||||||
|
let wallet_data = wallet.get_data();
|
||||||
|
if wallet_data.is_none() {
|
||||||
|
modal.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let data = wallet_data.unwrap();
|
||||||
|
let tx_id = self.tx_info_id.unwrap();
|
||||||
|
let txs = data.txs.iter()
|
||||||
|
.filter(|tx| tx.data.id == tx_id)
|
||||||
|
.collect::<Vec<&WalletTransaction>>();
|
||||||
|
if txs.is_empty() {
|
||||||
|
modal.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let tx = txs.get(0).unwrap();
|
||||||
|
|
||||||
|
ui.add_space(6.0);
|
||||||
|
|
||||||
|
// Show transaction amount status and time.
|
||||||
|
let rounding = View::item_rounding(0, 2, false);
|
||||||
|
self.tx_item_ui(ui, tx, rounding, false, false, &data, wallet, cb);
|
||||||
|
|
||||||
|
// Show transaction ID info.
|
||||||
|
if let Some(id) = tx.data.tx_slate_id {
|
||||||
|
let label = format!("{} {}", HASH_STRAIGHT, t!("id"));
|
||||||
|
Self::tx_info_modal_item_ui(ui, id.to_string(), label, true, cb);
|
||||||
|
}
|
||||||
|
// Show transaction kernel info.
|
||||||
|
if let Some(kernel) = tx.data.kernel_excess {
|
||||||
|
let label = format!("{} {}", FILE_ARCHIVE, t!("kernel"));
|
||||||
|
Self::tx_info_modal_item_ui(ui, kernel.0.to_hex(), label, true, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show transaction Slatepack message response or finalization input.
|
||||||
|
if !tx.posting && !tx.data.confirmed && (tx.data.tx_type == TxLogEntryType::TxSent ||
|
||||||
|
tx.data.tx_type == TxLogEntryType::TxReceived) {
|
||||||
|
self.tx_info_modal_slate_ui(ui, tx, wallet, modal, cb);
|
||||||
|
}
|
||||||
|
ui.add_space(8.0);
|
||||||
|
|
||||||
|
// Show button to close modal.
|
||||||
|
ui.vertical_centered_justified(|ui| {
|
||||||
|
View::button(ui, t!("close"), Colors::WHITE, || {
|
||||||
|
self.tx_info_id = None;
|
||||||
|
self.tx_info_finalize = false;
|
||||||
|
cb.hide_keyboard();
|
||||||
|
modal.close();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
ui.add_space(6.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw transaction information [`Modal`] item content.
|
||||||
|
fn tx_info_modal_item_ui(ui: &mut egui::Ui,
|
||||||
|
value: String,
|
||||||
|
label: String,
|
||||||
|
copy: bool,
|
||||||
|
cb: &dyn PlatformCallbacks) {
|
||||||
|
// Setup layout size.
|
||||||
|
let mut rect = ui.available_rect_before_wrap();
|
||||||
|
rect.set_height(50.0);
|
||||||
|
|
||||||
|
// Draw round background.
|
||||||
|
let bg_rect = rect.clone();
|
||||||
|
let mut rounding = View::item_rounding(1, 3, false);
|
||||||
|
|
||||||
|
ui.painter().rect(bg_rect, rounding, Colors::FILL, View::ITEM_STROKE);
|
||||||
|
|
||||||
|
ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| {
|
||||||
|
// Draw button to copy transaction info value.
|
||||||
|
if copy {
|
||||||
|
rounding.nw = 0.0;
|
||||||
|
rounding.sw = 0.0;
|
||||||
|
View::item_button(ui, rounding, COPY, None, || {
|
||||||
|
cb.copy_string_to_buffer(value.clone());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw value information.
|
||||||
|
let layout_size = ui.available_size();
|
||||||
|
ui.allocate_ui_with_layout(layout_size, Layout::left_to_right(Align::Center), |ui| {
|
||||||
|
ui.add_space(6.0);
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
ui.add_space(3.0);
|
||||||
|
View::ellipsize_text(ui, value, 15.0, Colors::TITLE);
|
||||||
|
ui.label(RichText::new(label).size(15.0).color(Colors::GRAY));
|
||||||
|
ui.add_space(3.0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw Slate content to show response or generate payment proof.
|
||||||
|
fn tx_info_modal_slate_ui(&mut self,
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
tx: &WalletTransaction,
|
||||||
|
wallet: &Wallet,
|
||||||
|
modal: &Modal,
|
||||||
|
cb: &dyn PlatformCallbacks) {
|
||||||
|
if self.tx_info_slate.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let slate = self.tx_info_slate.clone().unwrap();
|
||||||
|
let amount = amount_to_hr_string(tx.amount, true);
|
||||||
|
|
||||||
|
// Draw Slatepack message input or output description text.
|
||||||
|
ui.add_space(6.0);
|
||||||
|
ui.vertical_centered(|ui| {
|
||||||
|
if self.tx_info_finalize {
|
||||||
|
let desc_text = if self.tx_info_finalize_error {
|
||||||
|
t!("wallets.finalize_slatepack_err")
|
||||||
|
} else {
|
||||||
|
if tx.data.tx_type == TxLogEntryType::TxSent {
|
||||||
|
t!("wallets.parse_s2_slatepack_desc", "amount" => amount)
|
||||||
|
} else {
|
||||||
|
t!("wallets.parse_i2_slatepack_desc", "amount" => amount)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let desc_color = if self.tx_info_finalize_error {
|
||||||
|
Colors::RED
|
||||||
|
} else {
|
||||||
|
Colors::INACTIVE_TEXT
|
||||||
|
};
|
||||||
|
ui.label(RichText::new(desc_text).size(16.0).color(desc_color));
|
||||||
|
} else {
|
||||||
|
let desc_text = if tx.can_finalize {
|
||||||
|
if tx.data.tx_type == TxLogEntryType::TxSent {
|
||||||
|
t!("wallets.send_request_desc", "amount" => amount)
|
||||||
|
} else {
|
||||||
|
t!("wallets.invoice_desc", "amount" => amount)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if tx.data.tx_type == TxLogEntryType::TxSent {
|
||||||
|
t!("wallets.parse_i1_slatepack_desc", "amount" => amount)
|
||||||
|
} else {
|
||||||
|
t!("wallets.parse_s1_slatepack_desc", "amount" => amount)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ui.label(RichText::new(desc_text).size(16.0).color(Colors::INACTIVE_TEXT));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ui.add_space(4.0);
|
||||||
|
|
||||||
|
ui.vertical_centered(|ui| {
|
||||||
|
let message_edit = if self.tx_info_finalize {
|
||||||
|
&mut self.tx_info_finalize_edit
|
||||||
|
} else {
|
||||||
|
&mut self.tx_info_response_edit
|
||||||
|
};
|
||||||
|
let message_before = message_edit.clone();
|
||||||
|
|
||||||
|
// Draw Slatepack message text input or output.
|
||||||
|
let input_id = Id::from("tx_info_slatepack_message").with(slate.id).with(tx.data.id);
|
||||||
|
View::horizontal_line(ui, Colors::ITEM_STROKE);
|
||||||
|
ui.add_space(3.0);
|
||||||
|
ScrollArea::vertical()
|
||||||
|
.max_height(128.0)
|
||||||
|
.id_source(input_id)
|
||||||
|
.auto_shrink([false; 2])
|
||||||
|
.show(ui, |ui| {
|
||||||
|
ui.add_space(7.0);
|
||||||
|
egui::TextEdit::multiline(message_edit)
|
||||||
|
.font(egui::TextStyle::Small)
|
||||||
|
.desired_rows(5)
|
||||||
|
.interactive(self.tx_info_finalize)
|
||||||
|
.hint_text(SLATEPACK_MESSAGE_HINT)
|
||||||
|
.desired_width(f32::INFINITY)
|
||||||
|
.show(ui);
|
||||||
|
ui.add_space(6.0);
|
||||||
|
});
|
||||||
|
ui.add_space(2.0);
|
||||||
|
View::horizontal_line(ui, Colors::ITEM_STROKE);
|
||||||
|
ui.add_space(8.0);
|
||||||
|
|
||||||
|
if self.tx_info_finalize {
|
||||||
|
// Draw paste button.
|
||||||
|
let paste_text = format!("{} {}", CLIPBOARD_TEXT, t!("paste"));
|
||||||
|
View::button(ui, paste_text, Colors::BUTTON, || {
|
||||||
|
self.tx_info_finalize_edit = cb.get_string_from_buffer();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Callback on finalization message input change.
|
||||||
|
if message_before != self.tx_info_finalize_edit {
|
||||||
|
self.on_finalization_input_change(tx, wallet, cb);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Draw copy button.
|
||||||
|
let copy_text = format!("{} {}", COPY, t!("copy"));
|
||||||
|
View::button(ui, copy_text, Colors::BUTTON, || {
|
||||||
|
cb.copy_string_to_buffer(self.tx_info_response_edit.clone());
|
||||||
|
self.tx_info_finalize_edit = "".to_string();
|
||||||
|
if tx.can_finalize {
|
||||||
|
self.tx_info_finalize = true;
|
||||||
|
} else {
|
||||||
|
modal.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse Slatepack message on transaction finalization input change.
|
||||||
|
fn on_finalization_input_change(&mut self,
|
||||||
|
tx: &WalletTransaction,
|
||||||
|
wallet: &Wallet,
|
||||||
|
cb: &dyn PlatformCallbacks) {
|
||||||
|
let message = &self.tx_info_finalize_edit;
|
||||||
|
if message.is_empty() {
|
||||||
|
self.tx_info_finalize_error = false;
|
||||||
|
} else {
|
||||||
|
if let Ok(slate) = wallet.parse_slatepack(message) {
|
||||||
|
let send = slate.state == SlateState::Standard2 &&
|
||||||
|
tx.data.tx_type == TxLogEntryType::TxSent;
|
||||||
|
let receive = slate.state == SlateState::Invoice2 &&
|
||||||
|
tx.data.tx_type == TxLogEntryType::TxReceived;
|
||||||
|
if Some(slate.id) == tx.data.tx_slate_id && (send || receive) {
|
||||||
|
match wallet.finalize(message, wallet.can_use_dandelion()) {
|
||||||
|
Ok(_) => {
|
||||||
|
self.tx_info_finalize = false;
|
||||||
|
self.tx_info_finalize_edit = "".to_string();
|
||||||
|
cb.hide_keyboard();
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
self.tx_info_finalize_error = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.tx_info_finalize_error = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.tx_info_finalize_error = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ use std::sync::Arc;
|
||||||
use grin_keychain::ExtKeychain;
|
use grin_keychain::ExtKeychain;
|
||||||
use grin_util::Mutex;
|
use grin_util::Mutex;
|
||||||
use grin_wallet_impls::{DefaultLCProvider, HTTPNodeClient};
|
use grin_wallet_impls::{DefaultLCProvider, HTTPNodeClient};
|
||||||
use grin_wallet_libwallet::{TxLogEntry, WalletInfo, WalletInst};
|
use grin_wallet_libwallet::{TxLogEntry, TxLogEntryType, WalletInfo, WalletInst};
|
||||||
|
|
||||||
/// Mnemonic phrase setup mode.
|
/// Mnemonic phrase setup mode.
|
||||||
#[derive(PartialEq, Clone)]
|
#[derive(PartialEq, Clone)]
|
||||||
|
@ -149,6 +149,25 @@ pub struct WalletTransaction {
|
||||||
pub amount: u64,
|
pub amount: u64,
|
||||||
/// Flag to check if transaction is posting after finalization.
|
/// Flag to check if transaction is posting after finalization.
|
||||||
pub posting: bool,
|
pub posting: bool,
|
||||||
|
/// Flag to check if transaction can be finalized based on Slatepack message state.
|
||||||
|
pub can_finalize: bool,
|
||||||
/// Last wallet block height of transaction reposting.
|
/// Last wallet block height of transaction reposting.
|
||||||
pub repost_height: Option<u64>
|
pub repost_height: Option<u64>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl WalletTransaction {
|
||||||
|
/// Check if transaction can be cancelled.
|
||||||
|
pub fn can_cancel(&self) -> bool {
|
||||||
|
!self.posting && !self.data.confirmed &&
|
||||||
|
self.data.tx_type != TxLogEntryType::TxReceivedCancelled
|
||||||
|
&& self.data.tx_type != TxLogEntryType::TxSentCancelled
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if transaction can be reposted.
|
||||||
|
pub fn can_repost(&self, data: &WalletData) -> bool {
|
||||||
|
let last_height = data.info.last_confirmed_height;
|
||||||
|
let min_conf = data.info.minimum_confirmations;
|
||||||
|
self.posting && self.repost_height.is_some() &&
|
||||||
|
last_height - self.repost_height.unwrap() > min_conf
|
||||||
|
}
|
||||||
|
}
|
|
@ -479,9 +479,9 @@ impl Wallet {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse Slatepack message into [`Slate`].
|
/// Parse Slatepack message into [`Slate`].
|
||||||
pub fn parse_slatepack(&self, message: String) -> Result<Slate, Error> {
|
pub fn parse_slatepack(&self, message: &String) -> Result<Slate, Error> {
|
||||||
let api = Owner::new(self.instance.clone().unwrap(), None);
|
let api = Owner::new(self.instance.clone().unwrap(), None);
|
||||||
api.slate_from_slatepack_message(None, message, vec![])
|
api.slate_from_slatepack_message(None, message.clone(), vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create Slatepack message from provided slate.
|
/// Create Slatepack message from provided slate.
|
||||||
|
@ -493,7 +493,7 @@ impl Wallet {
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Save slatepack.
|
// Write Slatepack message to file.
|
||||||
let slatepack_dir = self.get_config().get_slatepack_path(&slate);
|
let slatepack_dir = self.get_config().get_slatepack_path(&slate);
|
||||||
let mut output = File::create(slatepack_dir)?;
|
let mut output = File::create(slatepack_dir)?;
|
||||||
output.write_all(message.as_bytes())?;
|
output.write_all(message.as_bytes())?;
|
||||||
|
@ -510,7 +510,51 @@ impl Wallet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get transaction by slate id.
|
/// Get last stored [`Slate`] for transaction.
|
||||||
|
pub fn read_slate_by_tx(&self, tx: &WalletTransaction) -> Option<(Slate, String)> {
|
||||||
|
let mut slate = None;
|
||||||
|
if let Some(slate_id) = tx.data.tx_slate_id {
|
||||||
|
// Get slate state based on tx state and status.
|
||||||
|
let state = if tx.posting {
|
||||||
|
if tx.data.tx_type == TxLogEntryType::TxSent {
|
||||||
|
Some(SlateState::Standard3)
|
||||||
|
} else {
|
||||||
|
Some(SlateState::Invoice3)
|
||||||
|
}
|
||||||
|
} else if !tx.data.confirmed && (tx.data.tx_type == TxLogEntryType::TxSent ||
|
||||||
|
tx.data.tx_type == TxLogEntryType::TxReceived) {
|
||||||
|
if tx.can_finalize {
|
||||||
|
if tx.data.tx_type == TxLogEntryType::TxSent {
|
||||||
|
Some(SlateState::Standard1)
|
||||||
|
} else {
|
||||||
|
Some(SlateState::Invoice1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if tx.data.tx_type == TxLogEntryType::TxReceived {
|
||||||
|
Some(SlateState::Standard2)
|
||||||
|
} else {
|
||||||
|
Some(SlateState::Invoice2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
// Get slate from state by reading Slatepack message file.
|
||||||
|
if let Some(st) = state {
|
||||||
|
let mut s = Slate::blank(0, false);
|
||||||
|
s.id = slate_id;
|
||||||
|
s.state = st;
|
||||||
|
if let Some(m) = self.read_slatepack(&s) {
|
||||||
|
if let Ok(s) = self.parse_slatepack(&m) {
|
||||||
|
slate = Some((s, m));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slate
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get transaction for [`Slate`] id.
|
||||||
pub fn tx_by_slate(&self, slate: &Slate) -> Option<WalletTransaction> {
|
pub fn tx_by_slate(&self, slate: &Slate) -> Option<WalletTransaction> {
|
||||||
if let Some(data) = self.get_data() {
|
if let Some(data) = self.get_data() {
|
||||||
let txs = data.txs.clone().iter().map(|tx| tx.clone()).filter(|tx| {
|
let txs = data.txs.clone().iter().map(|tx| tx.clone()).filter(|tx| {
|
||||||
|
@ -571,7 +615,7 @@ impl Wallet {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle message from the invoice issuer to send founds, return response for funds receiver.
|
/// Handle message from the invoice issuer to send founds, return response for funds receiver.
|
||||||
pub fn pay(&self, message: String) -> Result<String, Error> {
|
pub fn pay(&self, message: &String) -> Result<String, Error> {
|
||||||
let slate = self.parse_slatepack(message)?;
|
let slate = self.parse_slatepack(message)?;
|
||||||
let config = self.get_config();
|
let config = self.get_config();
|
||||||
let args = InitTxArgs {
|
let args = InitTxArgs {
|
||||||
|
@ -595,7 +639,7 @@ impl Wallet {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle message to receive funds, return response to sender.
|
/// Handle message to receive funds, return response to sender.
|
||||||
pub fn receive(&self, message: String) -> Result<String, Error> {
|
pub fn receive(&self, message: &String) -> Result<String, Error> {
|
||||||
let mut slate = self.parse_slatepack(message)?;
|
let mut slate = self.parse_slatepack(message)?;
|
||||||
let api = Owner::new(self.instance.clone().unwrap(), None);
|
let api = Owner::new(self.instance.clone().unwrap(), None);
|
||||||
controller::foreign_single_use(api.wallet_inst.clone(), None, |api| {
|
controller::foreign_single_use(api.wallet_inst.clone(), None, |api| {
|
||||||
|
@ -612,7 +656,7 @@ impl Wallet {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finalize transaction from provided message as sender or invoice issuer with Dandelion.
|
/// Finalize transaction from provided message as sender or invoice issuer with Dandelion.
|
||||||
pub fn finalize(&self, message: String, dandelion: bool) -> Result<Slate, Error> {
|
pub fn finalize(&self, message: &String, dandelion: bool) -> Result<Slate, Error> {
|
||||||
let mut slate = self.parse_slatepack(message)?;
|
let mut slate = self.parse_slatepack(message)?;
|
||||||
let api = Owner::new(self.instance.clone().unwrap(), None);
|
let api = Owner::new(self.instance.clone().unwrap(), None);
|
||||||
slate = api.finalize_tx(None, &slate)?;
|
slate = api.finalize_tx(None, &slate)?;
|
||||||
|
@ -629,7 +673,7 @@ impl Wallet {
|
||||||
// Post transaction to blockchain.
|
// Post transaction to blockchain.
|
||||||
let api = Owner::new(self.instance.clone().unwrap(), None);
|
let api = Owner::new(self.instance.clone().unwrap(), None);
|
||||||
api.post_tx(None, slate, dandelion)?;
|
api.post_tx(None, slate, dandelion)?;
|
||||||
// Setup transaction repost height and posting flag.
|
// Setup transaction repost height, posting flag and ability to finalize.
|
||||||
let mut slate = slate.clone();
|
let mut slate = slate.clone();
|
||||||
if slate.state == SlateState::Invoice2 {
|
if slate.state == SlateState::Invoice2 {
|
||||||
slate.state = SlateState::Invoice3
|
slate.state = SlateState::Invoice3
|
||||||
|
@ -643,6 +687,7 @@ impl Wallet {
|
||||||
if t.data.id == tx.data.id {
|
if t.data.id == tx.data.id {
|
||||||
t.repost_height = Some(data.info.last_confirmed_height);
|
t.repost_height = Some(data.info.last_confirmed_height);
|
||||||
t.posting = true;
|
t.posting = true;
|
||||||
|
t.can_finalize = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*w_data = Some(data);
|
*w_data = Some(data);
|
||||||
|
@ -656,12 +701,13 @@ impl Wallet {
|
||||||
pub fn cancel(&mut self, id: u32) {
|
pub fn cancel(&mut self, id: u32) {
|
||||||
let instance = self.instance.clone().unwrap();
|
let instance = self.instance.clone().unwrap();
|
||||||
let _ = cancel_tx(instance, None, &None, Some(id), None);
|
let _ = cancel_tx(instance, None, &None, Some(id), None);
|
||||||
// Set cancelling status.
|
// Setup cancelling status, posting flag, and ability to finalize.
|
||||||
{
|
|
||||||
let mut w_data = self.data.write().unwrap();
|
let mut w_data = self.data.write().unwrap();
|
||||||
let mut data = w_data.clone().unwrap();
|
let mut data = w_data.clone().unwrap();
|
||||||
let txs = data.txs.iter_mut().map(|tx| {
|
let txs = data.txs.iter_mut().map(|tx| {
|
||||||
if tx.data.id == id {
|
if tx.data.id == id {
|
||||||
|
tx.posting = false;
|
||||||
|
tx.can_finalize = false;
|
||||||
tx.data.tx_type = if tx.data.tx_type == TxLogEntryType::TxReceived {
|
tx.data.tx_type = if tx.data.tx_type == TxLogEntryType::TxReceived {
|
||||||
TxLogEntryType::TxReceivedCancelled
|
TxLogEntryType::TxReceivedCancelled
|
||||||
} else {
|
} else {
|
||||||
|
@ -672,7 +718,6 @@ impl Wallet {
|
||||||
}).collect::<Vec<WalletTransaction>>();
|
}).collect::<Vec<WalletTransaction>>();
|
||||||
data.txs = txs;
|
data.txs = txs;
|
||||||
*w_data = Some(data);
|
*w_data = Some(data);
|
||||||
}
|
|
||||||
// Refresh wallet info to update statuses.
|
// Refresh wallet info to update statuses.
|
||||||
self.sync();
|
self.sync();
|
||||||
}
|
}
|
||||||
|
@ -995,7 +1040,6 @@ fn sync_wallet_data(wallet: &Wallet) {
|
||||||
// Create wallet txs.
|
// Create wallet txs.
|
||||||
let mut new_txs: Vec<WalletTransaction> = vec![];
|
let mut new_txs: Vec<WalletTransaction> = vec![];
|
||||||
for tx in &filter_txs {
|
for tx in &filter_txs {
|
||||||
println!("{}", serde_json::to_string(tx).unwrap());
|
|
||||||
// Setup transaction amount.
|
// Setup transaction amount.
|
||||||
let amount = if tx.amount_debited > tx.amount_credited {
|
let amount = if tx.amount_debited > tx.amount_credited {
|
||||||
tx.amount_debited - tx.amount_credited
|
tx.amount_debited - tx.amount_credited
|
||||||
|
@ -1003,15 +1047,20 @@ fn sync_wallet_data(wallet: &Wallet) {
|
||||||
tx.amount_credited - tx.amount_debited
|
tx.amount_credited - tx.amount_debited
|
||||||
};
|
};
|
||||||
|
|
||||||
// Setup transaction posting flag based on slate state.
|
let unconfirmed_sent_or_received = tx.tx_slate_id.is_some() &&
|
||||||
let posting = if (tx.tx_type == TxLogEntryType::TxSent ||
|
!tx.confirmed && (tx.tx_type == TxLogEntryType::TxSent ||
|
||||||
tx.tx_type == TxLogEntryType::TxReceived) &&
|
tx.tx_type == TxLogEntryType::TxReceived);
|
||||||
!tx.confirmed && tx.tx_slate_id.is_some() {
|
|
||||||
|
// Setup transaction posting status based on slate state.
|
||||||
|
let posting = if unconfirmed_sent_or_received {
|
||||||
|
println!("{}", serde_json::to_string(tx).unwrap());
|
||||||
|
|
||||||
// Create slate to check existing file.
|
// Create slate to check existing file.
|
||||||
let mut slate = Slate::blank(1, false);
|
let is_invoice = tx.tx_type == TxLogEntryType::TxReceived;
|
||||||
|
let mut slate = Slate::blank(0, is_invoice);
|
||||||
slate.id = tx.tx_slate_id.unwrap();
|
slate.id = tx.tx_slate_id.unwrap();
|
||||||
slate.state = match tx.tx_type {
|
slate.state = match is_invoice {
|
||||||
TxLogEntryType::TxReceived => SlateState::Invoice3,
|
true => SlateState::Invoice3,
|
||||||
_ => SlateState::Standard3
|
_ => SlateState::Standard3
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1033,6 +1082,20 @@ fn sync_wallet_data(wallet: &Wallet) {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Setup flag for ability to finalize transaction.
|
||||||
|
let can_finalize = if !posting && unconfirmed_sent_or_received {
|
||||||
|
// Create slate to check existing file.
|
||||||
|
let mut slate = Slate::blank(1, false);
|
||||||
|
slate.id = tx.tx_slate_id.unwrap();
|
||||||
|
slate.state = match tx.tx_type {
|
||||||
|
TxLogEntryType::TxReceived => SlateState::Invoice1,
|
||||||
|
_ => SlateState::Standard1
|
||||||
|
};
|
||||||
|
wallet.read_slatepack(&slate).is_some()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
// Setup reposting height.
|
// Setup reposting height.
|
||||||
let mut repost_height = None;
|
let mut repost_height = None;
|
||||||
if posting {
|
if posting {
|
||||||
|
@ -1046,10 +1109,12 @@ fn sync_wallet_data(wallet: &Wallet) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add transaction to list.
|
||||||
new_txs.push(WalletTransaction {
|
new_txs.push(WalletTransaction {
|
||||||
data: tx.clone(),
|
data: tx.clone(),
|
||||||
amount,
|
amount,
|
||||||
posting,
|
posting,
|
||||||
|
can_finalize,
|
||||||
repost_height,
|
repost_height,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue