Skip to content

Commit f1fcf26

Browse files
edouardparispythcoiner
authored and
pythcoiner
committed
gui: use descriptor method to detect psbt change outputs
This commit also fix handling of create_spend result while updating liana:master close #841
1 parent b47c8c2 commit f1fcf26

File tree

7 files changed

+57
-15
lines changed

7 files changed

+57
-15
lines changed

gui/Cargo.lock

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gui/src/app/state/recovery.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ use std::sync::Arc;
44

55
use iced::Command;
66

7-
use liana::miniscript::bitcoin::bip32::{DerivationPath, Fingerprint};
7+
use liana::miniscript::bitcoin::{
8+
bip32::{DerivationPath, Fingerprint},
9+
secp256k1,
10+
};
811
use liana_ui::{component::form, widget::Element};
912

1013
use crate::{
@@ -162,7 +165,14 @@ impl State for RecoveryPanel {
162165
.any(|input| input.previous_output == coin.outpoint)
163166
})
164167
.collect();
165-
Ok(SpendTx::new(None, psbt, coins, &desc, network))
168+
Ok(SpendTx::new(
169+
None,
170+
psbt,
171+
coins,
172+
&desc,
173+
&secp256k1::Secp256k1::verification_only(),
174+
network,
175+
))
166176
},
167177
Message::Recovery,
168178
);

