1use std::fmt::Debug;
24use std::path::{Path, PathBuf};
25
26use bpstd::{Network, XpubDerivable};
27use clap::ValueHint;
28use descriptors::{Descriptor, StdDescr, TrKey, Wpkh};
29use strict_encoding::Ident;
30
31pub const DATA_DIR_ENV: &str = "LNPBP_DATA_DIR";
32#[cfg(any(target_os = "linux"))]
33pub const DATA_DIR: &str = "~/.lnp-bp";
34#[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))]
35pub const DATA_DIR: &str = "~/.lnp-bp";
36#[cfg(target_os = "macos")]
37pub const DATA_DIR: &str = "~/Library/Application Support/LNP-BP Suite";
38#[cfg(target_os = "windows")]
39pub const DATA_DIR: &str = "~\\AppData\\Local\\LNP-BP Suite";
40#[cfg(target_os = "ios")]
41pub const DATA_DIR: &str = "~/Documents";
42#[cfg(target_os = "android")]
43pub const DATA_DIR: &str = ".";
44
45pub const DEFAULT_ELECTRUM: &str = "example.com:50001";
46pub const DEFAULT_ESPLORA: &str = "https://blockstream.info/testnet/api";
47
48#[derive(Args, Clone, PartialEq, Eq, Debug)]
49pub struct ResolverOpt {
50 #[arg(
52 conflicts_with = "esplora",
53 long,
54 global = true,
55 default_value = DEFAULT_ELECTRUM,
56 env = "ELECRTUM_SERVER",
57 value_hint = ValueHint::Url,
58 value_name = "URL"
59 )]
60 pub electrum: String,
61
62 #[arg(
64 conflicts_with = "electrum",
65 long,
66 global = true,
67 default_value = DEFAULT_ESPLORA,
68 env = "ESPLORA_SERVER",
69 value_hint = ValueHint::Url,
70 value_name = "URL"
71 )]
72 pub esplora: String,
73
74 #[clap(long, global = true)]
75 pub sync: bool,
76}
77
78pub trait DescriptorOpts: clap::Args + Clone + Eq + Debug {
79 type Descr: Descriptor + serde::Serialize + for<'de> serde::Deserialize<'de>;
80 fn is_some(&self) -> bool;
81 fn descriptor(&self) -> Option<Self::Descr>;
82}
83
84#[derive(Args, Clone, PartialEq, Eq, Debug)]
85#[group(multiple = false)]
86pub struct DescrStdOpts {
87 #[arg(long, global = true)]
89 pub wpkh: Option<XpubDerivable>,
90
91 #[arg(long, global = true)]
93 pub tr_key_only: Option<XpubDerivable>,
94}
95
96impl DescriptorOpts for DescrStdOpts {
97 type Descr = StdDescr;
98
99 fn is_some(&self) -> bool { self.tr_key_only.is_some() | self.wpkh.is_some() }
100 fn descriptor(&self) -> Option<Self::Descr> {
101 if let Some(ref x) = self.tr_key_only {
102 Some(TrKey::from(x.clone()).into())
103 } else if let Some(ref x) = self.wpkh {
104 Some(Wpkh::from(x.clone()).into())
105 } else {
106 None
107 }
108 }
109}
110
111#[derive(Args, Clone, PartialEq, Eq, Debug)]
112#[group(multiple = false)]
113pub struct WalletOpts<O: DescriptorOpts = DescrStdOpts> {
114 #[arg(short = 'w', long = "wallet", global = true)]
115 pub name: Option<Ident>,
116
117 #[arg(
119 short = 'W',
120 long,
121 global = true,
122 value_hint = ValueHint::DirPath,
123 )]
124 pub wallet_path: Option<PathBuf>,
125
126 #[clap(flatten)]
127 pub descriptor_opts: O,
128}
129
130#[derive(Args, Clone, PartialEq, Eq, Debug)]
131pub struct GeneralOpts {
132 #[arg(
136 short,
137 long,
138 global = true,
139 default_value = DATA_DIR,
140 env = DATA_DIR_ENV,
141 value_hint = ValueHint::DirPath
142 )]
143 pub data_dir: PathBuf,
144
145 #[arg(short, long, global = true, default_value = "testnet", env = "LNPBP_NETWORK")]
147 pub network: Network,
148}
149
150impl GeneralOpts {
151 pub fn process(&mut self) {
152 self.data_dir =
153 PathBuf::from(shellexpand::tilde(&self.data_dir.display().to_string()).to_string());
154 }
155
156 pub fn base_dir(&self) -> PathBuf {
157 let mut dir = self.data_dir.clone();
158 dir.push(self.network.to_string());
159 dir
160 }
161
162 pub fn wallet_dir(&self, wallet_name: impl AsRef<Path>) -> PathBuf {
163 let mut dir = self.base_dir();
164 dir.push(wallet_name);
165 dir
166 }
167}