Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
edouardparis committed Jan 4, 2024
1 parent 3e0b15c commit 1b53c1d
Show file tree
Hide file tree
Showing 6 changed files with 522 additions and 84 deletions.
2 changes: 1 addition & 1 deletion gui/src/app/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ pub enum Message {
SpendTxs(Result<Vec<SpendTx>, Error>),
Psbt(Result<Psbt, Error>),
Recovery(Result<SpendTx, Error>),
Signed(Result<(Psbt, Fingerprint), Error>),
Signed(Fingerprint, Result<Psbt, Error>),
WalletRegistered(Result<Fingerprint, Error>),
Updated(Result<(), Error>),
Saved(Result<(), Error>),
Expand Down
157 changes: 82 additions & 75 deletions gui/src/app/state/psbt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use liana::{
miniscript::bitcoin::{bip32::Fingerprint, psbt::Psbt, Network},
};

use liana_ui::component::toast;
use liana_ui::{
component::{form, modal},
widget::Element,
Expand Down Expand Up @@ -138,6 +139,11 @@ impl PsbtState {
self.action = Some(PsbtAction::Delete(DeleteAction::default()));
}
view::SpendTxMessage::Sign => {
if let Some(PsbtAction::Sign(SignAction { display, .. })) = &mut self.action {
*display = true;
return Command::none();
}

let action = SignAction::new(
self.tx.signers(),
self.wallet.clone(),
Expand Down Expand Up @@ -365,12 +371,12 @@ impl Action for DeleteAction {

pub struct SignAction {
wallet: Arc<Wallet>,
chosen_hw: Option<usize>,
processing: bool,
hws: HardwareWallets,
error: Option<Error>,
signing: HashSet<Fingerprint>,
signed: HashSet<Fingerprint>,
is_saved: bool,
display: bool,
}

impl SignAction {
Expand All @@ -382,13 +388,13 @@ impl SignAction {
is_saved: bool,
) -> Self {
Self {
chosen_hw: None,
processing: false,
signing: HashSet::new(),
hws: HardwareWallets::new(datadir_path, network).with_wallet(wallet.clone()),
wallet,
error: None,
signed,
is_saved,
display: true,
}
}
}
Expand Down Expand Up @@ -416,61 +422,61 @@ impl Action for SignAction {
..
}) = self.hws.list.get(i)
{
self.chosen_hw = Some(i);
self.processing = true;
self.display = false;
self.signing.insert(*fingerprint);
let psbt = tx.psbt.clone();
let fingerprint = *fingerprint;
return Command::perform(
sign_psbt(self.wallet.clone(), device.clone(), *fingerprint, psbt),
Message::Signed,
sign_psbt(self.wallet.clone(), device.clone(), psbt),
move |res| Message::Signed(fingerprint, res),
);
}
}
Message::View(view::Message::Spend(view::SpendTxMessage::SelectHotSigner)) => {
self.processing = true;
return Command::perform(
sign_psbt_with_hot_signer(self.wallet.clone(), tx.psbt.clone()),
Message::Signed,
|(fg, res)| Message::Signed(fg, res),
);
}
Message::Signed(res) => match res {
Err(e) => self.error = Some(e),
Ok((psbt, fingerprint)) => {
self.error = None;
self.signed.insert(fingerprint);
let daemon = daemon.clone();
tx.psbt = psbt.clone();
if self.is_saved {
return Command::perform(
async move { daemon.update_spend_tx(&psbt).map_err(|e| e.into()) },
Message::Updated,
);
// If the spend transaction was never saved before, then both the psbt and
// labels attached to it must be updated.
} else {
let mut labels = HashMap::<LabelItem, Option<String>>::new();
for (item, label) in tx.labels() {
if !label.is_empty() {
labels.insert(label_item_from_str(item), Some(label.clone()));
Message::Signed(fingerprint, res) => {
self.signing.remove(&fingerprint);
match res {
Err(e) => self.error = Some(e),
Ok(psbt) => {
self.error = None;
self.signed.insert(fingerprint);
let daemon = daemon.clone();
tx.psbt = psbt.clone();
if self.is_saved {
return Command::perform(
async move { daemon.update_spend_tx(&psbt).map_err(|e| e.into()) },
Message::Updated,
);
// If the spend transaction was never saved before, then both the psbt and
// labels attached to it must be updated.
} else {
let mut labels = HashMap::<LabelItem, Option<String>>::new();
for (item, label) in tx.labels() {
if !label.is_empty() {
labels.insert(label_item_from_str(item), Some(label.clone()));
}
}
return Command::perform(
async move {
daemon.update_spend_tx(&psbt)?;
daemon.update_labels(&labels).map_err(|e| e.into())
},
Message::Updated,
);
}
return Command::perform(
async move {
daemon.update_spend_tx(&psbt)?;
daemon.update_labels(&labels).map_err(|e| e.into())
},
Message::Updated,
);
}
}
},
}
Message::Updated(res) => match res {
Ok(()) => {
self.processing = false;
match self.wallet.main_descriptor.partial_spend_info(&tx.psbt) {
Ok(sigs) => tx.sigs = sigs,
Err(e) => self.error = Some(Error::Unexpected(e.to_string())),
}
}
Ok(()) => match self.wallet.main_descriptor.partial_spend_info(&tx.psbt) {
Ok(sigs) => tx.sigs = sigs,
Err(e) => self.error = Some(Error::Unexpected(e.to_string())),
},
Err(e) => self.error = Some(e),
},

Expand All @@ -482,56 +488,57 @@ impl Action for SignAction {
self.error = Some(e.into());
}
},
Message::View(view::Message::Reload) => {
self.chosen_hw = None;
self.error = None;
return self.load(daemon);
}
_ => {}
};
Command::none()
}
fn view<'a>(&'a self, content: Element<'a, view::Message>) -> Element<'a, view::Message> {
modal::Modal::new(
content,
view::psbt::sign_action(
self.error.as_ref(),
&self.hws.list,
self.wallet.signer.as_ref().map(|s| s.fingerprint()),
self.wallet
.signer
.as_ref()
.and_then(|signer| self.wallet.keys_aliases.get(&signer.fingerprint)),
self.processing,
self.chosen_hw,
&self.signed,
),
)
.on_blur(Some(view::Message::Spend(view::SpendTxMessage::Cancel)))
.into()
if self.display {
modal::Modal::new(
content,
view::psbt::sign_action(
self.error.as_ref(),
&self.hws.list,
self.wallet.signer.as_ref().map(|s| s.fingerprint()),
self.wallet
.signer
.as_ref()
.and_then(|signer| self.wallet.keys_aliases.get(&signer.fingerprint)),
&self.signed,
&self.signing,
),
)
.on_blur(Some(view::Message::Spend(view::SpendTxMessage::Cancel)))
.into()
} else {
toast::Manager::new(content, &[("currently signing", "yes")]).into()
}
}
}

async fn sign_psbt_with_hot_signer(
wallet: Arc<Wallet>,
psbt: Psbt,
) -> Result<(Psbt, Fingerprint), Error> {
) -> (Fingerprint, Result<Psbt, Error>) {
if let Some(signer) = &wallet.signer {
let psbt = signer.sign_psbt(psbt).map_err(|e| {
WalletError::HotSigner(format!("Hot signer failed to sign psbt: {}", e))
})?;
Ok((psbt, signer.fingerprint()))
let res = signer
.sign_psbt(psbt)
.map_err(|e| WalletError::HotSigner(format!("Hot signer failed to sign psbt: {}", e)))
.map_err(|e| e.into());
(signer.fingerprint(), res)
} else {
Err(WalletError::HotSigner("Hot signer not loaded".to_string()).into())
(
Fingerprint::default(),
Err(WalletError::HotSigner("Hot signer not loaded".to_string()).into()),
)
}
}

async fn sign_psbt(
wallet: Arc<Wallet>,
hw: std::sync::Arc<dyn async_hwi::HWI + Send + Sync>,
fingerprint: Fingerprint,
mut psbt: Psbt,
) -> Result<(Psbt, Fingerprint), Error> {
) -> Result<Psbt, Error> {
// The BitBox02 is only going to produce a signature for a single key in the Script. In order
// to make sure it doesn't sign for a public key from another spending path we remove the BIP32
// derivation for the other paths.
Expand Down Expand Up @@ -560,7 +567,7 @@ async fn sign_psbt(
} else {
hw.sign_tx(&mut psbt).await.map_err(Error::from)?;
}
Ok((psbt, fingerprint))
Ok(psbt)
}

pub struct UpdateAction {
Expand Down
7 changes: 3 additions & 4 deletions gui/src/app/view/hw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ use async_hwi::DeviceKind;
pub fn hw_list_view(
i: usize,
hw: &HardwareWallet,
chosen: bool,
processing: bool,
signed: bool,
signing: bool,
) -> Element<Message> {
let mut bttn = Button::new(match hw {
HardwareWallet::Supported {
Expand All @@ -24,7 +23,7 @@ pub fn hw_list_view(
registered,
..
} => {
if chosen && processing {
if signing {
hw::processing_hardware_wallet(kind, version.as_ref(), fingerprint, alias.as_ref())
} else if signed {
hw::sign_success_hardware_wallet(
Expand Down Expand Up @@ -61,7 +60,7 @@ pub fn hw_list_view(
})
.style(theme::Button::Border)
.width(Length::Fill);
if !processing {
if !signing {
if let HardwareWallet::Supported { registered, .. } = hw {
if *registered != Some(false) {
bttn = bttn.on_press(Message::SelectHardwareWallet(i));
Expand Down
8 changes: 4 additions & 4 deletions gui/src/app/view/psbt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -945,9 +945,8 @@ pub fn sign_action<'a>(
hws: &'a [HardwareWallet],
signer: Option<Fingerprint>,
signer_alias: Option<&'a String>,
processing: bool,
chosen_hw: Option<usize>,
signed: &HashSet<Fingerprint>,
signing: &HashSet<Fingerprint>,
) -> Element<'a, Message> {
Column::new()
.push_maybe(warning.map(|w| warn(Some(w))))
Expand All @@ -967,11 +966,12 @@ pub fn sign_action<'a>(
col.push(hw_list_view(
i,
hw,
Some(i) == chosen_hw,
processing,
hw.fingerprint()
.map(|f| signed.contains(&f))
.unwrap_or(false),
hw.fingerprint()
.map(|f| signing.contains(&f))
.unwrap_or(false),
))
},
))
Expand Down
1 change: 1 addition & 0 deletions gui/ui/src/component/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod hw;
pub mod modal;
pub mod notification;
pub mod text;
pub mod toast;
pub mod tooltip;

pub use tooltip::tooltip;
Expand Down
Loading

0 comments on commit 1b53c1d

Please sign in to comment.