gui/src/app/state/spend/step.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use liana_ui::{component::form, widget::Element};
1919
use crate::{
2020
app::{cache::Cache, error::Error, message::Message, state::psbt, view, wallet::Wallet},
2121
daemon::{
22-
model::{remaining_sequence, Coin, SpendTx},
22+
model::{remaining_sequence, Coin, CreateSpendResult, SpendTx},
2323
Daemon,
2424
},
2525
};
@@ -382,8 +382,16 @@ impl Step for DefineSpend {
382382
async move {
383383
daemon
384384
.create_spend_tx(&inputs, &outputs, feerate_vb)
385-
.map(|res| res.psbt)
386385
.map_err(|e| e.into())
386+
.and_then(|res| match res {
387+
CreateSpendResult::Success { psbt, .. } => Ok(psbt),
388+
CreateSpendResult::InsufficientFunds { missing } => {
389+
Err(SpendCreationError::CoinSelection(
390+
liana::spend::InsufficientFunds { missing },
391+
)
392+
.into())
393+
}
394+
})
387395
},
388396
Message::Psbt,
389397
);
@@ -576,13 +584,15 @@ impl Recipient {
576584
pub struct SaveSpend {
577585
wallet: Arc<Wallet>,
578586
spend: Option<psbt::PsbtState>,
587+
curve: secp256k1::Secp256k1<secp256k1::VerifyOnly>,
579588
}
580589

581590
impl SaveSpend {
582591
pub fn new(wallet: Arc<Wallet>) -> Self {
583592
Self {
584593
wallet,
585594
spend: None,
595+
curve: secp256k1::Secp256k1::verification_only(),
586596
}
587597
}
588598
}
@@ -595,6 +605,7 @@ impl Step for SaveSpend {
595605
psbt,
596606
draft.inputs.clone(),
597607
&self.wallet.main_descriptor,
608+
&self.curve,
598609
draft.network,
599610
);
600611
tx.labels = draft.labels.clone();

gui/src/app/state/transactions.rs

+17-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ use std::{
55
};
66

77
use iced::Command;
8-
use liana::{miniscript::bitcoin::Txid, spend::MAX_FEERATE};
8+
use liana::{
9+
miniscript::bitcoin::Txid,
10+
spend::{SpendCreationError, MAX_FEERATE},
11+
};
912
use liana_ui::{
1013
component::{form, modal::Modal},
1114
widget::*,
@@ -20,7 +23,7 @@ use crate::app::{
2023
};
2124

2225
use crate::daemon::{
23-
model::{HistoryTransaction, Labelled},
26+
model::{CreateSpendResult, HistoryTransaction, Labelled},
2427
Daemon,
2528
};
2629

@@ -302,7 +305,18 @@ impl CreateRbfModal {
302305
self.warning = None;
303306

304307
let psbt = match daemon.rbf_psbt(&self.txid, self.is_cancel, self.feerate_vb) {
305-
Ok(res) => res.psbt,
308+
Ok(res) => match res {
309+
CreateSpendResult::Success { psbt, .. } => psbt,
310+
CreateSpendResult::InsufficientFunds { missing } => {
311+
self.warning = Some(
312+
SpendCreationError::CoinSelection(
313+
liana::spend::InsufficientFunds { missing },
314+
)
315+
.into(),
316+
);
317+
return Command::none();
318+
}
319+
},
306320
Err(e) => {
307321
self.warning = Some(e.into());
308322
return Command::none();

gui/src/daemon/client/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::collections::{HashMap, HashSet};
22
use std::fmt::Debug;
33
use std::iter::FromIterator;
44

5+
use liana::commands::CreateRecoveryResult;
56
use serde::de::DeserializeOwned;
67
use serde::{Deserialize, Serialize};
78
use serde_json::json;
@@ -154,7 +155,7 @@ impl<C: Client + Debug> Daemon for Lianad<C> {
154155
feerate_vb: u64,
155156
sequence: Option<u16>,
156157
) -> Result<Psbt, DaemonError> {
157-
let res: CreateSpendResult = self.call(
158+
let res: CreateRecoveryResult = self.call(
158159
"createrecovery",
159160
Some(vec![json!(address), json!(feerate_vb), json!(sequence)]),
160161
)?;

gui/src/daemon/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::iter::FromIterator;
1010
use liana::{
1111
commands::LabelItem,
1212
config::Config,
13-
miniscript::bitcoin::{address, psbt::Psbt, Address, OutPoint, Txid},
13+
miniscript::bitcoin::{address, psbt::Psbt, secp256k1, Address, OutPoint, Txid},
1414
StartupError,
1515
};
1616

@@ -102,6 +102,7 @@ pub trait Daemon: Debug {
102102
let info = self.get_info()?;
103103
let coins = self.list_coins()?.coins;
104104
let mut spend_txs = Vec::new();
105+
let curve = secp256k1::Secp256k1::verification_only();
105106
for tx in self.list_spend_txs()?.spend_txs {
106107
if let Some(txids) = txids {
107108
if !txids.contains(&tx.psbt.unsigned_tx.txid()) {
@@ -125,6 +126,7 @@ pub trait Daemon: Debug {
125126
tx.psbt,
126127
coins,
127128
&info.descriptors.main,
129+
&curve,
128130
info.network,
129131
));
130132
}

gui/src/daemon/model.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub use liana::{
1111
miniscript::bitcoin::{
1212
bip32::{DerivationPath, Fingerprint},
1313
psbt::Psbt,
14-
Address, Amount, Network, OutPoint, Transaction, Txid,
14+
secp256k1, Address, Amount, Network, OutPoint, Transaction, Txid,
1515
},
1616
};
1717

@@ -61,15 +61,19 @@ impl SpendTx {
6161
psbt: Psbt,
6262
coins: Vec<Coin>,
6363
desc: &LianaDescriptor,
64+
secp: &secp256k1::Secp256k1<impl secp256k1::Verification>,
6465
network: Network,
6566
) -> Self {
6667
let max_vbytes = desc.unsigned_tx_max_vbytes(&psbt.unsigned_tx);
67-
let mut change_indexes = Vec::new();
68+
let change_indexes: Vec<usize> = desc
69+
.change_indexes(&psbt, secp)
70+
.into_iter()
71+
.map(|c| c.index())
72+
.collect();
6873
let (change_amount, spend_amount) = psbt.unsigned_tx.output.iter().enumerate().fold(
6974
(Amount::from_sat(0), Amount::from_sat(0)),
7075
|(change, spend), (i, output)| {
71-
if !psbt.outputs[i].bip32_derivation.is_empty() {
72-
change_indexes.push(i);
76+
if change_indexes.contains(&i) {
7377
(change + output.value, spend)
7478
} else {
7579
(change, spend + output.value)

0 commit comments

Comments
 (0)