From 789c2aebfb3731b43b9d1750d5586db1456c14fc Mon Sep 17 00:00:00 2001 From: edouardparis Date: Tue, 29 Oct 2024 17:45:16 +0100 Subject: [PATCH 1/3] Add new template: multisig security wallet --- gui/src/installer/context.rs | 1 + gui/src/installer/message.rs | 3 +- .../installer/step/descriptor/editor/key.rs | 30 +-- .../installer/step/descriptor/editor/mod.rs | 120 ++++++--- .../step/descriptor/editor/template.rs | 5 +- gui/src/installer/view/editor/mod.rs | 5 +- gui/src/installer/view/editor/template/mod.rs | 20 ++ .../template/multisig_security_wallet.rs | 240 ++++++++++++++++++ gui/ui/src/image.rs | 8 + .../images/multisig_security_template.svg | 45 ++++ 10 files changed, 422 insertions(+), 55 deletions(-) create mode 100644 gui/src/installer/view/editor/template/multisig_security_wallet.rs create mode 100644 gui/ui/static/images/multisig_security_template.svg diff --git a/gui/src/installer/context.rs b/gui/src/installer/context.rs index 2abf2140..3dab5185 100644 --- a/gui/src/installer/context.rs +++ b/gui/src/installer/context.rs @@ -50,6 +50,7 @@ pub enum DescriptorTemplate { #[default] SimpleInheritance, Custom, + MultisigSecurity, } #[derive(Clone)] diff --git a/gui/src/installer/message.rs b/gui/src/installer/message.rs index b9c4a63c..96f5acd1 100644 --- a/gui/src/installer/message.rs +++ b/gui/src/installer/message.rs @@ -113,6 +113,8 @@ pub enum InternalBitcoindMsg { pub enum DefineDescriptor { ChangeTemplate(context::DescriptorTemplate), ImportDescriptor(String), + KeysEdited(Vec<(usize, usize)>, Key), + KeysEdit(Vec<(usize, usize)>), Path(usize, DefinePath), AddRecoveryPath, KeyModal(ImportKeyModal), @@ -136,7 +138,6 @@ pub enum DefineKey { Delete, Edit, Clipboard(String), - Edited(Key), } #[derive(Debug, Clone)] diff --git a/gui/src/installer/step/descriptor/editor/key.rs b/gui/src/installer/step/descriptor/editor/key.rs index 6444e46d..e4a6ac82 100644 --- a/gui/src/installer/step/descriptor/editor/key.rs +++ b/gui/src/installer/step/descriptor/editor/key.rs @@ -74,8 +74,7 @@ pub fn check_key_network(key: &DescriptorPublicKey, network: Network) -> bool { pub struct EditXpubModal { device_must_support_tapminiscript: bool, - path_index: usize, - key_index: usize, + keys_coordinate: Vec<(usize, usize)>, network: Network, error: Option, processing: bool, @@ -99,8 +98,7 @@ impl EditXpubModal { device_must_support_tapminiscript: bool, other_path_keys: HashSet, key: Option, - path_index: usize, - key_index: usize, + keys_coordinate: Vec<(usize, usize)>, network: Network, hot_signer: Arc>, hot_signer_fingerprint: Fingerprint, @@ -128,8 +126,7 @@ impl EditXpubModal { }, manually_imported_xpub, keys, - path_index, - key_index, + keys_coordinate, processing: false, error: None, network, @@ -304,22 +301,15 @@ impl super::DescriptorEditModal for EditXpubModal { } message::ImportKeyModal::ConfirmXpub => { if let Some(mut key) = self.chosen_signer.clone() { - let key_index = self.key_index; key.name.clone_from(&self.form_name.value); if self.other_path_keys.contains(&key.fingerprint) { self.duplicate_master_fg = true; } else { - let path_index = self.path_index; + let coordinate = self.keys_coordinate.clone(); return Command::perform( - async move { (path_index, key_index, key) }, - move |(path_index, key_index, key)| { - message::DefineDescriptor::Path( - path_index, - message::DefinePath::Key( - key_index, - message::DefineKey::Edited(key), - ), - ) + async move { (coordinate, key) }, + move |(coordinate, key)| { + message::DefineDescriptor::KeysEdited(coordinate, key) }, ) .map(Message::DefineDescriptor); @@ -346,11 +336,7 @@ impl super::DescriptorEditModal for EditXpubModal { fn view<'a>(&'a self, hws: &'a HardwareWallets) -> Element<'a, Message> { let chosen_signer = self.chosen_signer.as_ref().map(|s| s.fingerprint); view::editor::edit_key_modal( - if self.path_index > 0 { - "Set your key" - } else { - "Set your primary key" - }, + "Set your key", self.network, hws.list .iter() diff --git a/gui/src/installer/step/descriptor/editor/mod.rs b/gui/src/installer/step/descriptor/editor/mod.rs index cef52399..e2023b78 100644 --- a/gui/src/installer/step/descriptor/editor/mod.rs +++ b/gui/src/installer/step/descriptor/editor/mod.rs @@ -74,6 +74,23 @@ impl Path { } } + pub fn with_n_keys(mut self, n: usize) -> Self { + self.keys = Vec::new(); + for _i in 0..n { + self.keys.push(None); + } + self + } + + pub fn with_threshold(mut self, t: usize) -> Self { + self.threshold = if t > self.keys.len() { + self.keys.len() + } else { + t + }; + self + } + fn valid(&self) -> bool { !self.keys.is_empty() && !self.keys.iter().any(|k| k.is_none()) && !self.duplicate_sequence } @@ -164,6 +181,12 @@ impl DefineDescriptor { DescriptorTemplate::SimpleInheritance => { self.paths = vec![Path::new_primary_path(), Path::new_recovery_path()]; } + DescriptorTemplate::MultisigSecurity => { + self.paths = vec![ + Path::new_primary_path().with_n_keys(2).with_threshold(2), + Path::new_recovery_path().with_n_keys(3).with_threshold(2), + ]; + } DescriptorTemplate::Custom => { self.paths = vec![Path::new_primary_path(), Path::new_recovery_path()]; } @@ -195,6 +218,46 @@ impl Step for DefineDescriptor { Message::DefineDescriptor(message::DefineDescriptor::AddRecoveryPath) => { self.paths.push(Path::new_recovery_path()); } + Message::DefineDescriptor(message::DefineDescriptor::KeysEdited(coordinate, key)) => { + hws.set_alias(key.fingerprint, key.name.clone()); + for (i, j) in coordinate { + self.paths[i].keys[j] = Some(key.fingerprint); + } + self.keys.insert(key.fingerprint, key); + self.modal = None; + self.check_setup(); + } + Message::DefineDescriptor(message::DefineDescriptor::KeysEdit(coordinate)) => { + let use_taproot = self.use_taproot; + let mut set = HashSet::::new(); + let key = coordinate + .first() + .and_then(|(i, j)| self.paths[*i].keys[*j]) + .and_then(|f| self.keys.get(&f)) + .cloned(); + for (i, j) in &coordinate { + set.extend(self.paths[*i].keys.iter().filter_map(|key| { + if key.is_some() && key != &self.paths[*i].keys[*j] { + *key + } else { + None + } + })); + } + let modal = EditXpubModal::new( + use_taproot, + set, + key, + coordinate, + self.network, + self.signer.clone(), + self.signer_fingerprint, + self.keys.values().cloned().collect(), + ); + let cmd = modal.load(); + self.modal = Some(Box::new(modal)); + return cmd; + } Message::DefineDescriptor(message::DefineDescriptor::Path(i, msg)) => match msg { message::DefinePath::SequenceEdited(seq) => { self.modal = None; @@ -233,13 +296,7 @@ impl Step for DefineDescriptor { message::DefineKey::Clipboard(key) => { return Command::perform(async move { key }, Message::Clibpboard); } - message::DefineKey::Edited(key) => { - hws.set_alias(key.fingerprint, key.name.clone()); - self.paths[i].keys[j] = Some(key.fingerprint); - self.keys.insert(key.fingerprint, key); - self.modal = None; - self.check_setup(); - } + message::DefineKey::Edit => { let use_taproot = self.use_taproot; let path = &self.paths[i]; @@ -253,8 +310,7 @@ impl Step for DefineDescriptor { } })), path.keys[j].and_then(|f| self.keys.get(&f)).cloned(), - i, - j, + vec![(i, j)], self.network, self.signer.clone(), self.signer_fingerprint, @@ -424,6 +480,17 @@ impl Step for DefineDescriptor { self.valid(), ) } + DescriptorTemplate::MultisigSecurity => { + view::editor::template::multisig_security_wallet::multisig_security_template( + progress, + self.use_taproot, + self.path_keys(&self.paths[0]), + self.path_keys(&self.paths[1]), + self.paths[1].sequence, + self.paths[1].threshold, + self.valid(), + ) + } DescriptorTemplate::Custom => view::editor::template::custom::custom_template( progress, self.use_taproot, @@ -714,25 +781,21 @@ mod tests { sandbox.load(&ctx).await; let key = DescriptorPublicKey::from_str("[4df3f0e3/84'/0'/0']tpubDDRs9DnRUiJc4hq92PSJKhfzQBgHJUrDo7T2i48smsDfLsQcm3Vh7JhuGqJv8zozVkNFin8YPgpmn2NWNmpRaE3GW2pSxbmAzYf2juy7LeW").unwrap(); - let specter_key = message::DefinePath::Key( - 0, - message::DefineKey::Edited(Key { - name: "My Specter key".to_string(), - fingerprint: key.master_fingerprint(), - key, - device_kind: Some(async_hwi::DeviceKind::Specter), - device_version: None, - is_compatible_taproot: false, - is_hot_signer: false, - }), - ); + let specter_key = Key { + name: "My Specter key".to_string(), + fingerprint: key.master_fingerprint(), + key, + device_kind: Some(async_hwi::DeviceKind::Specter), + device_version: None, + is_compatible_taproot: false, + is_hot_signer: false, + }; // Use Specter device for primary key sandbox - .update(Message::DefineDescriptor(message::DefineDescriptor::Path( - 0, - specter_key.clone(), - ))) + .update(Message::DefineDescriptor( + message::DefineDescriptor::KeysEdited(vec![(0, 0)], specter_key.clone()), + )) .await; // Edit recovery key @@ -795,10 +858,9 @@ mod tests { // Now edit the recovery key to use Specter device sandbox - .update(Message::DefineDescriptor(message::DefineDescriptor::Path( - 1, - specter_key.clone(), - ))) + .update(Message::DefineDescriptor( + message::DefineDescriptor::KeysEdited(vec![(1, 0)], specter_key.clone()), + )) .await; sandbox.check(|step| { assert!((step).apply(&mut ctx)); diff --git a/gui/src/installer/step/descriptor/editor/template.rs b/gui/src/installer/step/descriptor/editor/template.rs index 53243fd7..4b9aee01 100644 --- a/gui/src/installer/step/descriptor/editor/template.rs +++ b/gui/src/installer/step/descriptor/editor/template.rs @@ -73,7 +73,10 @@ impl Step for DescriptorTemplateDescription { DescriptorTemplate::SimpleInheritance => { view::editor::template::inheritance::inheritance_template_description(progress) } - DescriptorTemplate::Custom { .. } => { + DescriptorTemplate::MultisigSecurity => { + view::editor::template::multisig_security_wallet::multisig_security_template_description(progress) + } + DescriptorTemplate::Custom => { view::editor::template::custom::custom_template_description(progress) } } diff --git a/gui/src/installer/view/editor/mod.rs b/gui/src/installer/view/editor/mod.rs index a2ad333e..ff495336 100644 --- a/gui/src/installer/view/editor/mod.rs +++ b/gui/src/installer/view/editor/mod.rs @@ -6,6 +6,7 @@ use iced::{Alignment, Length}; use liana::miniscript::bitcoin::Network; use liana_ui::component::text::{self, h3, p1_bold, p2_regular, H3_SIZE}; use liana_ui::image; +use std::borrow::Cow; use std::str::FromStr; use liana::miniscript::bitcoin::{self, bip32::Fingerprint}; @@ -130,7 +131,7 @@ pub fn path( pub fn defined_key<'a>( alias: &'a str, color: iced::Color, - title: &'static str, + title: impl Into>, warning: Option<&'static str>, fixed: bool, ) -> Element<'a, message::DefineKey> { @@ -177,7 +178,7 @@ pub fn defined_key<'a>( pub fn undefined_key<'a>( color: iced::Color, - title: &'static str, + title: impl Into>, active: bool, fixed: bool, ) -> Element<'a, message::DefineKey> { diff --git a/gui/src/installer/view/editor/template/mod.rs b/gui/src/installer/view/editor/template/mod.rs index 38482e3f..90f6ab6f 100644 --- a/gui/src/installer/view/editor/template/mod.rs +++ b/gui/src/installer/view/editor/template/mod.rs @@ -1,5 +1,6 @@ pub mod custom; pub mod inheritance; +pub mod multisig_security_wallet; use iced::{alignment, Alignment, Length}; @@ -47,6 +48,25 @@ pub fn choose_descriptor_template(progress: (usize, usize)) -> Element<'static, ) .width(Length::Fill), ) + .push( + card::simple( + Row::new() + .align_items(Alignment::Center) + .push( + Column::new() + .align_items(Alignment::Start) + .push(h3("Multisig security wallet")) + .push(p2_regular("A secure scheme requiring stricter multiparty signature and recovery.").style(color::GREY_2)) + .width(Length::Fill) + ) + .push(button::secondary(None, "Select").on_press( + Message::SelectDescriptorTemplate( + context::DescriptorTemplate::MultisigSecurity, + ), + )), + ) + .width(Length::Fill), + ) .push( card::simple( Row::new() diff --git a/gui/src/installer/view/editor/template/multisig_security_wallet.rs b/gui/src/installer/view/editor/template/multisig_security_wallet.rs new file mode 100644 index 00000000..539b02d1 --- /dev/null +++ b/gui/src/installer/view/editor/template/multisig_security_wallet.rs @@ -0,0 +1,240 @@ +use iced::{alignment, widget::Space, Alignment, Length}; + +use liana_ui::{ + color, + component::{ + button, collapse, + text::{h3, p1_regular, text, Text, H3_SIZE}, + }, + icon, image, theme, + widget::*, +}; + +use crate::installer::{ + context, + message::{self, Message}, + step::descriptor::editor::key::Key, + view::{ + editor::{define_descriptor_advanced_settings, defined_key, path, undefined_key}, + layout, + }, +}; + +pub fn multisig_security_template_description( + progress: (usize, usize), +) -> Element<'static, Message> { + layout( + progress, + None, + "Introduction", + Column::new() + .align_items(Alignment::Start) + .push(h3("Multisig security wallet")) + .max_width(800.0) + .push(Container::new( + p1_regular("For this setup you will need 3 keys: two Primary Keys and a Recovery Key. For security reasons, we suggest you use 3 Hardware Wallets to store them.") + .style(color::GREY_2) + .horizontal_alignment(alignment::Horizontal::Left) + ).align_x(alignment::Horizontal::Left).width(Length::Fill)) + .push(Row::new() + .spacing(30) + .push( + Row::new() + .align_items(Alignment::Center) + .spacing(10) + .push(icon::round_key_icon().size(H3_SIZE).style(color::GREEN)) + .push(p1_regular("Primary key #1").bold()) + ).push( + Row::new() + .align_items(Alignment::Center) + .spacing(10) + .push(icon::round_key_icon().size(H3_SIZE).style(color::GREEN)) + .push(p1_regular("Primary key #2").bold()) + ).push( + Row::new() + .align_items(Alignment::Center) + .spacing(10) + .push(icon::round_key_icon().size(H3_SIZE).style(color::ORANGE)) + .push(p1_regular("Recovery key").bold()) + )) + .push(Container::new( + p1_regular("The Primary Keys will compose a 2-of-2 multisig which will be your always-active spending policy. In case one of your keys becomes unavailable, after a period of inactivity you will be able to recover your funds using the Recovery Key together with one of your Primary Keys (2-of-3 multisig):") + .style(color::GREY_2) + .horizontal_alignment(alignment::Horizontal::Left) + ).align_x(alignment::Horizontal::Left).width(Length::Fill)) + .push(image::multisig_security_template_description().width(Length::Fill)) + .push(Row::new().push(Space::with_width(Length::Fill)).push(button::primary(None, "Select").width(Length::Fixed(200.0)).on_press(Message::Next))) + .spacing(20), + true, + Some(Message::Previous), + ) +} + +pub fn multisig_security_template<'a>( + progress: (usize, usize), + use_taproot: bool, + primary_keys: Vec>, + recovery_keys: Vec>, + sequence: u16, + threshold: usize, + valid: bool, +) -> Element<'a, Message> { + layout( + progress, + None, + "Set keys", + Column::new() + .align_items(Alignment::Start) + .max_width(1000.0) + .push(collapse::Collapse::new( + || { + Button::new( + Row::new() + .align_items(Alignment::Center) + .spacing(10) + .push(text("Advanced settings").small().bold()) + .push(icon::collapse_icon()), + ) + .style(theme::Button::Transparent) + }, + || { + Button::new( + Row::new() + .align_items(Alignment::Center) + .spacing(10) + .push(text("Advanced settings").small().bold()) + .push(icon::collapsed_icon()), + ) + .style(theme::Button::Transparent) + }, + move || define_descriptor_advanced_settings(use_taproot), + )) + .push( + path( + color::GREEN, + None, + 0, + false, + primary_keys.len(), + primary_keys + .iter() + .enumerate() + .map(|(i, primary_key)| { + if let Some(key) = primary_key { + defined_key( + &key.name, + color::GREEN, + format!("Primary key #{}", i + 1), + if use_taproot && !key.is_compatible_taproot { + Some("Key is not compatible with taproot") + } else { + None + }, + true, + ) + } else { + undefined_key( + color::GREEN, + format!("Primary key #{}", i + 1), + !primary_keys[0..i].iter().any(|k| k.is_none()), + true, + ) + } + .map(move |msg| message::DefinePath::Key(i, msg)) + }) + .collect(), + true, + ) + .map(move |msg| { + if let message::DefinePath::Key(i, message::DefineKey::Edit) = msg { + Message::DefineDescriptor(message::DefineDescriptor::KeysEdit(vec![ + (0, i), + (1, i), + ])) + } else { + Message::DefineDescriptor(message::DefineDescriptor::Path(0, msg)) + } + }), + ) + .push( + path( + color::ORANGE, + None, + sequence, + false, + threshold, + recovery_keys + .iter() + .enumerate() + .map(|(j, recovery_key)| { + if let Some(key) = recovery_key { + defined_key( + &key.name, + if j < 2 { color::GREEN } else { color::ORANGE }, + if j < 2 { + format!("Primary key #{}", j + 1) + } else { + "Recovery key".to_string() + }, + if use_taproot && !key.is_compatible_taproot { + Some("Key is not compatible with Taproot") + } else { + None + }, + true, + ) + } else { + undefined_key( + if j < 2 { color::GREEN } else { color::ORANGE }, + if j < 2 { + format!("Primary key #{}", j + 1) + } else { + "Recovery key".to_string() + }, + !(primary_keys.iter().any(|k| k.is_none()) + || recovery_keys[0..j].iter().any(|k| k.is_none())), + true, + ) + } + .map(move |msg| message::DefinePath::Key(j, msg)) + }) + .collect(), + true, + ) + .map(move |msg| { + if let message::DefinePath::Key(i, message::DefineKey::Edit) = msg { + Message::DefineDescriptor(message::DefineDescriptor::KeysEdit(if i < 2 { + vec![(0, i), (1, i)] + } else { + // recovery path is the path with three keys + vec![(1, i)] + })) + } else { + Message::DefineDescriptor(message::DefineDescriptor::Path(1, msg)) + } + }), + ) + .push( + Row::new() + .push( + button::secondary(None, "Customize") + .width(Length::Fixed(200.0)) + .on_press(Message::DefineDescriptor( + message::DefineDescriptor::ChangeTemplate( + context::DescriptorTemplate::Custom, + ), + )), + ) + .push(Space::with_width(Length::Fill)) + .push( + button::primary(None, "Continue") + .width(Length::Fixed(200.0)) + .on_press_maybe(if valid { Some(Message::Next) } else { None }), + ), + ) + .push(Space::with_height(100.0)) + .spacing(20), + true, + Some(Message::Previous), + ) +} diff --git a/gui/ui/src/image.rs b/gui/ui/src/image.rs index ed4b8bae..a690bbae 100644 --- a/gui/ui/src/image.rs +++ b/gui/ui/src/image.rs @@ -75,3 +75,11 @@ pub fn custom_template_description() -> Svg { let h = Handle::from_memory(CUSTOM_TEMPLATE_DESC.to_vec()); Svg::new(h) } + +const MULTISIG_SECURITY_TEMPLATE_DESC: &[u8] = + include_bytes!("../static/images/multisig_security_template.svg"); + +pub fn multisig_security_template_description() -> Svg { + let h = Handle::from_memory(MULTISIG_SECURITY_TEMPLATE_DESC.to_vec()); + Svg::new(h) +} diff --git a/gui/ui/static/images/multisig_security_template.svg b/gui/ui/static/images/multisig_security_template.svg new file mode 100644 index 00000000..15cd8702 --- /dev/null +++ b/gui/ui/static/images/multisig_security_template.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 2eddbbd7000ccb8e392a3da4fd854651bf604a80 Mon Sep 17 00:00:00 2001 From: edouardparis Date: Tue, 29 Oct 2024 18:19:43 +0100 Subject: [PATCH 2/3] change wording in inheritance template --- .../view/editor/template/inheritance.rs | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/gui/src/installer/view/editor/template/inheritance.rs b/gui/src/installer/view/editor/template/inheritance.rs index aab9dc58..dddc76b6 100644 --- a/gui/src/installer/view/editor/template/inheritance.rs +++ b/gui/src/installer/view/editor/template/inheritance.rs @@ -4,7 +4,7 @@ use liana_ui::{ color, component::{ button, collapse, - text::{h3, p1_regular, text, Text}, + text::{h3, p1_regular, text, Text, H3_SIZE}, }, icon, image, theme, widget::*, @@ -30,16 +30,32 @@ pub fn inheritance_template_description(progress: (usize, usize)) -> Element<'st .push(h3("Inheritance wallet")) .max_width(800.0) .push(Container::new( - p1_regular("For this Inheritance wallet you will need 2 Keys: Your Primary Key and an Inheritance Key to be given to a chosen heir. For security reasons, we suggest you use 2 Hardware Wallets to store them.") + p1_regular("For this Inheritance wallet you will need 2 Keys: Your Primary Key (for yourself) and an Inheritance Key (for your heir). For security reasons, we suggest you use 2 Hardware Wallets to store them.") + .style(color::GREY_2) + .horizontal_alignment(alignment::Horizontal::Left) + ).align_x(alignment::Horizontal::Left).width(Length::Fill)) + .push(Row::new() + .spacing(30) + .push( + Row::new() + .align_items(Alignment::Center) + .spacing(10) + .push(icon::round_key_icon().size(H3_SIZE).style(color::GREEN)) + .push(p1_regular("Primary key").bold()) + ).push( + Row::new() + .align_items(Alignment::Center) + .spacing(10) + .push(icon::round_key_icon().size(H3_SIZE).style(color::WHITE)) + .push(p1_regular("Inheritance key").bold()) + )) + .push(Container::new( + p1_regular("You will always be able to spend using your Primary Key. +After a period of inactivity (but not before that) your Inheritance Key will become able to recover your funds. Give it to your heir(s) in order to be able to collect their inheritance.") .style(color::GREY_2) .horizontal_alignment(alignment::Horizontal::Left) ).align_x(alignment::Horizontal::Left).width(Length::Fill)) .push(image::inheritance_template_description().width(Length::Fill)) - .push(Container::new( - p1_regular("Your relative’s Inheritance Key will become active only if you don’t move the coins in your wallet for the defined period of time, enabling him/her to recover your funds while not being able to access them before that.") - .style(color::GREY_2) - .horizontal_alignment(alignment::Horizontal::Left) - ).align_x(alignment::Horizontal::Left).width(Length::Fill)) .push(Row::new().push(Space::with_width(Length::Fill)).push(button::primary(None, "Select").width(Length::Fixed(200.0)).on_press(Message::Next))) .spacing(20), true, From 36af35fae3f21995fcbe0c4c1a5f685a2318d0a0 Mon Sep 17 00:00:00 2001 From: edouardparis Date: Wed, 30 Oct 2024 11:52:23 +0100 Subject: [PATCH 3/3] refac: remove select button at the choose template step --- gui/src/installer/view/editor/template/mod.rs | 91 ++++++++----------- 1 file changed, 40 insertions(+), 51 deletions(-) diff --git a/gui/src/installer/view/editor/template/mod.rs b/gui/src/installer/view/editor/template/mod.rs index 90f6ab6f..66859aac 100644 --- a/gui/src/installer/view/editor/template/mod.rs +++ b/gui/src/installer/view/editor/template/mod.rs @@ -6,10 +6,8 @@ use iced::{alignment, Alignment, Length}; use liana_ui::{ color, - component::{ - button, card, - text::{h3, p1_regular, p2_regular}, - }, + component::text::{h3, p1_regular, p2_regular}, + theme, widget::*, }; @@ -26,64 +24,55 @@ pub fn choose_descriptor_template(progress: (usize, usize)) -> Element<'static, .align_items(Alignment::Start) .push(Container::new( p1_regular("What do you want your wallet for? This depends on the amount of funds you have, the more funds, the higher the security should be. Not sure about the wallet type? We can help you.") - .style(color::GREY_2) - .horizontal_alignment(alignment::Horizontal::Left) + .style(color::GREY_2) + .horizontal_alignment(alignment::Horizontal::Left) ).align_x(alignment::Horizontal::Left).width(Length::Fill)) .push( - card::simple( - Row::new() - .align_items(Alignment::Center) - .push( - Column::new() - .align_items(Alignment::Start) - .push(h3("Simple inheritance")) - .push(p2_regular("Two keys required, one for yourself to spend and another for your heir.").style(color::GREY_2)) - .width(Length::Fill) - ) - .push(button::secondary(None, "Select").on_press( - Message::SelectDescriptorTemplate( - context::DescriptorTemplate::SimpleInheritance, - ), - )), + Button::new( + Column::new() + .align_items(Alignment::Start) + .push(h3("Simple inheritance")) + .push(p2_regular("Two keys required, one for yourself to spend and another for your heir.").style(color::GREY_2)) + .width(Length::Fill) ) + .padding(15) + .on_press( + Message::SelectDescriptorTemplate( + context::DescriptorTemplate::SimpleInheritance, + ) + ).style(theme::Button::Secondary) .width(Length::Fill), ) .push( - card::simple( - Row::new() - .align_items(Alignment::Center) - .push( - Column::new() - .align_items(Alignment::Start) - .push(h3("Multisig security wallet")) - .push(p2_regular("A secure scheme requiring stricter multiparty signature and recovery.").style(color::GREY_2)) - .width(Length::Fill) - ) - .push(button::secondary(None, "Select").on_press( - Message::SelectDescriptorTemplate( - context::DescriptorTemplate::MultisigSecurity, - ), - )), + Button::new( + Column::new() + .align_items(Alignment::Start) + .push(h3("Multisig security wallet")) + .push(p2_regular("A secure scheme requiring stricter multiparty signature and recovery.").style(color::GREY_2)) + .width(Length::Fill) ) + .padding(15) + .on_press( + Message::SelectDescriptorTemplate( + context::DescriptorTemplate::MultisigSecurity, + ) + ).style(theme::Button::Secondary) .width(Length::Fill), ) .push( - card::simple( - Row::new() - .align_items(Alignment::Center) - .push( - Column::new() - .align_items(Alignment::Start) - .push(h3("Custom (choose your own)")) - .push(p2_regular("Create a custom setup that fits all your needs").style(color::GREY_2)) - .width(Length::Fill) - ) - .push(button::secondary(None, "Select").on_press( - Message::SelectDescriptorTemplate( - context::DescriptorTemplate::Custom , - ), - )), + Button::new( + Column::new() + .align_items(Alignment::Start) + .push(h3("Custom (choose your own)")) + .push(p2_regular("Create a custom setup that fits all your needs.").style(color::GREY_2)) + .width(Length::Fill) ) + .padding(15) + .on_press( + Message::SelectDescriptorTemplate( + context::DescriptorTemplate::Custom, + ) + ).style(theme::Button::Secondary) .width(Length::Fill), ) .spacing(20),