Skip to content

Commit 76ebc11

Browse files
committed
installer: add existing wallet from backup
1 parent d18ba8c commit 76ebc11

File tree

6 files changed

+139
-19
lines changed

6 files changed

+139
-19
lines changed

liana-gui/src/app/settings.rs

+12
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,18 @@ pub struct KeySetting {
116116
pub master_fingerprint: Fingerprint,
117117
}
118118

119+
impl KeySetting {
120+
pub fn from_map(value: HashMap<Fingerprint, String>) -> Vec<Self> {
121+
value
122+
.into_iter()
123+
.map(|(k, v)| KeySetting {
124+
name: v,
125+
master_fingerprint: k,
126+
})
127+
.collect()
128+
}
129+
}
130+
119131
#[derive(PartialEq, Eq, Debug, Clone)]
120132
pub enum SettingsError {
121133
NotFound,

liana-gui/src/export.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -195,11 +195,11 @@ pub enum ImportExportType {
195195
Option<SyncSender<bool>>, /*overwrite_labels*/
196196
Option<SyncSender<bool>>, /*overwrite_aliases*/
197197
),
198+
WalletFromBackup,
198199
Descriptor(LianaDescriptor),
199200
ExportLabels,
200201
ImportPsbt,
201202
ImportDescriptor,
202-
WalletFromBackup,
203203
}
204204

