cdk_mintd/env_vars/
mod.rs1#![allow(missing_docs)]
2mod common;
8mod database;
9mod info;
10mod limits;
11mod mint_info;
12mod onchain;
13mod payment_backend;
14mod signatory;
15
16mod auth;
17#[cfg(feature = "bdk")]
18mod bdk;
19#[cfg(feature = "cln")]
20mod cln;
21#[cfg(feature = "fakewallet")]
22mod fake_wallet;
23#[cfg(feature = "grpc-processor")]
24mod grpc_processor;
25#[cfg(feature = "ldk-node")]
26mod ldk_node;
27#[cfg(feature = "lnd")]
28mod lnd;
29#[cfg(feature = "management-rpc")]
30mod management_rpc;
31#[cfg(feature = "prometheus")]
32mod prometheus;
33
34use std::env;
35use std::str::FromStr;
36
37use anyhow::{anyhow, bail, Result};
38pub use auth::*;
39#[cfg(feature = "bdk")]
40pub use bdk::*;
41#[cfg(feature = "cln")]
42pub use cln::*;
43pub use common::*;
44pub use database::*;
45#[cfg(feature = "fakewallet")]
46pub use fake_wallet::*;
47#[cfg(feature = "grpc-processor")]
48pub use grpc_processor::*;
49#[cfg(feature = "ldk-node")]
50pub use ldk_node::*;
51pub use limits::*;
52#[cfg(feature = "lnd")]
53pub use lnd::*;
54#[cfg(feature = "management-rpc")]
55pub use management_rpc::*;
56pub use mint_info::*;
57pub use onchain::*;
58pub use payment_backend::*;
59#[cfg(feature = "prometheus")]
60pub use prometheus::*;
61
62use crate::config::{DatabaseEngine, OnchainBackend, PaymentBackend, PaymentBackendType, Settings};
63
64fn bool_override(name: &str) -> Option<bool> {
67 env::var_os(name).map(
68 |value| match value.to_str().and_then(|value| value.parse().ok()) {
69 Some(value) => value,
70 None => {
71 tracing::warn!("Invalid boolean environment override {name}; using false");
72 false
73 }
74 },
75 )
76}
77
78impl Settings {
79 pub fn from_env(&mut self) -> Result<Self> {
80 if let Ok(database) = env::var(DATABASE_ENV_VAR) {
81 let engine = DatabaseEngine::from_str(&database).map_err(|err| anyhow!(err))?;
82 self.database.engine = engine;
83 }
84
85 if self.database.engine == DatabaseEngine::Postgres {
87 self.database.postgres = Some(
88 self.database
89 .postgres
90 .clone()
91 .unwrap_or_default()
92 .from_env(),
93 );
94 }
95
96 self.auth_database = Some(crate::config::AuthDatabase {
98 postgres: Some(
99 self.auth_database
100 .clone()
101 .unwrap_or_default()
102 .postgres
103 .unwrap_or_default()
104 .from_env(),
105 ),
106 });
107
108 self.info = self.info.clone().from_env();
109 self.signatory = Some(self.signatory.clone().unwrap_or_default().from_env());
110
111 self.mint_info = self.mint_info.clone().from_env();
112 match self.payment_backend.len() {
117 0 => {
118 let backend = PaymentBackend::default().from_env();
119 if backend.backend != PaymentBackendType::None {
120 self.payment_backend.push(backend);
121 }
122 }
123 1 => {
124 self.payment_backend[0] = self.payment_backend[0].clone().from_env();
125 }
126 _ => {
127 tracing::warn!(
128 "CDK_MINTD_PAYMENT_BACKEND_* environment variables ignored: multiple [[payment_backend]] entries configured"
129 );
130 }
131 }
132 self.onchain = Some(self.onchain.clone().unwrap_or_default().from_env());
133 self.limits = self.limits.clone().from_env();
134
135 {
136 let auth = self.auth.clone().unwrap_or_default().from_env();
138
139 if auth.auth_enabled {
141 self.auth = Some(auth);
142 } else {
143 self.auth = None;
144 }
145 }
146
147 #[cfg(feature = "management-rpc")]
148 {
149 self.mint_management_rpc = Some(
150 self.mint_management_rpc
151 .clone()
152 .unwrap_or_default()
153 .from_env(),
154 );
155 }
156
157 #[cfg(feature = "prometheus")]
158 {
159 self.prometheus = Some(self.prometheus.clone().unwrap_or_default().from_env());
160 }
161
162 #[cfg(feature = "cln")]
163 {
164 let cln = self.cln.clone().unwrap_or_default().from_env();
165 if cln.rpc_path.as_os_str().is_empty() {
166 self.cln = None;
167 } else {
168 self.cln = Some(cln);
169 }
170 }
171
172 #[cfg(feature = "fakewallet")]
173 {
174 let fake_wallet_supported_units_from_env =
176 env::var(ENV_FAKE_WALLET_SUPPORTED_UNITS).is_ok();
177 let fake_wallet = self.fake_wallet.clone().unwrap_or_default().from_env();
178 let supported_units_configured =
179 fake_wallet.supported_units != vec![cdk::nuts::CurrencyUnit::Sat];
180
181 if fake_wallet_supported_units_from_env || supported_units_configured {
182 self.expand_single_fake_wallet_backend_entry(&fake_wallet);
183 }
184
185 self.fake_wallet = Some(fake_wallet);
186 }
187
188 #[cfg(feature = "lnd")]
189 {
190 let lnd = self.lnd.clone().unwrap_or_default().from_env()?;
191 if lnd.address.is_empty() {
192 self.lnd = None;
193 } else {
194 self.lnd = Some(lnd);
195 }
196 }
197
198 #[cfg(feature = "ldk-node")]
199 {
200 let ldk_node = self.ldk_node.clone().unwrap_or_default().from_env();
201 if ldk_node.bitcoin_network.is_none()
202 && ldk_node.esplora_url.is_none()
203 && ldk_node.electrum_url.is_none()
204 {
205 self.ldk_node = None;
206 } else {
207 self.ldk_node = Some(ldk_node);
208 }
209 }
210
211 #[cfg(feature = "grpc-processor")]
212 {
213 let grpc_processor = self.grpc_processor.clone().unwrap_or_default().from_env();
214 let grpc_processor_configured = self
215 .payment_backend
216 .iter()
217 .any(|backend| backend.backend == PaymentBackendType::GrpcProcessor);
218 if grpc_processor.supported_units.is_empty() && !grpc_processor_configured {
219 self.grpc_processor = None;
220 } else {
221 self.grpc_processor = Some(grpc_processor);
222 }
223 }
224
225 #[cfg(feature = "bdk")]
226 {
227 let bdk = self.bdk.clone().unwrap_or_default().from_env();
228 if bdk.network.is_none() && bdk.mnemonic.is_none() {
229 self.bdk = None;
230 } else {
231 self.bdk = Some(bdk);
232 }
233 }
234
235 for payment_backend in &self.payment_backend {
236 match payment_backend.backend {
237 #[cfg(feature = "cln")]
238 PaymentBackendType::Cln => {}
239 #[cfg(feature = "fakewallet")]
240 PaymentBackendType::FakeWallet => {}
241 #[cfg(feature = "lnd")]
242 PaymentBackendType::Lnd => {}
243 #[cfg(feature = "ldk-node")]
244 PaymentBackendType::LdkNode => {}
245 #[cfg(feature = "grpc-processor")]
246 PaymentBackendType::GrpcProcessor => {}
247 PaymentBackendType::None => {}
248 #[allow(unreachable_patterns)]
249 _ => bail!("Selected payment backend is not enabled in this build"),
250 }
251 }
252
253 let has_payment_backend = self
254 .payment_backend
255 .iter()
256 .any(|backend| backend.backend != PaymentBackendType::None);
257 let has_onchain_backend = self
258 .onchain
259 .as_ref()
260 .map(|onchain| onchain.onchain_backend != OnchainBackend::None)
261 .unwrap_or(false);
262 if !has_payment_backend && !has_onchain_backend {
263 bail!("At least one payment backend must be set");
264 }
265
266 self.validate_backend_pairing()
267 .map_err(|err| anyhow!(err))?;
268
269 Ok(self.clone())
270 }
271
272 #[cfg(feature = "fakewallet")]
273 fn expand_single_fake_wallet_backend_entry(&mut self, fake_wallet: &crate::config::FakeWallet) {
274 let fake_wallet_backend_index = self
275 .payment_backend
276 .iter()
277 .enumerate()
278 .filter_map(|(index, backend)| {
279 (backend.backend == PaymentBackendType::FakeWallet).then_some(index)
280 })
281 .collect::<Vec<_>>();
282
283 if fake_wallet_backend_index.len() != 1 {
284 return;
285 }
286
287 let mut units = Vec::new();
288 for unit in &fake_wallet.supported_units {
289 if !units.contains(unit) {
290 units.push(unit.clone());
291 }
292 }
293
294 if units.is_empty() {
295 return;
296 }
297
298 let index = fake_wallet_backend_index[0];
299 let base_backend = self.payment_backend[index].clone();
300 let expanded_backends = units.into_iter().map(|unit| PaymentBackend {
301 unit,
302 ..base_backend.clone()
303 });
304
305 self.payment_backend
306 .splice(index..=index, expanded_backends);
307 }
308}