Merge #1756: Add an option for add a descriptor from file/backup for liana-connect
31798b7e4317125e671e2d52e28e9ddc16815bf0 export: allow to import a backup from a simple descriptor (pythcoiner) 54c83615b070a982ec99f3c58278ecabba8a264e export: add test cases for import_descriptor() (pythcoiner) d66b596cf930597254b1e48426c9488fd77d210d import: allow to import a descriptor from a backup in export::import_descriptor() (pythcoiner) 53839e92744b24e1365c3b57108b350c729b17b5 gui: add a spacer below the main column at Add wallet step in liana-connect flow (pythcoiner) 4bb4269975e0469205c96751bcbf24311177d53d gui: add import descriptor from file feature in liana-connect flow (pythcoiner) Pull request description: This PR closes #1751: - add the option to import a descriptor from a file. - add a spacer at the bottom of the screen. - add the possibility to import also a descriptor from a backup file. ACKs for top commit: edouardparis: ACK 31798b7e4317125e671e2d52e28e9ddc16815bf0 Tree-SHA512: 7e5ae0f3bbc4af1d779e1cd97e9cadceabe62317f857c895d9f5de49ed84f81c1da1df8df4d935ff0b1c2a040e1fa03f598bbdc6d64e82b225089c884c774743
This commit is contained in:
commit
eff5894da6
@ -1,7 +1,10 @@
|
||||
use chrono::{Duration, Utc};
|
||||
use liana::miniscript::{
|
||||
self,
|
||||
bitcoin::{bip32::Fingerprint, Network, Txid},
|
||||
use liana::{
|
||||
descriptors::LianaDescriptor,
|
||||
miniscript::{
|
||||
self,
|
||||
bitcoin::{bip32::Fingerprint, Network, Txid},
|
||||
},
|
||||
};
|
||||
use lianad::{
|
||||
bip329,
|
||||
@ -111,6 +114,23 @@ impl Debug for Backup {
|
||||
}
|
||||
|
||||
impl Backup {
|
||||
/// Create a Backup from a descriptor
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `descriptor` - the descriptor
|
||||
/// * `network` - the network
|
||||
pub fn from_descriptor(descriptor: LianaDescriptor, network: Network) -> Self {
|
||||
let account = Account::new(descriptor.to_string());
|
||||
Backup {
|
||||
name: None,
|
||||
alias: None,
|
||||
accounts: vec![account],
|
||||
network,
|
||||
date: None,
|
||||
proprietary: Default::default(),
|
||||
version: default_version(),
|
||||
}
|
||||
}
|
||||
/// Create a Backup from the Installer context
|
||||
///
|
||||
/// # Arguments
|
||||
|
||||
@ -246,7 +246,7 @@ pub enum Progress {
|
||||
WalletFromBackup(
|
||||
(
|
||||
LianaDescriptor,
|
||||
Network,
|
||||
Option<Network>,
|
||||
HashMap<Fingerprint, settings::KeySetting>,
|
||||
Backup,
|
||||
),
|
||||
@ -637,7 +637,19 @@ pub async fn import_descriptor(
|
||||
file.read_to_string(&mut descr_str)?;
|
||||
let descr_str = descr_str.trim();
|
||||
|
||||
let descriptor = LianaDescriptor::from_str(descr_str).map_err(|_| Error::ParseDescriptor)?;
|
||||
let descriptor = if let Ok(d) = LianaDescriptor::from_str(descr_str) {
|
||||
Some(d)
|
||||
} else {
|
||||
let backup: Result<Backup, _> = serde_json::from_str(descr_str);
|
||||
backup.ok().and_then(|b| {
|
||||
if b.accounts.len() == 1 {
|
||||
LianaDescriptor::from_str(&b.accounts[0].descriptor).ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
};
|
||||
let descriptor = descriptor.ok_or(Error::ParseDescriptor)?;
|
||||
|
||||
send_progress!(sender, Progress(100.0));
|
||||
send_progress!(sender, Descriptor(descriptor));
|
||||
@ -1033,13 +1045,33 @@ pub async fn wallet_from_backup(
|
||||
|
||||
let backup: Result<Backup, _> = serde_json::from_str(&backup_str);
|
||||
let backup = match backup {
|
||||
Ok(psbt) => psbt,
|
||||
Ok(b) => b,
|
||||
Err(e) => {
|
||||
return Err(Error::BackupImport(format!("{:?}", e)));
|
||||
// try to import as bare descriptor
|
||||
let descr = LianaDescriptor::from_str(&backup_str);
|
||||
match descr {
|
||||
Ok(descr) => {
|
||||
let network = if descr.all_xpubs_net_is(Network::Bitcoin) {
|
||||
Network::Bitcoin
|
||||
} else {
|
||||
Network::Signet
|
||||
};
|
||||
Backup::from_descriptor(descr, network)
|
||||
}
|
||||
Err(e2) => {
|
||||
return Err(Error::BackupImport(format!(
|
||||
"A backup or descriptor file is expected: {e}, {e2}"
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let network = backup.network;
|
||||
let network = if backup.network == Network::Bitcoin {
|
||||
Some(backup.network)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let account = match backup.accounts.len() {
|
||||
0 => {
|
||||
@ -1274,8 +1306,44 @@ pub async fn app_backup_export(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::env;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_import_descriptor_from_file() {
|
||||
let (sender, mut receiver) = unbounded_channel();
|
||||
let path = env::current_dir()
|
||||
.unwrap()
|
||||
.join("test_assets")
|
||||
.join("liana-jz5sm0xn.txt");
|
||||
println!("path: {}", path.display());
|
||||
import_descriptor(&sender, path).await.unwrap();
|
||||
let _msg = receiver.try_recv().unwrap();
|
||||
assert!(matches!(Progress::Progress(100.0), _msg));
|
||||
let raw_descriptor = "wsh(or_d(pk([8a550171/48'/1'/0'/2']tpubDFnCs5ZaCqopaNhgLCiXAwbkaBdcnuMt1VFoPsRpUrpidyvzG67MYjkfxw6HnTBhHqeU3xw2ioNBVcWY3jXwGhSyppEQvtn38GsL7RH1eef/<0;1>/*),and_v(v:pkh([8a550171/48'/1'/0'/2']tpubDFnCs5ZaCqopaNhgLCiXAwbkaBdcnuMt1VFoPsRpUrpidyvzG67MYjkfxw6HnTBhHqeU3xw2ioNBVcWY3jXwGhSyppEQvtn38GsL7RH1eef/<2;3>/*),older(52596))))#jz5sm0xn";
|
||||
let descr = LianaDescriptor::from_str(raw_descriptor).unwrap();
|
||||
let _msg = receiver.try_recv().unwrap();
|
||||
assert!(matches!(Progress::Descriptor(descr), _msg));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_import_descriptor_from_backup_file() {
|
||||
let (sender, mut receiver) = unbounded_channel();
|
||||
let path = env::current_dir()
|
||||
.unwrap()
|
||||
.join("test_assets")
|
||||
.join("liana-backup-2025-06-23T13-23-54.json");
|
||||
println!("path: {}", path.display());
|
||||
import_descriptor(&sender, path).await.unwrap();
|
||||
let _msg = receiver.try_recv().unwrap();
|
||||
assert!(matches!(Progress::Progress(100.0), _msg));
|
||||
let raw_descriptor = "wsh(or_d(pk([8a550171/48'/1'/0'/2']tpubDFnCs5ZaCqopaNhgLCiXAwbkaBdcnuMt1VFoPsRpUrpidyvzG67MYjkfxw6HnTBhHqeU3xw2ioNBVcWY3jXwGhSyppEQvtn38GsL7RH1eef/<0;1>/*),and_v(v:pkh([8a550171/48'/1'/0'/2']tpubDFnCs5ZaCqopaNhgLCiXAwbkaBdcnuMt1VFoPsRpUrpidyvzG67MYjkfxw6HnTBhHqeU3xw2ioNBVcWY3jXwGhSyppEQvtn38GsL7RH1eef/<2;3>/*),older(52596))))#jz5sm0xn";
|
||||
let descr = LianaDescriptor::from_str(raw_descriptor).unwrap();
|
||||
let _msg = receiver.try_recv().unwrap();
|
||||
assert!(matches!(Progress::Descriptor(descr), _msg));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_coldcard_xpub() {
|
||||
let raw = r#"
|
||||
|
||||
@ -117,6 +117,8 @@ pub enum ImportRemoteWallet {
|
||||
InvitationFetched(Result<api::WalletInvitation, Error>),
|
||||
AcceptInvitation,
|
||||
InvitationAccepted(Result<api::Wallet, Error>),
|
||||
ImportDescriptorFromFile,
|
||||
ImportExport(ImportExportMessage),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
||||
@ -1,13 +1,15 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use iced::Task;
|
||||
use iced::{Subscription, Task};
|
||||
|
||||
use liana::{descriptors::LianaDescriptor, miniscript::bitcoin::Network};
|
||||
use liana_ui::{component::form, widget::Element};
|
||||
|
||||
use crate::{
|
||||
app::state::export::ExportModal,
|
||||
daemon::DaemonError,
|
||||
dir::NetworkDirectory,
|
||||
export::{ImportExportMessage, ImportExportType, Progress},
|
||||
hw::HardwareWallets,
|
||||
installer::{
|
||||
context::{self, Context, RemoteBackend},
|
||||
@ -448,6 +450,7 @@ pub struct ImportRemoteWallet {
|
||||
error: Option<String>,
|
||||
backend: context::RemoteBackend,
|
||||
wallets: Vec<api::Wallet>,
|
||||
modal: Option<ExportModal>,
|
||||
// wallet alias is stored here to be applied to context
|
||||
// and be modified in a following step
|
||||
wallet_alias: Option<String>,
|
||||
@ -464,6 +467,7 @@ impl ImportRemoteWallet {
|
||||
error: None,
|
||||
backend: context::RemoteBackend::Undefined,
|
||||
wallets: Vec::new(),
|
||||
modal: None,
|
||||
wallet_alias: None,
|
||||
}
|
||||
}
|
||||
@ -502,6 +506,37 @@ impl Step for ImportRemoteWallet {
|
||||
// Verification of the values is happening when the user click on Next button.
|
||||
fn update(&mut self, _hws: &mut HardwareWallets, message: Message) -> Task<Message> {
|
||||
match message {
|
||||
Message::ImportRemoteWallet(message::ImportRemoteWallet::ImportDescriptorFromFile) => {
|
||||
let modal = ExportModal::new(None, ImportExportType::ImportDescriptor);
|
||||
let launch = modal.launch(false);
|
||||
self.modal = Some(modal);
|
||||
return launch;
|
||||
}
|
||||
Message::ImportExport(ImportExportMessage::Path(p)) => {
|
||||
if let Some(modal) = self.modal.as_mut() {
|
||||
return modal.update(ImportExportMessage::Path(p));
|
||||
}
|
||||
}
|
||||
Message::ImportExport(ImportExportMessage::Close) => self.modal = None,
|
||||
Message::ImportRemoteWallet(message::ImportRemoteWallet::ImportExport(m)) => match m {
|
||||
ImportExportMessage::Close => self.modal = None,
|
||||
ImportExportMessage::Progress(Progress::Descriptor(d)) => {
|
||||
self.modal = None;
|
||||
return Task::batch([
|
||||
Task::done(Message::ImportRemoteWallet(
|
||||
message::ImportRemoteWallet::ImportDescriptor(d.to_string()),
|
||||
)),
|
||||
Task::done(Message::ImportRemoteWallet(
|
||||
message::ImportRemoteWallet::ConfirmDescriptor,
|
||||
)),
|
||||
]);
|
||||
}
|
||||
m => {
|
||||
if let Some(modal) = self.modal.as_mut() {
|
||||
return modal.update(m);
|
||||
}
|
||||
}
|
||||
},
|
||||
Message::ImportRemoteWallet(message::ImportRemoteWallet::ImportDescriptor(desc)) => {
|
||||
self.imported_descriptor.value = desc;
|
||||
if !self.imported_descriptor.value.is_empty() {
|
||||
@ -643,6 +678,19 @@ impl Step for ImportRemoteWallet {
|
||||
Task::none()
|
||||
}
|
||||
|
||||
fn subscription(&self, _hws: &HardwareWallets) -> iced::Subscription<Message> {
|
||||
if let Some(modal) = &self.modal {
|
||||
if let Some(sub) = modal.subscription() {
|
||||
return sub.map(|m| {
|
||||
Message::ImportRemoteWallet(message::ImportRemoteWallet::ImportExport(
|
||||
ImportExportMessage::Progress(m),
|
||||
))
|
||||
});
|
||||
}
|
||||
}
|
||||
Subscription::none()
|
||||
}
|
||||
|
||||
fn apply(&mut self, ctx: &mut Context) -> bool {
|
||||
// Set to true in order to force the registration process to be shown to user.
|
||||
ctx.hw_is_used = true;
|
||||
@ -662,7 +710,7 @@ impl Step for ImportRemoteWallet {
|
||||
progress: (usize, usize),
|
||||
email: Option<&'a str>,
|
||||
) -> Element<Message> {
|
||||
view::import_wallet_or_descriptor(
|
||||
let content = view::import_wallet_or_descriptor(
|
||||
progress,
|
||||
email,
|
||||
&self.invitation_token,
|
||||
@ -675,7 +723,12 @@ impl Step for ImportRemoteWallet {
|
||||
.iter()
|
||||
.map(|w| (&w.name, w.metadata.wallet_alias.as_ref()))
|
||||
.collect(),
|
||||
)
|
||||
);
|
||||
if let Some(modal) = &self.modal {
|
||||
modal.view(content)
|
||||
} else {
|
||||
content
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -120,12 +120,26 @@ impl Step for ImportDescriptor {
|
||||
}
|
||||
Message::ImportExport(ImportExportMessage::Progress(Progress::WalletFromBackup(r))) => {
|
||||
let (descriptor, network, aliases, backup) = r;
|
||||
if self.network == network {
|
||||
self.imported_backup = Some(backup);
|
||||
self.imported_descriptor.value = descriptor.to_string();
|
||||
self.imported_aliases = Some(aliases);
|
||||
if let Some(n) = network {
|
||||
if self.network == n {
|
||||
self.imported_backup = Some(backup);
|
||||
self.imported_descriptor.value = descriptor.to_string();
|
||||
self.imported_aliases = Some(aliases);
|
||||
} else {
|
||||
self.error =
|
||||
Some("Backup network do not match the selected network!".into());
|
||||
}
|
||||
} else {
|
||||
self.error = Some("Backup network do not match the selected network!".into());
|
||||
// The backup have been inferred from a bare descriptor, we check whether
|
||||
// the descriptor match any test network
|
||||
if self.network != Network::Bitcoin {
|
||||
self.imported_backup = Some(backup);
|
||||
self.imported_descriptor.value = descriptor.to_string();
|
||||
self.imported_aliases = Some(aliases);
|
||||
} else {
|
||||
self.error =
|
||||
Some("Backup network do not match the selected network!".into());
|
||||
}
|
||||
}
|
||||
}
|
||||
Message::ImportExport(m) => {
|
||||
|
||||
@ -233,6 +233,12 @@ pub fn import_wallet_or_descriptor<'a>(
|
||||
.size(text::P1_SIZE)
|
||||
.padding(10),
|
||||
)
|
||||
.push(text("or").bold())
|
||||
.push(button::primary(None, "Import descriptor").on_press(
|
||||
Message::ImportRemoteWallet(
|
||||
message::ImportRemoteWallet::ImportDescriptorFromFile,
|
||||
),
|
||||
))
|
||||
.spacing(10),
|
||||
)
|
||||
.push(
|
||||
@ -268,7 +274,8 @@ pub fn import_wallet_or_descriptor<'a>(
|
||||
.push_maybe(error.map(|e| card::error("Something wrong happened", e.to_string())))
|
||||
.push(card_wallets)
|
||||
.push(card::simple(col_invitation_token).padding(0))
|
||||
.push(card::simple(col_descriptor).padding(0)),
|
||||
.push(card::simple(col_descriptor).padding(0))
|
||||
.push(Space::with_height(10)),
|
||||
true,
|
||||
Some(Message::Previous),
|
||||
)
|
||||
|
||||
69
liana-gui/test_assets/liana-backup-2025-06-23T13-23-54.json
Normal file
69
liana-gui/test_assets/liana-backup-2025-06-23T13-23-54.json
Normal file
@ -0,0 +1,69 @@
|
||||
{
|
||||
"name": "Liana-jz5sm0xn",
|
||||
"alias": "My Liana Regtest wallet",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "Liana-jz5sm0xn",
|
||||
"descriptor": "wsh(or_d(pk([8a550171/48'/1'/0'/2']tpubDFnCs5ZaCqopaNhgLCiXAwbkaBdcnuMt1VFoPsRpUrpidyvzG67MYjkfxw6HnTBhHqeU3xw2ioNBVcWY3jXwGhSyppEQvtn38GsL7RH1eef/<0;1>/*),and_v(v:pkh([8a550171/48'/1'/0'/2']tpubDFnCs5ZaCqopaNhgLCiXAwbkaBdcnuMt1VFoPsRpUrpidyvzG67MYjkfxw6HnTBhHqeU3xw2ioNBVcWY3jXwGhSyppEQvtn38GsL7RH1eef/<2;3>/*),older(52596))))#jz5sm0xn",
|
||||
"receive_index": 1,
|
||||
"change_index": 2,
|
||||
"timestamp": 1748013169,
|
||||
"keys": {
|
||||
"8a550171": {
|
||||
"key": "8a550171",
|
||||
"alias": "a"
|
||||
}
|
||||
},
|
||||
"labels": [],
|
||||
"transactions": [
|
||||
"020000000001042e410675d4d1b009e257ca11345502e5c1f00709590db95e2ac9fe1a11044d4d0000000000fdffffff2503d8712de399f674baab16b844a54870bd2142650c609edb3d1cd60bcbf77b0000000000fdffffff4e093e78a81157ebcb11780bfe010fc0752231015d0c2a8114630ac7c6c159c50000000000fdffffffb5e6c596c3659f7af56ebaa9e8ae618c5ac7f338033172e9475f1933f04e348a0000000000fdffffff02d263060000000000225120e49d1997805dbb7290369fb95f94451b0ca3e738119b9c6b6e5a70a33384913100e1f50500000000220020fd22758b64471a67371158c546ab5918732659085eb21c9af6591cb811e56c660247304402203c379630bf2b827abf013ef8ed6a37a18dfc98fef28199a208bc19bc68b441f40220248456a96302579d0739ce8dbc63550835961a811198859aaa250c8611e46466012103df49913c09de6d937101041d2e413a09e5991ba3ef31534d88054b319d2d74510247304402202a8e2ffcaa86fef2fc40caf21d0d59b4801ad553701b4466c2872e5ac3ffb23f02200f10f5493543f8c4fe37627a7ad6bfa93b01a22873983656003ababe9d6c4ca60121031337b42040d5f2700ba46ae7cf70dc172c2b4f695313a8ed0fe62ea843278e6c0247304402204ee9ae50ff1bbde05832236fdea9f3709a4d9fa87014cf86a63e9333641c737c02206394e7124539adf560f76ddbb87ec4614d9a9e70ac995c88d1b2b6e614ab4e430121034547cd6c5fe44edbc9af9193df5a9a7fc0055c3f47b968e92ae30d6630a6cd08024730440220135820533d687ed853e92f7e52ef73de755f13ace2db60f5f85a07681bd62e2a022015290d93eb8b0d53f17c2851f2fb53ba2859ee15aacb0a188041f46f249101100121029f4c9445023494227a966609268d0db59bf82eb21433188470bbdcdd63f5508caf5d0000"
|
||||
],
|
||||
"psbts": [
|
||||
"cHNidP8BAF4CAAAAAcb4e2jUBqxxBTgMZFk6JUCes6Q3cvgpYJ2uJDUOBbudAQAAAAD9////AX3g9QUAAAAAIgAgCkktj1GAtl5qSGMFiltgrcw2ozjyaWF4XBktdHaUItuyXQAAAAEA/bICAgAAAAABBC5BBnXU0bAJ4lfKETRVAuXB8AcJWQ25XirJ/hoRBE1NAAAAAAD9////JQPYcS3jmfZ0uqsWuESlSHC9IUJlDGCe2z0c1gvL93sAAAAAAP3///9OCT54qBFX68sReAv+AQ/AdSIxAV0MKoEUYwrHxsFZxQAAAAAA/f///7XmxZbDZZ969W66qeiuYYxax/M4AzFy6UdfGTPwTjSKAAAAAAD9////AtJjBgAAAAAAIlEg5J0Zl4Bdu3KQNp+5X5RFGwyj5zgRm5xrblpwozOEkTEA4fUFAAAAACIAIP0idYtkRxpnNxFYxUarWRhzJlkIXrIcmvZZHLgR5WxmAkcwRAIgPDeWML8rgnq/AT747Wo3oY38mP7ygZmiCLwZvGi0QfQCICSEVqljAledBznOjbxjVQg1lhqBEZiFmqolDIYR5GRmASED30mRPAnebZNxAQQdLkE6CeWZG6PvMVNNiAVLMZ0tdFECRzBEAiAqji/8qob+8vxAyvIdDVm0gBrVU3AbRGbChy5aw/+yPwIgDxD1STVD+MT+N2J6eta/qTsBoihzmDZWADq6vp1sTKYBIQMTN7QgQNXycAukaufPcNwXLCtPaVMTqO0P5i6oQyeObAJHMEQCIE7prlD/G73gWDIjb96p83CaTZ+ocBTPhqY+kzNkHHN8AiBjlOcSRTmt9WD3bdu4fsRhTZqecKyZXIjRsrbmFKtOQwEhA0VHzWxf5E7bya+Rk99amn/ABVw/R7lo6SrjDWYwps0IAkcwRAIgE1ggUz1ofthT6S9+Uu9z3nVfE6zi22D1+FoHaBvWLioCIBUpDZPriw1T8XwoUfL7U7ooWe4VqssKGIBB9G8kkQEQASECn0yURQI0lCJ6lmYJJo0NtZv4LrIUMxiEcLvc3WP1UIyvXQAAAQErAOH1BQAAAAAiACD9InWLZEcaZzcRWMVGq1kYcyZZCF6yHJr2WRy4EeVsZiICA2vrvUCtFrmnsdsUyMDb2kT4uowEfiQ5D/1l+cWZ1vDWRzBEAiAaM9aLqBTG5C4tK9p9c28Jz439Emr7XPoxUYyJllYLMAIgFA6/yH55PAeZedfY2h6at7dB/k/wPf8M3+y0IEcQgKIBIgIDio+/H1qygPy0Phj9olT5VctStZGyB6qVDiVdlfiIWTpHMEQCIGUetlDH7qqci2rSxbHnvoqcs1pEJHgaLbRAnMPjffv1AiBHhT5DcOQhVhn0vtXO8Ij5ii3BafsK9VX2SN2l9H1/9QEBBUQhA2vrvUCtFrmnsdsUyMDb2kT4uowEfiQ5D/1l+cWZ1vDWrHNkdqkUXG6thIRwLnqHwJdmKl7XWxiKxDyIrQN0zQCyaCIGA2vrvUCtFrmnsdsUyMDb2kT4uowEfiQ5D/1l+cWZ1vDWHIpVAXEwAACAAQAAgAAAAIACAACAAAAAAAEAAAAiBgOKj78fWrKA/LQ+GP2iVPlVy1K1kbIHqpUOJV2V+IhZOhyKVQFxMAAAgAEAAIAAAACAAgAAgAIAAAABAAAAACICA1BIFqUUMoNtx4WVqTmwuL2iEpyL6ZLAflqiZpCHcVveHIpVAXEwAACAAQAAgAAAAIACAACAAwAAAAIAAAAiAgO+QA+pMN6tM8/CHiT8Rt32H2jEOY2nZpV2rV/QYKGJEhyKVQFxMAAAgAEAAIAAAACAAgAAgAEAAAACAAAAAA=="
|
||||
],
|
||||
"coins": {
|
||||
"9dbb050e3524ae9d6029f87237a4b39e40253a59640c380571ac06d4687bf8c6:1": {
|
||||
"amount": 100000000,
|
||||
"outpoint": "9dbb050e3524ae9d6029f87237a4b39e40253a59640c380571ac06d4687bf8c6:1",
|
||||
"address": "bcrt1ql538tzmygudxwdc3trz5d26erpejvkggt6epexhktywtsy09d3nqzqf3d4",
|
||||
"block_height": 23984,
|
||||
"account": 0,
|
||||
"derivation_index": 1,
|
||||
"is_coinbase": null,
|
||||
"is_from_self": false
|
||||
}
|
||||
},
|
||||
"chain_tip": {
|
||||
"block_height": 24332,
|
||||
"block_hash": null
|
||||
},
|
||||
"proprietary": {
|
||||
"config": {
|
||||
"debug": null,
|
||||
"log_level": null,
|
||||
"start_internal_bitcoind": false
|
||||
},
|
||||
"liana_version": "11.0",
|
||||
"settings": {
|
||||
"alias": "My Liana Regtest wallet",
|
||||
"descriptor_checksum": "jz5sm0xn",
|
||||
"hardware_wallets": [],
|
||||
"keys": [
|
||||
{
|
||||
"master_fingerprint": "8a550171",
|
||||
"name": "a",
|
||||
"provider_key": null
|
||||
}
|
||||
],
|
||||
"name": "Liana-jz5sm0xn",
|
||||
"pinned_at": 1748013169,
|
||||
"remote_backend_auth": null,
|
||||
"start_internal_bitcoind": false
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"network": "regtest",
|
||||
"date": 1750677837,
|
||||
"version": 0
|
||||
}
|
||||
1
liana-gui/test_assets/liana-jz5sm0xn.txt
Normal file
1
liana-gui/test_assets/liana-jz5sm0xn.txt
Normal file
@ -0,0 +1 @@
|
||||
wsh(or_d(pk([8a550171/48'/1'/0'/2']tpubDFnCs5ZaCqopaNhgLCiXAwbkaBdcnuMt1VFoPsRpUrpidyvzG67MYjkfxw6HnTBhHqeU3xw2ioNBVcWY3jXwGhSyppEQvtn38GsL7RH1eef/<0;1>/*),and_v(v:pkh([8a550171/48'/1'/0'/2']tpubDFnCs5ZaCqopaNhgLCiXAwbkaBdcnuMt1VFoPsRpUrpidyvzG67MYjkfxw6HnTBhHqeU3xw2ioNBVcWY3jXwGhSyppEQvtn38GsL7RH1eef/<2;3>/*),older(52596))))#jz5sm0xn
|
||||
Loading…
x
Reference in New Issue
Block a user