bark/
config.rs

1
2use std::fmt;
3use std::path::{Path, PathBuf};
4
5use anyhow::Context;
6use bitcoin::{FeeRate, Network};
7
8use bitcoin_ext::{BlockDelta, BlockHeight};
9
10
11/// Networks bark can be used on
12#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
13pub enum BarkNetwork {
14	/// Bitcoin's mainnet
15	Mainnet,
16	/// The official Bitcoin Core signet
17	Signet,
18	/// Mutinynet
19	Mutinynet,
20	/// Any regtest network
21	Regtest,
22}
23
24impl BarkNetwork {
25	/// Map to the [Network] types
26	pub fn as_bitcoin(&self) -> Network {
27		match self {
28			Self::Mainnet => Network::Bitcoin,
29			Self::Signet => Network::Signet,
30			Self::Mutinynet => Network::Signet,
31			Self::Regtest => Network::Regtest,
32		}
33	}
34}
35
36impl fmt::Display for BarkNetwork {
37	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38	    match self {
39			Self::Mainnet => f.write_str("mainnet"),
40			Self::Signet => f.write_str("signet"),
41			Self::Mutinynet => f.write_str("mutinynet"),
42			Self::Regtest => f.write_str("regtest"),
43		}
44	}
45}
46
47impl fmt::Debug for BarkNetwork {
48	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49		fmt::Display::fmt(self, f)
50	}
51}
52
53/// Configuration of the Bark wallet.
54///
55/// - [Config::esplora_address] or [Config::bitcoind_address] must be provided.
56/// - If you use [Config::bitcoind_address], you must also provide:
57///   - [Config::bitcoind_cookiefile] or
58///   - [Config::bitcoind_user] and [Config::bitcoind_pass]
59/// - Other optional fields can be omitted.
60///
61/// # Example
62/// Configure the wallet using defaults, then override endpoints for public signet:
63///
64/// ```rust
65/// use bark::Config;
66///
67/// let cfg = Config {
68///   server_address: "https://ark.signet.2nd.dev".into(),
69///   esplora_address: Some("https://esplora.signet.2nd.dev".into()),
70///   ..Config::network_default(bitcoin::Network::Bitcoin)
71/// };
72/// // cfg now has all other fields from the default configuration
73/// ```
74#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct Config {
76	/// The address of your ark server.
77	pub server_address: String,
78
79	/// The address of the Esplora HTTP REST server to use.
80	///
81	/// Either this or the `bitcoind_address` field has to be provided.
82	pub esplora_address: Option<String>,
83
84	/// The address of the bitcoind RPC server to use.
85	///
86	/// Either this or the `esplora_address` field has to be provided.
87	/// Either `bitcoind_cookiefile` or `bitcoind_user` and `bitcoind_pass` has to be provided.
88	pub bitcoind_address: Option<String>,
89
90	/// The path to the bitcoind rpc cookie file.
91	///
92	/// Only used with `bitcoind_address`.
93	pub bitcoind_cookiefile: Option<PathBuf>,
94
95	/// The bitcoind RPC username.
96	///
97	/// Only used with `bitcoind_address`.
98	pub bitcoind_user: Option<String>,
99
100	/// The bitcoind RPC password.
101	///
102	/// Only used with `bitcoind_address`.
103	pub bitcoind_pass: Option<String>,
104
105	/// The number of blocks before expiration to refresh vtxos.
106	///
107	/// Default value: 144 (24h) for mainnet, 12 for testnets
108	pub vtxo_refresh_expiry_threshold: BlockHeight,
109
110	/// An upper limit of the number of blocks we expect to need to
111	/// safely exit the vtxos.
112	///
113	/// Default value: 12
114	pub vtxo_exit_margin: BlockDelta,
115
116	/// The number of blocks to claim a HTLC-recv VTXO.
117	///
118	/// Default value: 18
119	pub htlc_recv_claim_delta: BlockDelta,
120
121	/// A fallback fee rate to use in sat/kWu when we fail to retrieve a fee rate from the
122	/// configured bitcoind/esplora connection.
123	///
124	/// Example for 1 sat/vB: --fallback-fee-rate 250
125	pub fallback_fee_rate: Option<FeeRate>,
126
127	/// The number of confirmations required before considering a round tx
128	/// fully confirmed
129	///
130	/// Default value: 6 for mainnet, 2 for testnets
131	pub round_tx_required_confirmations: BlockHeight,
132}
133
134impl Config {
135	/// A network-dependent default config that sets some useful defaults
136	///
137	/// The [Default::default] provides a sane default for mainnet
138	pub fn network_default(network: Network) -> Self {
139		let mut ret = Self {
140			server_address: "http://127.0.0.1:3535".to_owned(),
141			esplora_address: None,
142			bitcoind_address: None,
143			bitcoind_cookiefile: None,
144			bitcoind_user: None,
145			bitcoind_pass: None,
146			vtxo_refresh_expiry_threshold: 144,
147			vtxo_exit_margin: 12,
148			htlc_recv_claim_delta: 18,
149			fallback_fee_rate: None,
150			round_tx_required_confirmations: 6,
151		};
152
153		if network != Network::Bitcoin {
154			ret.vtxo_refresh_expiry_threshold = 12;
155			ret.fallback_fee_rate = Some(FeeRate::from_sat_per_vb_unchecked(1));
156			ret.round_tx_required_confirmations = 2;
157		}
158
159		ret
160	}
161
162	/// Load config from the config file path, filling missing fields
163	/// from the network default
164	pub fn load(network: Network, path: impl AsRef<Path>) -> anyhow::Result<Config> {
165		let default = config::Config::try_from(&Self::network_default(network))
166			.expect("default config failed to deconstruct");
167
168		Ok(config::Config::builder()
169			.add_source(default)
170			.add_source(config::File::from(path.as_ref()))
171			.build().context("error building config")?
172			.try_deserialize::<Config>().context("error parsing config")?)
173	}
174}
175