installer: add signer to participate wallet process

This commit is contained in:
edouard 2023-02-10 18:23:27 +01:00
parent 233f9b1886
commit 037c4d025d
3 changed files with 155 additions and 23 deletions

View File

@ -21,6 +21,7 @@ pub enum Message {
Close,
Reload,
Select(usize),
UseHotSigner,
Installed(Result<PathBuf, Error>),
Network(Network),
DefineBitcoind(DefineBitcoind),
@ -45,7 +46,6 @@ pub enum DefineDescriptor {
HWXpubImported(Result<DescriptorPublicKey, Error>),
XPubEdited(String),
EditName,
UseHotSigner,
NameEdited(String),
SequenceEdited(String),
ThresholdEdited(bool, usize),

View File

@ -658,7 +658,7 @@ impl DescriptorKeyModal for EditXpubModal {
self.hws = Vec::new();
return self.load();
}
Message::DefineDescriptor(message::DefineDescriptor::UseHotSigner) => {
Message::UseHotSigner => {
self.chosen_hw = None;
self.chosen_signer = true;
self.form_xpub.valid = true;
@ -841,6 +841,12 @@ impl HardwareWalletXpubs {
}
}
fn reset(&mut self) {
self.error = None;
self.next_account = ChildNumber::from_hardened_idx(0).unwrap();
self.xpubs = Vec::new();
}
fn select(&mut self, i: usize, network: Network) -> Command<Message> {
if let HardwareWallet::Supported {
device,
@ -878,6 +884,42 @@ impl HardwareWalletXpubs {
}
}
pub struct SignerXpubs {
signer: Arc<Signer>,
xpubs: Vec<String>,
next_account: ChildNumber,
}
impl SignerXpubs {
fn new(signer: Arc<Signer>) -> Self {
Self {
signer,
xpubs: Vec::new(),
next_account: ChildNumber::from_hardened_idx(0).unwrap(),
}
}
fn reset(&mut self) {
self.xpubs = Vec::new();
self.next_account = ChildNumber::from_hardened_idx(0).unwrap();
}
fn select(&mut self, network: Network) {
let derivation_path = generate_derivation_path(network, self.next_account);
self.next_account = self.next_account.increment().unwrap();
self.xpubs.push(format!(
"[{}{}]{}/<0;1>/*",
self.signer.fingerprint(),
derivation_path.to_string().trim_start_matches('m'),
self.signer.get_extended_pubkey(&derivation_path)
));
}
pub fn view(&self) -> Element<Message> {
view::signer_xpubs(&self.xpubs)
}
}
pub struct ParticipateXpub {
network: Network,
network_valid: bool,
@ -886,6 +928,7 @@ pub struct ParticipateXpub {
shared: bool,
xpubs_hw: Vec<HardwareWalletXpubs>,
xpubs_signer: SignerXpubs,
}
impl ParticipateXpub {
@ -896,8 +939,30 @@ impl ParticipateXpub {
data_dir: None,
xpubs_hw: Vec::new(),
shared: false,
xpubs_signer: SignerXpubs::new(Arc::new(Signer::generate(Network::Bitcoin).unwrap())),
}
}
fn set_network(&mut self, network: Network) {
if network != self.network {
self.xpubs_hw.iter_mut().for_each(|hw| hw.reset());
self.xpubs_signer.reset();
}
self.network = network;
if let Some(signer) = Arc::get_mut(&mut self.xpubs_signer.signer) {
signer.set_network(network);
}
if let Some(mut network_datadir) = self.data_dir.clone() {
network_datadir.push(self.network.to_string());
self.network_valid = !network_datadir.exists();
}
}
}
impl Default for ParticipateXpub {
fn default() -> Self {
Self::new()
}
}
impl Step for ParticipateXpub {
@ -906,10 +971,7 @@ impl Step for ParticipateXpub {
fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::Network(network) => {
self.network = network;
let mut network_datadir = self.data_dir.clone().unwrap();
network_datadir.push(self.network.to_string());
self.network_valid = !network_datadir.exists();
self.set_network(network);
}
Message::UserActionDone(shared) => self.shared = shared,
Message::ImportXpub(i, res) => {
@ -917,6 +979,9 @@ impl Step for ParticipateXpub {
hw.update(res);
}
}
Message::UseHotSigner => {
self.xpubs_signer.select(self.network);
}
Message::Select(i) => {
if let Some(hw) = self.xpubs_hw.get_mut(i) {
return hw.select(i, self.network);
@ -943,11 +1008,8 @@ impl Step for ParticipateXpub {
}
fn load_context(&mut self, ctx: &Context) {
self.network = ctx.bitcoin_config.network;
self.data_dir = Some(ctx.data_dir.clone());
let mut network_datadir = ctx.data_dir.clone();
network_datadir.push(self.network.to_string());
self.network_valid = !network_datadir.exists();
self.set_network(ctx.bitcoin_config.network);
}
fn load(&self) -> Command<Message> {
@ -961,6 +1023,11 @@ impl Step for ParticipateXpub {
ctx.bitcoin_config.network = self.network;
// Drop connections to hardware wallets.
self.xpubs_hw = Vec::new();
if !self.xpubs_signer.xpubs.is_empty() {
ctx.signer = Some(self.xpubs_signer.signer.clone());
} else {
ctx.signer = None;
}
true
}
@ -974,17 +1041,12 @@ impl Step for ParticipateXpub {
.enumerate()
.map(|(i, hw)| hw.view(i))
.collect(),
self.xpubs_signer.view(),
self.shared,
)
}
}
impl Default for ParticipateXpub {
fn default() -> Self {
Self::new()
}
}
impl From<ParticipateXpub> for Box<dyn Step> {
fn from(s: ParticipateXpub) -> Box<dyn Step> {
Box::new(s)

View File

@ -411,6 +411,76 @@ pub fn import_descriptor<'a>(
)
}
pub fn signer_xpubs(xpubs: &Vec<String>) -> Element<Message> {
Container::new(
Column::new()
.push(
Button::new(
Row::new().align_items(Alignment::Center).push(
Column::new()
.push(text("This computer").bold())
.push(
text("Derive a key from a mnemonic stored on this computer")
.small(),
)
.spacing(5)
.width(Length::Fill),
),
)
.on_press(Message::UseHotSigner)
.padding(10)
.style(button::Style::TransparentBorder.into())
.width(Length::Fill),
)
.push_maybe(if xpubs.is_empty() {
None
} else {
Some(separation().width(Length::Fill))
})
.push_maybe(if xpubs.is_empty() {
None
} else {
Some(xpubs.iter().fold(Column::new().padding(15), |col, xpub| {
col.push(
Row::new()
.spacing(5)
.align_items(Alignment::Center)
.push(
Container::new(
Scrollable::new(Container::new(text(xpub).small()).padding(10))
.horizontal_scroll(
Properties::new().width(2).scroller_width(2),
),
)
.width(Length::Fill),
)
.push(
Container::new(
button::border(Some(icon::clipboard_icon()), "Copy")
.on_press(Message::Clibpboard(xpub.clone()))
.width(Length::Shrink),
)
.padding(10),
),
)
}))
})
.push_maybe(if !xpubs.is_empty() {
Some(
Container::new(
button::border(Some(icon::plus_icon()), "New public key")
.on_press(Message::UseHotSigner),
)
.padding(10),
)
} else {
None
}),
)
.style(card::SimpleCardStyle)
.into()
}
pub fn hardware_wallet_xpubs<'a>(
i: usize,
xpubs: &'a Vec<String>,
@ -531,13 +601,14 @@ pub fn hardware_wallet_xpubs<'a>(
.into()
}
pub fn participate_xpub(
pub fn participate_xpub<'a>(
progress: (usize, usize),
network: bitcoin::Network,
network_valid: bool,
hws: Vec<Element<Message>>,
hws: Vec<Element<'a, Message>>,
signer: Element<'a, Message>,
shared: bool,
) -> Element<Message> {
) -> Element<'a, Message> {
let row_network = Row::new()
.spacing(10)
.align_items(Alignment::Center)
@ -583,6 +654,7 @@ pub fn participate_xpub(
)
.spacing(10)
.push(Column::with_children(hws).spacing(10))
.push(signer)
.width(Length::Fill),
)
.push(Checkbox::new(
@ -1138,7 +1210,7 @@ pub fn edit_key_modal<'a>(
.spacing(5)
.push(text("This computer").bold())
.push(
text("Derive a key from a mnemonic stored on the computer").small(),
text("Derive a key from a mnemonic stored on this computer").small(),
)
.width(Length::Fill),
)
@ -1150,9 +1222,7 @@ pub fn edit_key_modal<'a>(
.spacing(10),
)
.width(Length::Fill)
.on_press(Message::DefineDescriptor(
message::DefineDescriptor::UseHotSigner,
))
.on_press(Message::UseHotSigner)
.style(button::Style::Border.into()),
)
.width(Length::Fill),