205205
impl PartialEq for ImportExportType {
@@ -301,7 +301,6 @@ impl Export {
301301
path: PathBuf,
302302
) {
303303
match export_type {
304-
ImportExportType::WalletFromBackup => wallet_from_backup(sender, path).await,
305304
ImportExportType::Transactions => export_transactions(sender, daemon, path).await,
306305
ImportExportType::ExportPsbt(str) => export_string(sender, path, str),
307306
ImportExportType::Descriptor(descriptor) => export_descriptor(sender, path, descriptor),
@@ -310,6 +309,7 @@ impl Export {
310309
ImportExportType::ImportDescriptor => import_descriptor(sender, path),
311310
ImportExportType::ExportBackup(str) => export_string(sender, path, str),
312311
ImportExportType::ImportBackup(..) => import_backup(sender, path, daemon).await,
312+
ImportExportType::WalletFromBackup => wallet_from_backup(sender, path).await,
313313
};
314314
}
315315

liana-gui/src/installer/message.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ use liana::miniscript::{
22
bitcoin::{bip32::Fingerprint, Network},
33
DescriptorPublicKey,
44
};
5-
use std::path::PathBuf;
5+
use std::{collections::HashMap, path::PathBuf};
66

77
use super::{context, Error};
88
use crate::{
99
app::view::Close,
10-
backup,
10+
backup::{self, Backup},
1111
download::{DownloadError, Progress},
1212
export::ImportExportMessage,
1313
hw::HardwareWalletMessage,
@@ -50,6 +50,8 @@ pub enum Message {
5050
BackupWallet,
5151
ExportWallet(Result<String, backup::Error>),
5252
ImportExport(ImportExportMessage),
53+
ImportBackup,
54+
WalletFromBackup((HashMap<Fingerprint, String>, Backup)),
5355
}
5456

5557
impl Close for Message {

liana-gui/src/installer/mod.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ use std::sync::{Arc, Mutex};
2121
use crate::{
2222
app::{
2323
config as gui_config,
24-
settings::{self as gui_settings, AuthConfig, Settings, SettingsError, WalletSetting},
24+
settings::{
25+
self as gui_settings, AuthConfig, KeySetting, Settings, SettingsError, WalletSetting,
26+
},
2527
wallet::wallet_name,
2628
},
2729
backup,
@@ -286,6 +288,11 @@ impl Installer {
286288
.expect("There is always a step")
287289
.update(&mut self.hws, Message::Installed(Err(e)), &self.context)
288290
}
291+
Message::WalletFromBackup((aliases, backup)) => {
292+
self.context.keys = KeySetting::from_map(aliases);
293+
self.context.backup = Some(backup);
294+
Task::none()
295+
}
289296
_ => self
290297
.steps
291298
.get_mut(self.current)

liana-gui/src/installer/step/descriptor/mod.rs

+61-10
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use async_hwi::DeviceKind;
1818
use crate::{
1919
app::{state::export::ExportModal, wallet::wallet_name},
2020
backup::{self, Backup},
21-
export::{ImportExportMessage, ImportExportType},
21+
export::{ImportExportMessage, ImportExportType, Progress},
2222
hw::{HardwareWallet, HardwareWallets},
2323
installer::{
2424
message::{self, Message},
@@ -32,6 +32,8 @@ pub struct ImportDescriptor {
3232
imported_descriptor: form::Value<String>,
3333
wrong_network: bool,
3434
error: Option<String>,
35+
modal: Option<ExportModal>,
36+
imported_backup: bool,
3537
}
3638

3739
impl ImportDescriptor {
@@ -41,6 +43,8 @@ impl ImportDescriptor {
4143
imported_descriptor: form::Value::default(),
4244
wrong_network: false,
4345
error: None,
46+
modal: None,
47+
imported_backup: false,
4448
}
4549
}
4650

@@ -77,19 +81,60 @@ impl Step for ImportDescriptor {
7781
fn skip(&self, ctx: &Context) -> bool {
7882
ctx.remote_backend.is_some()
7983
}
80-
// form value is set as valid each time it is edited.
81-
// Verification of the values is happening when the user click on Next button.
84+
85+
fn subscription(&self, _hws: &HardwareWallets) -> Subscription<Message> {
86+
if let Some(modal) = &self.modal {
87+
if let Some(sub) = modal.subscription() {
88+
sub.map(|m| Message::ImportExport(ImportExportMessage::Progress(m)))
89+
} else {
90+
Subscription::none()
91+
}
92+
} else {
93+
Subscription::none()
94+
}
95+
}
96+
8297
fn update(
8398
&mut self,
8499
_hws: &mut HardwareWallets,
85100
message: Message,
86101
_ctx: &Context,
87102
) -> Task<Message> {
88-
if let Message::DefineDescriptor(message::DefineDescriptor::ImportDescriptor(desc)) =
89-
message
90-
{
91-
self.imported_descriptor.value = desc;
92-
self.check_descriptor(self.network);
103+
match message {
104+
Message::DefineDescriptor(message::DefineDescriptor::ImportDescriptor(desc)) => {
105+
self.imported_descriptor.value = desc;
106+
self.check_descriptor(self.network);
107+
}
108+
Message::ImportExport(ImportExportMessage::Close) => {
109+
self.modal = None;
110+
}
111+
Message::ImportBackup => {
112+
if !self.imported_backup {
113+
let modal = ExportModal::new(None, ImportExportType::WalletFromBackup);
114+
let launch = modal.launch(false);
115+
self.modal = Some(modal);
116+
return launch;
117+
}
118+
}
119+
Message::ImportExport(ImportExportMessage::Progress(Progress::WalletFromBackup(r))) => {
120+
let (descriptor, network, aliases, backup) = r;
121+
if self.network == network {
122+
self.imported_backup = true;
123+
self.imported_descriptor.value = descriptor.to_string();
124+
return Task::perform(async move { (aliases, backup) }, |(a, b)| {
125+
Message::WalletFromBackup((a, b))
126+
});
127+
} else {
128+
self.error = Some("Backup network do not match the selected network!".into());
129+
}
130+
}
131+
Message::ImportExport(m) => {
132+
if let Some(modal) = self.modal.as_mut() {
133+
let task: Task<Message> = modal.update(m);
134+
return task;
135+
};
136+
}
137+
_ => {}
93138
}
94139
Task::none()
95140
}
@@ -113,13 +158,19 @@ impl Step for ImportDescriptor {
113158
progress: (usize, usize),
114159
email: Option<&'a str>,
115160
) -> Element<Message> {
116-
view::import_descriptor(
161+
let content = view::import_descriptor(
117162
progress,
118163
email,
119164
&self.imported_descriptor,
165+
self.imported_backup,
120166
self.wrong_network,
121167
self.error.as_ref(),
122-
)
168+
);
169+
if let Some(modal) = &self.modal {
170+
modal.view(content)
171+
} else {
172+
content
173+
}
123174
}
124175
}
125176

liana-gui/src/installer/view/mod.rs

+52-4
Original file line numberDiff line numberDiff line change
@@ -262,11 +262,15 @@ pub fn import_descriptor<'a>(
262262
progress: (usize, usize),
263263
email: Option<&'a str>,
264264
imported_descriptor: &form::Value<String>,
265+
imported_backup: bool,
265266
wrong_network: bool,
266267
error: Option<&String>,
267268
) -> Element<'a, Message> {
269+
let valid = !imported_descriptor.value.is_empty() && imported_descriptor.valid;
270+
268271
let col_descriptor = Column::new()
269272
.push(text("Descriptor:").bold())
273+
.push(Space::with_height(10))
270274
.push(
271275
form::Form::new_trimmed("Descriptor", imported_descriptor, |msg| {
272276
Message::DefineDescriptor(message::DefineDescriptor::ImportDescriptor(msg))
@@ -278,21 +282,65 @@ pub fn import_descriptor<'a>(
278282
})
279283
.size(text::P1_SIZE)
280284
.padding(10),
285+
);
286+
287+
let descriptor = if imported_backup {
288+
None
289+
} else {
290+
Some(col_descriptor)
291+
};
292+
293+
let or = if !valid && !imported_backup {
294+
Some(
295+
Row::new()
296+
.push(text("or").bold())
297+
.push(Space::with_width(Length::Fill)),
281298
)
282-
.spacing(10);
299+
} else {
300+
None
301+
};
302+
303+
let import_backup = if !valid && !imported_backup {
304+
Some(
305+
Row::new()
306+
.push(button::secondary(None, "Import backup").on_press(Message::ImportBackup))
307+
.push(Space::with_width(Length::Fill)),
308+
)
309+
} else {
310+
None
311+
};
312+
313+
let backup_imported = if imported_backup {
314+
Some(
315+
Row::new()
316+
.push(text("Backup successfuly imported!").bold())
317+
.push(Space::with_width(Length::Fill)),
318+
)
319+
} else {
320+
None
321+
};
322+
283323
layout(
284324
progress,
285325
email,
286326
"Import the wallet",
287327
Column::new()
288-
.push(Column::new().spacing(20).push(col_descriptor).push(text(
289-
"If you are using a Bitcoin Core node, \
328+
.push(
329+
Column::new()
330+
.spacing(20)
331+
.push_maybe(descriptor)
332+
.push_maybe(or)
333+
.push_maybe(import_backup)
334+
.push_maybe(backup_imported)
335+
.push(text(
336+
"If you are using a Bitcoin Core node, \
290337
you will need to perform a rescan of \
291338
the blockchain after creating the wallet \
292339
in order to see your coins and past \
293340
transactions. This can be done in \
294341
Settings > Node.",
295-
)))
342+
)),
343+
)
296344
.push(
297345
if imported_descriptor.value.is_empty() || !imported_descriptor.valid {
298346
button::secondary(None, "Next").width(Length::Fixed(200.0))

0 commit comments

Comments
 (0)