Add taproot support to installer descriptor editor step
This commit is contained in:
parent
8bc0cac00a
commit
2debb32181
@ -33,11 +33,12 @@ pub fn hw_list_view(
|
||||
alias.as_ref(),
|
||||
)
|
||||
} else if *registered == Some(false) {
|
||||
hw::unregistered_hardware_wallet(
|
||||
hw::warning_hardware_wallet(
|
||||
kind,
|
||||
version.as_ref(),
|
||||
fingerprint,
|
||||
alias.as_ref(),
|
||||
"The wallet descriptor is not registered on the device.\n You can register it in the settings.",
|
||||
)
|
||||
} else {
|
||||
hw::supported_hardware_wallet(kind, version.as_ref(), fingerprint, alias.as_ref())
|
||||
|
||||
@ -673,3 +673,24 @@ fn ledger_version_supported(version: Option<&Version>) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// Kind and minimal version of devices supporting tapminiscript.
|
||||
// We cannot use a lazy_static HashMap yet, because DeviceKind does not implement Hash.
|
||||
const DEVICES_COMPATIBLE_WITH_TAPMINISCRIPT: [(DeviceKind, Option<Version>); 0] = [];
|
||||
|
||||
pub fn is_compatible_with_tapminiscript(
|
||||
device_kind: &DeviceKind,
|
||||
version: Option<&Version>,
|
||||
) -> bool {
|
||||
DEVICES_COMPATIBLE_WITH_TAPMINISCRIPT
|
||||
.iter()
|
||||
.any(|(kind, minimal_version)| {
|
||||
device_kind == kind
|
||||
&& match (version, minimal_version) {
|
||||
(Some(v1), Some(v2)) => v1 >= v2,
|
||||
(None, Some(_)) => false,
|
||||
(Some(_), None) => true,
|
||||
(None, None) => true,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ use crate::{
|
||||
download::Progress,
|
||||
hw::HardwareWalletMessage,
|
||||
};
|
||||
use async_hwi::DeviceKind;
|
||||
use async_hwi::{DeviceKind, Version};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Message {
|
||||
@ -30,6 +30,7 @@ pub enum Message {
|
||||
UseHotSigner,
|
||||
Installed(Result<PathBuf, Error>),
|
||||
Network(Network),
|
||||
CreateTaprootDescriptor(bool),
|
||||
SelectBitcoindType(SelectBitcoindTypeMsg),
|
||||
InternalBitcoind(InternalBitcoindMsg),
|
||||
DefineBitcoind(DefineBitcoind),
|
||||
@ -85,12 +86,18 @@ pub enum DefinePath {
|
||||
EditSequence,
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum DefineKey {
|
||||
Delete,
|
||||
Edit,
|
||||
Clipboard(String),
|
||||
Edited(String, DescriptorPublicKey, Option<DeviceKind>),
|
||||
Edited(
|
||||
String,
|
||||
DescriptorPublicKey,
|
||||
Option<DeviceKind>,
|
||||
Option<Version>,
|
||||
),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
||||
@ -24,8 +24,9 @@ use liana_ui::{
|
||||
widget::Element,
|
||||
};
|
||||
|
||||
use async_hwi::DeviceKind;
|
||||
use async_hwi::{DeviceKind, Version};
|
||||
|
||||
use crate::hw;
|
||||
use crate::{
|
||||
app::{settings::KeySetting, wallet::wallet_name},
|
||||
hw::{HardwareWallet, HardwareWallets},
|
||||
@ -72,6 +73,7 @@ impl RecoveryPath {
|
||||
&self,
|
||||
aliases: &HashMap<Fingerprint, String>,
|
||||
duplicate_name: &HashSet<Fingerprint>,
|
||||
incompatible_with_tapminiscript: &HashSet<Fingerprint>,
|
||||
) -> Element<message::DefinePath> {
|
||||
view::recovery_path_view(
|
||||
self.sequence,
|
||||
@ -85,6 +87,7 @@ impl RecoveryPath {
|
||||
view::defined_descriptor_key(
|
||||
aliases.get(key).unwrap().to_string(),
|
||||
duplicate_name.contains(key),
|
||||
incompatible_with_tapminiscript.contains(key),
|
||||
)
|
||||
} else {
|
||||
view::undefined_descriptor_key()
|
||||
@ -99,6 +102,7 @@ impl RecoveryPath {
|
||||
struct Setup {
|
||||
keys: Vec<Key>,
|
||||
duplicate_name: HashSet<Fingerprint>,
|
||||
incompatible_with_tapminiscript: HashSet<Fingerprint>,
|
||||
spending_keys: Vec<Option<Fingerprint>>,
|
||||
spending_threshold: usize,
|
||||
recovery_paths: Vec<RecoveryPath>,
|
||||
@ -109,6 +113,7 @@ impl Setup {
|
||||
Self {
|
||||
keys: Vec::new(),
|
||||
duplicate_name: HashSet::new(),
|
||||
incompatible_with_tapminiscript: HashSet::new(),
|
||||
spending_keys: vec![None],
|
||||
spending_threshold: 1,
|
||||
recovery_paths: vec![RecoveryPath::new()],
|
||||
@ -120,6 +125,7 @@ impl Setup {
|
||||
&& !self.spending_keys.iter().any(|k| k.is_none())
|
||||
&& !self.recovery_paths.iter().any(|path| !path.valid())
|
||||
&& self.duplicate_name.is_empty()
|
||||
&& self.incompatible_with_tapminiscript.is_empty()
|
||||
}
|
||||
|
||||
// Mark as duplicate every defined key that have the same name but not the same fingerprint.
|
||||
@ -150,6 +156,33 @@ impl Setup {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_for_tapminiscript_support(&mut self, must_support_taproot: bool) {
|
||||
self.incompatible_with_tapminiscript = HashSet::new();
|
||||
if must_support_taproot {
|
||||
for key in &self.keys {
|
||||
// check if key is used by a path
|
||||
if !self
|
||||
.spending_keys
|
||||
.iter()
|
||||
.chain(self.recovery_paths.iter().flat_map(|path| &path.keys))
|
||||
.any(|k| *k == Some(key.fingerprint))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// device_kind is none only for HotSigner which is compatible.
|
||||
if let Some(device_kind) = key.device_kind.as_ref() {
|
||||
if !hw::is_compatible_with_tapminiscript(
|
||||
device_kind,
|
||||
key.device_version.as_ref(),
|
||||
) {
|
||||
self.incompatible_with_tapminiscript.insert(key.fingerprint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn keys_aliases(&self) -> HashMap<Fingerprint, String> {
|
||||
let mut map = HashMap::new();
|
||||
for key in &self.keys {
|
||||
@ -162,6 +195,7 @@ impl Setup {
|
||||
pub struct DefineDescriptor {
|
||||
network: Network,
|
||||
network_valid: bool,
|
||||
use_taproot: bool,
|
||||
data_dir: Option<PathBuf>,
|
||||
setup: HashMap<Network, Setup>,
|
||||
|
||||
@ -175,6 +209,7 @@ impl DefineDescriptor {
|
||||
pub fn new(signer: Arc<Mutex<Signer>>) -> Self {
|
||||
Self {
|
||||
network: Network::Bitcoin,
|
||||
use_taproot: false,
|
||||
setup: HashMap::from([(Network::Bitcoin, Setup::new())]),
|
||||
data_dir: None,
|
||||
network_valid: true,
|
||||
@ -204,6 +239,14 @@ impl DefineDescriptor {
|
||||
network_datadir.push(self.network.to_string());
|
||||
self.network_valid = !network_datadir.exists();
|
||||
}
|
||||
self.check_setup()
|
||||
}
|
||||
|
||||
fn check_setup(&mut self) {
|
||||
self.setup_mut().check_for_duplicate();
|
||||
let use_taproot = self.use_taproot;
|
||||
self.setup_mut()
|
||||
.check_for_tapminiscript_support(use_taproot);
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,6 +264,10 @@ impl Step for DefineDescriptor {
|
||||
hws.set_network(network);
|
||||
self.set_network(network)
|
||||
}
|
||||
Message::CreateTaprootDescriptor(use_taproot) => {
|
||||
self.use_taproot = use_taproot;
|
||||
self.check_setup();
|
||||
}
|
||||
Message::DefineDescriptor(message::DefineDescriptor::AddRecoveryPath) => {
|
||||
self.setup_mut().recovery_paths.push(RecoveryPath::new());
|
||||
}
|
||||
@ -236,7 +283,7 @@ impl Step for DefineDescriptor {
|
||||
message::DefineKey::Clipboard(key) => {
|
||||
return Command::perform(async move { key }, Message::Clibpboard);
|
||||
}
|
||||
message::DefineKey::Edited(name, imported_key, kind) => {
|
||||
message::DefineKey::Edited(name, imported_key, kind, version) => {
|
||||
let fingerprint = imported_key.master_fingerprint();
|
||||
hws.set_alias(fingerprint, name.clone());
|
||||
if let Some(key) = self
|
||||
@ -252,17 +299,20 @@ impl Step for DefineDescriptor {
|
||||
name,
|
||||
key: imported_key,
|
||||
device_kind: kind,
|
||||
device_version: version,
|
||||
});
|
||||
}
|
||||
|
||||
self.setup_mut().spending_keys[i] = Some(fingerprint);
|
||||
|
||||
self.modal = None;
|
||||
self.setup_mut().check_for_duplicate();
|
||||
self.check_setup();
|
||||
}
|
||||
message::DefineKey::Edit => {
|
||||
let use_taproot = self.use_taproot;
|
||||
let setup = self.setup_mut();
|
||||
let modal = EditXpubModal::new(
|
||||
use_taproot,
|
||||
HashSet::from_iter(setup.spending_keys.iter().filter_map(|key| {
|
||||
if key.is_some() && key != &setup.spending_keys[i] {
|
||||
*key
|
||||
@ -293,7 +343,7 @@ impl Step for DefineDescriptor {
|
||||
{
|
||||
self.setup_mut().spending_threshold -= 1;
|
||||
}
|
||||
self.setup_mut().check_for_duplicate();
|
||||
self.check_setup();
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
@ -327,7 +377,7 @@ impl Step for DefineDescriptor {
|
||||
message::DefineKey::Clipboard(key) => {
|
||||
return Command::perform(async move { key }, Message::Clibpboard);
|
||||
}
|
||||
message::DefineKey::Edited(name, imported_key, kind) => {
|
||||
message::DefineKey::Edited(name, imported_key, kind, version) => {
|
||||
let fingerprint = imported_key.master_fingerprint();
|
||||
hws.set_alias(fingerprint, name.clone());
|
||||
if let Some(key) = self
|
||||
@ -343,17 +393,20 @@ impl Step for DefineDescriptor {
|
||||
name,
|
||||
key: imported_key,
|
||||
device_kind: kind,
|
||||
device_version: version,
|
||||
});
|
||||
}
|
||||
|
||||
self.setup_mut().recovery_paths[i].keys[j] = Some(fingerprint);
|
||||
|
||||
self.modal = None;
|
||||
self.setup_mut().check_for_duplicate();
|
||||
self.check_setup();
|
||||
}
|
||||
message::DefineKey::Edit => {
|
||||
let use_taproot = self.use_taproot;
|
||||
let setup = self.setup_mut();
|
||||
let modal = EditXpubModal::new(
|
||||
use_taproot,
|
||||
HashSet::from_iter(setup.recovery_paths[i].keys.iter().filter_map(
|
||||
|key| {
|
||||
if key.is_some() && key != &setup.recovery_paths[i].keys[j] {
|
||||
@ -390,7 +443,7 @@ impl Step for DefineDescriptor {
|
||||
{
|
||||
self.setup_mut().recovery_paths.remove(i);
|
||||
}
|
||||
self.setup_mut().check_for_duplicate();
|
||||
self.check_setup();
|
||||
}
|
||||
},
|
||||
},
|
||||
@ -490,7 +543,11 @@ impl Step for DefineDescriptor {
|
||||
PathInfo::Multi(self.setup[&self.network].spending_threshold, spending_keys)
|
||||
};
|
||||
|
||||
let policy = match LianaPolicy::new(spending_keys, recovery_paths) {
|
||||
let policy = match if self.use_taproot {
|
||||
LianaPolicy::new(spending_keys, recovery_paths)
|
||||
} else {
|
||||
LianaPolicy::new_legacy(spending_keys, recovery_paths)
|
||||
} {
|
||||
Ok(policy) => policy,
|
||||
Err(e) => {
|
||||
self.error = Some(e.to_string());
|
||||
@ -513,6 +570,7 @@ impl Step for DefineDescriptor {
|
||||
progress,
|
||||
self.network,
|
||||
self.network_valid,
|
||||
self.use_taproot,
|
||||
self.setup[&self.network]
|
||||
.spending_keys
|
||||
.iter()
|
||||
@ -522,6 +580,9 @@ impl Step for DefineDescriptor {
|
||||
view::defined_descriptor_key(
|
||||
aliases.get(key).unwrap().to_string(),
|
||||
self.setup[&self.network].duplicate_name.contains(key),
|
||||
self.setup[&self.network]
|
||||
.incompatible_with_tapminiscript
|
||||
.contains(key),
|
||||
)
|
||||
} else {
|
||||
view::undefined_descriptor_key()
|
||||
@ -539,12 +600,14 @@ impl Step for DefineDescriptor {
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, path)| {
|
||||
path.view(&aliases, &self.setup[&self.network].duplicate_name)
|
||||
.map(move |msg| {
|
||||
Message::DefineDescriptor(message::DefineDescriptor::RecoveryPath(
|
||||
i, msg,
|
||||
))
|
||||
})
|
||||
path.view(
|
||||
&aliases,
|
||||
&self.setup[&self.network].duplicate_name,
|
||||
&self.setup[&self.network].incompatible_with_tapminiscript,
|
||||
)
|
||||
.map(move |msg| {
|
||||
Message::DefineDescriptor(message::DefineDescriptor::RecoveryPath(i, msg))
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
self.valid(),
|
||||
@ -583,6 +646,7 @@ fn new_multixkey_from_xpub(
|
||||
#[derive(Clone)]
|
||||
pub struct Key {
|
||||
pub device_kind: Option<DeviceKind>,
|
||||
pub device_version: Option<Version>,
|
||||
pub name: String,
|
||||
pub fingerprint: Fingerprint,
|
||||
pub key: DescriptorPublicKey,
|
||||
@ -675,6 +739,7 @@ impl DescriptorEditModal for EditSequenceModal {
|
||||
}
|
||||
|
||||
pub struct EditXpubModal {
|
||||
device_must_support_tapminiscript: bool,
|
||||
/// None if path is primary path
|
||||
path_index: Option<usize>,
|
||||
key_index: usize,
|
||||
@ -692,12 +757,13 @@ pub struct EditXpubModal {
|
||||
keys: Vec<Key>,
|
||||
hot_signer: Arc<Mutex<Signer>>,
|
||||
hot_signer_fingerprint: Fingerprint,
|
||||
chosen_signer: Option<(Fingerprint, Option<DeviceKind>)>,
|
||||
chosen_signer: Option<(Fingerprint, Option<DeviceKind>, Option<Version>)>,
|
||||
}
|
||||
|
||||
impl EditXpubModal {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn new(
|
||||
device_must_support_tapminiscript: bool,
|
||||
other_path_keys: HashSet<Fingerprint>,
|
||||
key: Option<Fingerprint>,
|
||||
path_index: Option<usize>,
|
||||
@ -708,6 +774,7 @@ impl EditXpubModal {
|
||||
) -> Self {
|
||||
let hot_signer_fingerprint = hot_signer.lock().unwrap().fingerprint();
|
||||
Self {
|
||||
device_must_support_tapminiscript,
|
||||
other_path_keys,
|
||||
form_name: form::Value {
|
||||
valid: true,
|
||||
@ -740,7 +807,7 @@ impl EditXpubModal {
|
||||
error: None,
|
||||
network,
|
||||
edit_name: false,
|
||||
chosen_signer: key.map(|k| (k, None)),
|
||||
chosen_signer: key.map(|k| (k, None, None)),
|
||||
hot_signer_fingerprint,
|
||||
hot_signer,
|
||||
duplicate_master_fg: false,
|
||||
@ -767,10 +834,11 @@ impl DescriptorEditModal for EditXpubModal {
|
||||
device,
|
||||
fingerprint,
|
||||
kind,
|
||||
version,
|
||||
..
|
||||
}) = hws.list.get(i)
|
||||
{
|
||||
self.chosen_signer = Some((*fingerprint, Some(*kind)));
|
||||
self.chosen_signer = Some((*fingerprint, Some(*kind), version.clone()));
|
||||
self.processing = true;
|
||||
return Command::perform(
|
||||
get_extended_pubkey(device.clone(), *fingerprint, self.network),
|
||||
@ -787,7 +855,7 @@ impl DescriptorEditModal for EditXpubModal {
|
||||
}
|
||||
Message::UseHotSigner => {
|
||||
let fingerprint = self.hot_signer.lock().unwrap().fingerprint();
|
||||
self.chosen_signer = Some((fingerprint, None));
|
||||
self.chosen_signer = Some((fingerprint, None, None));
|
||||
self.form_xpub.valid = true;
|
||||
if let Some(alias) = self
|
||||
.keys
|
||||
@ -882,7 +950,12 @@ impl DescriptorEditModal for EditXpubModal {
|
||||
if let Ok(key) = DescriptorPublicKey::from_str(&self.form_xpub.value) {
|
||||
let key_index = self.key_index;
|
||||
let name = self.form_name.value.clone();
|
||||
let device_kind = self.chosen_signer.and_then(|(_, kind)| kind);
|
||||
let (device_kind, device_version) =
|
||||
if let Some((_, kind, version)) = &self.chosen_signer {
|
||||
(*kind, version.clone())
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
if self.other_path_keys.contains(&key.master_fingerprint()) {
|
||||
self.duplicate_master_fg = true;
|
||||
} else if let Some(path_index) = self.path_index {
|
||||
@ -893,7 +966,12 @@ impl DescriptorEditModal for EditXpubModal {
|
||||
path_index,
|
||||
message::DefinePath::Key(
|
||||
key_index,
|
||||
message::DefineKey::Edited(name, key, device_kind),
|
||||
message::DefineKey::Edited(
|
||||
name,
|
||||
key,
|
||||
device_kind,
|
||||
device_version,
|
||||
),
|
||||
),
|
||||
)
|
||||
},
|
||||
@ -906,7 +984,12 @@ impl DescriptorEditModal for EditXpubModal {
|
||||
message::DefineDescriptor::PrimaryPath(
|
||||
message::DefinePath::Key(
|
||||
key_index,
|
||||
message::DefineKey::Edited(name, key, device_kind),
|
||||
message::DefineKey::Edited(
|
||||
name,
|
||||
key,
|
||||
device_kind,
|
||||
device_version,
|
||||
),
|
||||
),
|
||||
)
|
||||
},
|
||||
@ -917,7 +1000,8 @@ impl DescriptorEditModal for EditXpubModal {
|
||||
}
|
||||
message::ImportKeyModal::SelectKey(i) => {
|
||||
if let Some(key) = self.keys.get(i) {
|
||||
self.chosen_signer = Some((key.fingerprint, key.device_kind));
|
||||
self.chosen_signer =
|
||||
Some((key.fingerprint, key.device_kind, key.device_version.clone()));
|
||||
self.form_xpub.value = key.key.to_string();
|
||||
self.form_xpub.valid = true;
|
||||
self.form_name.value = key.name.clone();
|
||||
@ -930,7 +1014,7 @@ impl DescriptorEditModal for EditXpubModal {
|
||||
Command::none()
|
||||
}
|
||||
fn view<'a>(&'a self, hws: &'a HardwareWallets) -> Element<'a, Message> {
|
||||
let chosen_signer = self.chosen_signer.map(|s| s.0);
|
||||
let chosen_signer = self.chosen_signer.as_ref().map(|s| s.0);
|
||||
view::edit_key_modal(
|
||||
self.network,
|
||||
hws.list
|
||||
@ -953,6 +1037,7 @@ impl DescriptorEditModal for EditXpubModal {
|
||||
&& hw.fingerprint() == chosen_signer
|
||||
&& self.form_xpub.valid
|
||||
&& !self.form_xpub.value.is_empty(),
|
||||
self.device_must_support_tapminiscript,
|
||||
))
|
||||
}
|
||||
})
|
||||
@ -969,13 +1054,15 @@ impl DescriptorEditModal for EditXpubModal {
|
||||
&key.name,
|
||||
&key.fingerprint,
|
||||
key.device_kind.as_ref(),
|
||||
key.device_version.as_ref(),
|
||||
Some(key.fingerprint) == chosen_signer,
|
||||
self.device_must_support_tapminiscript,
|
||||
))
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
self.error.as_ref(),
|
||||
self.chosen_signer.map(|s| s.0),
|
||||
self.chosen_signer.as_ref().map(|s| s.0),
|
||||
&self.hot_signer_fingerprint,
|
||||
self.keys.iter().find_map(|k| {
|
||||
if k.fingerprint == self.hot_signer_fingerprint {
|
||||
|
||||
@ -23,7 +23,7 @@ use liana_ui::{
|
||||
|
||||
use crate::{
|
||||
bitcoind::{ConfigField, RpcAuthType, RpcAuthValues, StartInternalBitcoindError},
|
||||
hw::HardwareWallet,
|
||||
hw::{is_compatible_with_tapminiscript, HardwareWallet},
|
||||
installer::{
|
||||
message::{self, Message},
|
||||
prompt,
|
||||
@ -173,11 +173,29 @@ pub fn welcome<'a>() -> Element<'a, Message> {
|
||||
.into()
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum DescriptorKind {
|
||||
Legacy,
|
||||
Taproot,
|
||||
}
|
||||
|
||||
const DESCRIPTOR_KINDS: [DescriptorKind; 2] = [DescriptorKind::Legacy, DescriptorKind::Taproot];
|
||||
|
||||
impl std::fmt::Display for DescriptorKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Legacy => write!(f, "Default"),
|
||||
Self::Taproot => write!(f, "Taproot"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn define_descriptor<'a>(
|
||||
progress: (usize, usize),
|
||||
network: bitcoin::Network,
|
||||
network_valid: bool,
|
||||
use_taproot: bool,
|
||||
spending_keys: Vec<Element<'a, Message>>,
|
||||
spending_threshold: usize,
|
||||
recovery_paths: Vec<Element<'a, Message>>,
|
||||
@ -204,6 +222,23 @@ pub fn define_descriptor<'a>(
|
||||
Some(text("A data directory already exists for this network").style(color::RED))
|
||||
});
|
||||
|
||||
let col_wallet = Column::new()
|
||||
.spacing(10)
|
||||
.push(text("Wallet").bold())
|
||||
.push(container(
|
||||
pick_list(
|
||||
&DESCRIPTOR_KINDS[..],
|
||||
Some(if use_taproot {
|
||||
DescriptorKind::Taproot
|
||||
} else {
|
||||
DescriptorKind::Legacy
|
||||
}),
|
||||
|kind| Message::CreateTaprootDescriptor(kind == DescriptorKind::Taproot),
|
||||
)
|
||||
.style(theme::PickList::Secondary)
|
||||
.padding(10),
|
||||
));
|
||||
|
||||
let col_spending_keys = Column::new()
|
||||
.push(
|
||||
Row::new()
|
||||
@ -266,7 +301,13 @@ pub fn define_descriptor<'a>(
|
||||
.push(
|
||||
Column::new()
|
||||
.width(Length::Fill)
|
||||
.push(col_network)
|
||||
.push(
|
||||
Row::new()
|
||||
.push(col_network)
|
||||
.push(Space::with_width(Length::Fixed(100.0)))
|
||||
.push(col_wallet)
|
||||
.align_items(Alignment::Start),
|
||||
)
|
||||
.push(
|
||||
Column::new()
|
||||
.spacing(25)
|
||||
@ -707,6 +748,7 @@ pub fn register_descriptor<'a>(
|
||||
hw.fingerprint()
|
||||
.map(|fg| registered.contains(&fg))
|
||||
.unwrap_or(false),
|
||||
false,
|
||||
))
|
||||
}),
|
||||
)
|
||||
@ -1287,6 +1329,7 @@ pub fn undefined_descriptor_key<'a>() -> Element<'a, message::DefineKey> {
|
||||
pub fn defined_descriptor_key<'a>(
|
||||
name: String,
|
||||
duplicate_name: bool,
|
||||
incompatible_with_tapminiscript: bool,
|
||||
) -> Element<'a, message::DefineKey> {
|
||||
let col = Column::new()
|
||||
.width(Length::Fill)
|
||||
@ -1336,6 +1379,21 @@ pub fn defined_descriptor_key<'a>(
|
||||
)
|
||||
.push(text("Duplicate name").small().style(color::RED))
|
||||
.into()
|
||||
} else if incompatible_with_tapminiscript {
|
||||
Column::new()
|
||||
.align_items(Alignment::Center)
|
||||
.push(
|
||||
card::invalid(col)
|
||||
.padding(5)
|
||||
.height(Length::Fixed(150.0))
|
||||
.width(Length::Fixed(150.0)),
|
||||
)
|
||||
.push(
|
||||
text("Taproot is not supported\nby this key device")
|
||||
.small()
|
||||
.style(color::RED),
|
||||
)
|
||||
.into()
|
||||
} else {
|
||||
card::simple(col)
|
||||
.padding(5)
|
||||
@ -1594,6 +1652,7 @@ pub fn hw_list_view(
|
||||
chosen: bool,
|
||||
processing: bool,
|
||||
selected: bool,
|
||||
device_must_support_taproot: bool,
|
||||
) -> Element<Message> {
|
||||
let mut bttn = Button::new(match hw {
|
||||
HardwareWallet::Supported {
|
||||
@ -1607,6 +1666,16 @@ pub fn hw_list_view(
|
||||
hw::processing_hardware_wallet(kind, version.as_ref(), fingerprint, alias.as_ref())
|
||||
} else if selected {
|
||||
hw::selected_hardware_wallet(kind, version.as_ref(), fingerprint, alias.as_ref())
|
||||
} else if device_must_support_taproot
|
||||
&& !is_compatible_with_tapminiscript(kind, version.as_ref())
|
||||
{
|
||||
hw::warning_hardware_wallet(
|
||||
kind,
|
||||
version.as_ref(),
|
||||
fingerprint,
|
||||
alias.as_ref(),
|
||||
"Device firmware version does not support taproot miniscript",
|
||||
)
|
||||
} else {
|
||||
hw::supported_hardware_wallet(kind, version.as_ref(), fingerprint, alias.as_ref())
|
||||
}
|
||||
@ -1634,19 +1703,31 @@ pub fn key_list_view<'a>(
|
||||
name: &'a str,
|
||||
fingerprint: &'a Fingerprint,
|
||||
kind: Option<&'a DeviceKind>,
|
||||
version: Option<&'a async_hwi::Version>,
|
||||
chosen: bool,
|
||||
device_must_support_taproot: bool,
|
||||
) -> Element<'a, Message> {
|
||||
let bttn = Button::new(if chosen {
|
||||
hw::selected_hardware_wallet(
|
||||
kind.map(|k| k.to_string()).unwrap_or_default(),
|
||||
None::<String>,
|
||||
version,
|
||||
fingerprint,
|
||||
Some(name),
|
||||
)
|
||||
} else if device_must_support_taproot
|
||||
&& kind.map(|kind| is_compatible_with_tapminiscript(kind, version)) == Some(false)
|
||||
{
|
||||
hw::warning_hardware_wallet(
|
||||
kind.map(|k| k.to_string()).unwrap_or_default(),
|
||||
version,
|
||||
fingerprint,
|
||||
Some(name),
|
||||
"Device firmware version does not support taproot miniscript",
|
||||
)
|
||||
} else {
|
||||
hw::supported_hardware_wallet(
|
||||
kind.map(|k| k.to_string()).unwrap_or_default(),
|
||||
None::<String>,
|
||||
version,
|
||||
fingerprint,
|
||||
Some(name),
|
||||
)
|
||||
|
||||
@ -10,7 +10,7 @@ use liana::{
|
||||
};
|
||||
|
||||
pub struct Signer {
|
||||
curve: secp256k1::Secp256k1<secp256k1::SignOnly>,
|
||||
curve: secp256k1::Secp256k1<secp256k1::All>,
|
||||
key: HotSigner,
|
||||
pub fingerprint: Fingerprint,
|
||||
}
|
||||
@ -23,7 +23,7 @@ impl std::fmt::Debug for Signer {
|
||||
|
||||
impl Signer {
|
||||
pub fn new(key: HotSigner) -> Self {
|
||||
let curve = secp256k1::Secp256k1::signing_only();
|
||||
let curve = secp256k1::Secp256k1::new();
|
||||
let fingerprint = key.fingerprint(&curve);
|
||||
Self {
|
||||
key,
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use iced::Color;
|
||||
pub const BLACK: Color = iced::Color::BLACK;
|
||||
pub const TRANSPARENT: Color = iced::Color::TRANSPARENT;
|
||||
pub const LIGHT_BLACK: Color = Color::from_rgb(
|
||||
0x14 as f32 / 255.0,
|
||||
0x14 as f32 / 255.0,
|
||||
|
||||
@ -51,11 +51,12 @@ pub fn supported_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Display>(
|
||||
.padding(10)
|
||||
}
|
||||
|
||||
pub fn unregistered_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Display>(
|
||||
pub fn warning_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Display>(
|
||||
kind: K,
|
||||
version: Option<V>,
|
||||
fingerprint: F,
|
||||
alias: Option<impl Into<Cow<'a, str>>>,
|
||||
warning: &'static str,
|
||||
) -> Container<'a, T> {
|
||||
container(
|
||||
row(vec![
|
||||
@ -75,7 +76,7 @@ pub fn unregistered_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Displa
|
||||
.into(),
|
||||
column(vec![tooltip::Tooltip::new(
|
||||
icon::warning_icon(),
|
||||
"The wallet descriptor is not registered on the device.\n You can register it in the settings.",
|
||||
warning,
|
||||
tooltip::Position::Bottom,
|
||||
)
|
||||
.style(theme::Container::Card(theme::Card::Simple))
|
||||
|
||||
@ -441,6 +441,7 @@ pub enum PickList {
|
||||
#[default]
|
||||
Simple,
|
||||
Invalid,
|
||||
Secondary,
|
||||
}
|
||||
impl pick_list::StyleSheet for Theme {
|
||||
type Style = PickList;
|
||||
@ -465,6 +466,15 @@ impl pick_list::StyleSheet for Theme {
|
||||
border_radius: 25.0,
|
||||
text_color: color::RED,
|
||||
},
|
||||
PickList::Secondary => pick_list::Appearance {
|
||||
placeholder_color: color::GREY_3,
|
||||
handle_color: color::GREY_3,
|
||||
background: color::TRANSPARENT.into(),
|
||||
border_width: 1.0,
|
||||
border_color: color::GREY_3,
|
||||
border_radius: 25.0,
|
||||
text_color: color::GREY_3,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user