hw: load wallet from config
This commit is contained in:
parent
6500381059
commit
258aeb57fe
9
gui/Cargo.lock
generated
9
gui/Cargo.lock
generated
@ -125,7 +125,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "async-hwi"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/revault/async-hwi?branch=add-ledger#de5615ba2e2e2d3ded6a058f0193f8787d3873dc"
|
||||
source = "git+https://github.com/revault/async-hwi?branch=master#14b29f820910132d9b8f799d030bfed69ac67239"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"base64",
|
||||
@ -1380,7 +1380,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ledger_bitcoin_client"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/edouardparis/app-bitcoin-new/?branch=bitcoin_client_rs#95ec68b546d49a77eee274880d2450fdb08f840c"
|
||||
source = "git+https://github.com/edouardparis/app-bitcoin-new/?branch=bitcoin_client_rs#efe26ed9fcfe0676c33141ad4777fd3786f7d539"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bitcoin",
|
||||
@ -1597,7 +1597,7 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
[[package]]
|
||||
name = "minisafe"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/revault/minisafe?branch=master#790d283e77063c019f54690eb1c483562e12338c"
|
||||
source = "git+https://github.com/revault/minisafe?branch=master#8b129fe3e51ac41a78c282a018e70bd86e2ab24f"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"base64",
|
||||
@ -1636,8 +1636,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "miniscript"
|
||||
version = "8.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f4975078076f0b7b914a3044ad7432d2a7fcec38edb855afdc672e24ca35b69"
|
||||
source = "git+https://github.com/darosior/rust-miniscript?branch=multipath_descriptors_on_8.0#a63d5a263a9006b4d29342012133a3bc919765ba"
|
||||
dependencies = [
|
||||
"bitcoin",
|
||||
"serde",
|
||||
|
||||
@ -14,7 +14,7 @@ name = "minisafe-gui"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
async-hwi = { git = "https://github.com/revault/async-hwi", branch = "add-ledger" }
|
||||
async-hwi = { git = "https://github.com/revault/async-hwi", branch = "master" }
|
||||
minisafe = { git = "https://github.com/revault/minisafe", branch = "master", default-features = false }
|
||||
backtrace = "0.3"
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use crate::hw::HardwareWalletConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
@ -9,16 +10,23 @@ pub struct Config {
|
||||
pub log_level: Option<String>,
|
||||
/// Use iced debug feature if true.
|
||||
pub debug: Option<bool>,
|
||||
/// hardware wallets config.
|
||||
#[serde(default)]
|
||||
pub hardware_wallets: Vec<HardwareWalletConfig>,
|
||||
}
|
||||
|
||||
pub const DEFAULT_FILE_NAME: &str = "gui.toml";
|
||||
|
||||
impl Config {
|
||||
pub fn new(minisafed_config_path: PathBuf) -> Self {
|
||||
pub fn new(
|
||||
minisafed_config_path: PathBuf,
|
||||
hardware_wallets: Vec<HardwareWalletConfig>,
|
||||
) -> Self {
|
||||
Self {
|
||||
minisafed_config_path,
|
||||
log_level: None,
|
||||
debug: None,
|
||||
hardware_wallets,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,12 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_hwi::{ledger, specter, DeviceKind, Error as HWIError, HWI};
|
||||
use log::debug;
|
||||
use minisafe::miniscript::bitcoin::util::bip32::Fingerprint;
|
||||
use std::sync::Arc;
|
||||
use minisafe::miniscript::bitcoin::{
|
||||
hashes::hex::{FromHex, ToHex},
|
||||
util::bip32::Fingerprint,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HardwareWallet {
|
||||
@ -22,7 +27,33 @@ impl HardwareWallet {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn list_hardware_wallets() -> Vec<HardwareWallet> {
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct HardwareWalletConfig {
|
||||
pub kind: String,
|
||||
pub fingerprint: String,
|
||||
pub token: String,
|
||||
}
|
||||
|
||||
impl HardwareWalletConfig {
|
||||
pub fn new(kind: &async_hwi::DeviceKind, fingerprint: &Fingerprint, token: &[u8; 32]) -> Self {
|
||||
Self {
|
||||
kind: kind.to_string(),
|
||||
fingerprint: fingerprint.to_string(),
|
||||
token: token.to_hex(),
|
||||
}
|
||||
}
|
||||
|
||||
fn token(&self) -> [u8; 32] {
|
||||
let mut res = [0x00; 32];
|
||||
res.copy_from_slice(&Vec::from_hex(&self.token).unwrap());
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn list_hardware_wallets(
|
||||
cfg: &[HardwareWalletConfig],
|
||||
wallet: Option<(&str, &str)>,
|
||||
) -> Vec<HardwareWallet> {
|
||||
let mut hws: Vec<HardwareWallet> = Vec::new();
|
||||
match specter::SpecterSimulator::try_connect().await {
|
||||
Ok(device) => match HardwareWallet::new(Arc::new(device)).await {
|
||||
@ -49,8 +80,26 @@ pub async fn list_hardware_wallets() -> Vec<HardwareWallet> {
|
||||
}
|
||||
}
|
||||
match ledger::LedgerSimulator::try_connect().await {
|
||||
Ok(device) => match HardwareWallet::new(Arc::new(device)).await {
|
||||
Ok(hw) => hws.push(hw),
|
||||
Ok(mut device) => match device.get_master_fingerprint().await {
|
||||
Ok(fingerprint) => {
|
||||
if let Some((name, descriptor)) = wallet {
|
||||
device
|
||||
.load_wallet(
|
||||
name,
|
||||
descriptor,
|
||||
cfg.iter()
|
||||
.find(|cfg| cfg.fingerprint == fingerprint.to_string())
|
||||
.map(|cfg| cfg.token()),
|
||||
)
|
||||
.expect("Configuration must be correct");
|
||||
}
|
||||
|
||||
hws.push(HardwareWallet {
|
||||
kind: device.device_kind(),
|
||||
fingerprint,
|
||||
device: Arc::new(device),
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
debug!("{}", e);
|
||||
}
|
||||
|
||||
@ -12,7 +12,9 @@ use std::convert::TryInto;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::{app::config as gui_config, installer::config::DEFAULT_FILE_NAME};
|
||||
use crate::{
|
||||
app::config as gui_config, hw::HardwareWalletConfig, installer::config::DEFAULT_FILE_NAME,
|
||||
};
|
||||
|
||||
pub use message::Message;
|
||||
use step::{Context, DefineBitcoind, DefineDescriptor, Final, RegisterDescriptor, Step, Welcome};
|
||||
@ -133,6 +135,12 @@ impl Installer {
|
||||
}
|
||||
|
||||
pub async fn install(ctx: Context) -> Result<PathBuf, Error> {
|
||||
let hardware_wallets = ctx
|
||||
.hw_tokens
|
||||
.iter()
|
||||
.map(|(kind, fingerprint, token)| HardwareWalletConfig::new(kind, fingerprint, token))
|
||||
.collect();
|
||||
|
||||
let mut cfg: minisafe::config::Config = ctx
|
||||
.try_into()
|
||||
.expect("Everything should be checked at this point");
|
||||
@ -179,6 +187,7 @@ pub async fn install(ctx: Context) -> Result<PathBuf, Error> {
|
||||
e
|
||||
))
|
||||
})?,
|
||||
hardware_wallets,
|
||||
))
|
||||
.unwrap()
|
||||
.as_bytes(),
|
||||
|
||||
@ -2,10 +2,10 @@ use std::str::FromStr;
|
||||
|
||||
use iced::{pure::Element, Command};
|
||||
use minisafe::{
|
||||
descriptors::InheritanceDescriptor,
|
||||
descriptors::MultipathDescriptor,
|
||||
miniscript::{
|
||||
bitcoin::util::bip32::{DerivationPath, Fingerprint},
|
||||
descriptor::{Descriptor, DescriptorPublicKey, DescriptorXKey, Wildcard},
|
||||
descriptor::{Descriptor, DescriptorMultiXKey, DescriptorPublicKey, Wildcard},
|
||||
},
|
||||
};
|
||||
|
||||
@ -123,7 +123,7 @@ impl Step for DefineDescriptor {
|
||||
}
|
||||
false
|
||||
} else if !self.imported_descriptor.value.is_empty() {
|
||||
if let Ok(desc) = InheritanceDescriptor::from_str(&self.imported_descriptor.value) {
|
||||
if let Ok(desc) = MultipathDescriptor::from_str(&self.imported_descriptor.value) {
|
||||
ctx.descriptor = Some(desc);
|
||||
true
|
||||
} else {
|
||||
@ -144,7 +144,7 @@ impl Step for DefineDescriptor {
|
||||
return false;
|
||||
}
|
||||
|
||||
let desc = match InheritanceDescriptor::new(
|
||||
let desc = match MultipathDescriptor::new(
|
||||
user_key.unwrap(),
|
||||
heir_key.unwrap(),
|
||||
sequence.unwrap(),
|
||||
@ -207,7 +207,10 @@ impl GetHardwareWalletXpubModal {
|
||||
}
|
||||
}
|
||||
fn load(&self) -> Command<Message> {
|
||||
Command::perform(list_hardware_wallets(), Message::ConnectedHardwareWallets)
|
||||
Command::perform(
|
||||
list_hardware_wallets(&[], None),
|
||||
Message::ConnectedHardwareWallets,
|
||||
)
|
||||
}
|
||||
fn update(&mut self, message: Message) -> Command<Message> {
|
||||
match message {
|
||||
@ -276,9 +279,12 @@ async fn get_extended_pubkey(
|
||||
.get_extended_pubkey(&derivation_path, true)
|
||||
.await
|
||||
.map_err(Error::from)?;
|
||||
Ok(DescriptorPublicKey::XPub(DescriptorXKey {
|
||||
Ok(DescriptorPublicKey::MultiXPub(DescriptorMultiXKey {
|
||||
origin: Some((fingerprint, derivation_path)),
|
||||
derivation_path: DerivationPath::master(),
|
||||
derivation_paths: vec![
|
||||
DerivationPath::from_str("m/0").unwrap(),
|
||||
DerivationPath::from_str("m/1").unwrap(),
|
||||
],
|
||||
xkey,
|
||||
wildcard: Wildcard::Unhardened,
|
||||
}))
|
||||
@ -286,7 +292,7 @@ async fn get_extended_pubkey(
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RegisterDescriptor {
|
||||
descriptor: Option<InheritanceDescriptor>,
|
||||
descriptor: Option<MultipathDescriptor>,
|
||||
processing: bool,
|
||||
chosen_hw: Option<usize>,
|
||||
hws: Vec<(HardwareWallet, Option<[u8; 32]>)>,
|
||||
@ -348,11 +354,21 @@ impl Step for RegisterDescriptor {
|
||||
};
|
||||
Command::none()
|
||||
}
|
||||
fn apply(&mut self, _ctx: &mut Context) -> bool {
|
||||
fn apply(&mut self, ctx: &mut Context) -> bool {
|
||||
for (hw, token) in &self.hws {
|
||||
if let Some(token) = token {
|
||||
if *token != [0x00; 32] {
|
||||
ctx.hw_tokens.push((hw.kind, hw.fingerprint, *token));
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
fn load(&self) -> Command<Message> {
|
||||
Command::perform(list_hardware_wallets(), Message::ConnectedHardwareWallets)
|
||||
Command::perform(
|
||||
list_hardware_wallets(&[], None),
|
||||
Message::ConnectedHardwareWallets,
|
||||
)
|
||||
}
|
||||
fn view(&self) -> Element<Message> {
|
||||
let desc = self.descriptor.as_ref().unwrap();
|
||||
|
||||
@ -5,10 +5,11 @@ use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
|
||||
use async_hwi::DeviceKind;
|
||||
use iced::{pure::Element, Command};
|
||||
use minisafe::{
|
||||
config::{BitcoinConfig, BitcoindConfig},
|
||||
descriptors::InheritanceDescriptor,
|
||||
descriptors::MultipathDescriptor,
|
||||
miniscript::bitcoin,
|
||||
};
|
||||
|
||||
@ -40,7 +41,8 @@ pub trait Step {
|
||||
pub struct Context {
|
||||
pub bitcoin_config: BitcoinConfig,
|
||||
pub bitcoind_config: Option<BitcoindConfig>,
|
||||
pub descriptor: Option<InheritanceDescriptor>,
|
||||
pub descriptor: Option<MultipathDescriptor>,
|
||||
pub hw_tokens: Vec<(DeviceKind, bitcoin::util::bip32::Fingerprint, [u8; 32])>,
|
||||
pub data_dir: Option<PathBuf>,
|
||||
}
|
||||
|
||||
@ -51,6 +53,7 @@ impl Context {
|
||||
network,
|
||||
poll_interval_secs: Duration::from_secs(30),
|
||||
},
|
||||
hw_tokens: Vec::new(),
|
||||
bitcoind_config: None,
|
||||
descriptor: None,
|
||||
data_dir,
|
||||
|
||||
@ -81,7 +81,7 @@ pub fn fake_daemon_config() -> Config {
|
||||
toml::from_str(
|
||||
r#"
|
||||
data_dir = "/home/edouard/code/revault/demo/minisafe/datadir"
|
||||
main_descriptor = "wsh(or_d(pk(tpubDCbK3Ysvk8HjcF6mPyrgMu3KgLiaaP19RjKpNezd8GrbAbNg6v5BtWLaCt8FNm6QkLseopKLf5MNYQFtochDTKHdfgG6iqJ8cqnLNAwtXuP/*),and_v(v:pkh(tpubDDtb2WPYwEWw2WWDV7reLV348iJHw2HmhzvPysKKrJw3hYmvrd4jasyoioVPdKGQqjyaBMEvTn1HvHWDSVqQ6amyyxRZ5YjpPBBGjJ8yu8S/*),older(100))))#459t6xxr"
|
||||
main_descriptor = "wsh(or_d(pk(tpubDCbK3Ysvk8HjcF6mPyrgMu3KgLiaaP19RjKpNezd8GrbAbNg6v5BtWLaCt8FNm6QkLseopKLf5MNYQFtochDTKHdfgG6iqJ8cqnLNAwtXuP/<0;1>/*),and_v(v:pkh(tpubDDtb2WPYwEWw2WWDV7reLV348iJHw2HmhzvPysKKrJw3hYmvrd4jasyoioVPdKGQqjyaBMEvTn1HvHWDSVqQ6amyyxRZ5YjpPBBGjJ8yu8S/<0;1>/*),older(100))))#9sx3g3pv"
|
||||
|
||||
[bitcoin_config]
|
||||
network = "regtest"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user