setup.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. #[cfg(feature = "fakewallet")]
  2. use std::collections::HashMap;
  3. #[cfg(feature = "fakewallet")]
  4. use std::collections::HashSet;
  5. use std::path::Path;
  6. use std::sync::Arc;
  7. #[cfg(feature = "cln")]
  8. use anyhow::anyhow;
  9. use async_trait::async_trait;
  10. use axum::Router;
  11. #[cfg(feature = "fakewallet")]
  12. use bip39::rand::{thread_rng, Rng};
  13. use cdk::cdk_database::MintKVStore;
  14. use cdk::cdk_payment::MintPayment;
  15. use cdk::nuts::CurrencyUnit;
  16. #[cfg(any(
  17. feature = "lnbits",
  18. feature = "cln",
  19. feature = "lnd",
  20. feature = "ldk-node",
  21. feature = "fakewallet"
  22. ))]
  23. use cdk::types::FeeReserve;
  24. use crate::config::{self, Settings};
  25. #[cfg(feature = "cln")]
  26. use crate::expand_path;
  27. #[async_trait]
  28. pub trait LnBackendSetup {
  29. async fn setup(
  30. &self,
  31. routers: &mut Vec<Router>,
  32. settings: &Settings,
  33. unit: CurrencyUnit,
  34. runtime: Option<std::sync::Arc<tokio::runtime::Runtime>>,
  35. work_dir: &Path,
  36. kv_store: Option<Arc<dyn MintKVStore<Err = cdk::cdk_database::Error> + Send + Sync>>,
  37. ) -> anyhow::Result<impl MintPayment>;
  38. }
  39. #[cfg(feature = "cln")]
  40. #[async_trait]
  41. impl LnBackendSetup for config::Cln {
  42. async fn setup(
  43. &self,
  44. _routers: &mut Vec<Router>,
  45. _settings: &Settings,
  46. _unit: CurrencyUnit,
  47. _runtime: Option<std::sync::Arc<tokio::runtime::Runtime>>,
  48. _work_dir: &Path,
  49. _kv_store: Option<Arc<dyn MintKVStore<Err = cdk::cdk_database::Error> + Send + Sync>>,
  50. ) -> anyhow::Result<cdk_cln::Cln> {
  51. let cln_socket = expand_path(
  52. self.rpc_path
  53. .to_str()
  54. .ok_or(anyhow!("cln socket not defined"))?,
  55. )
  56. .ok_or(anyhow!("cln socket not defined"))?;
  57. let fee_reserve = FeeReserve {
  58. min_fee_reserve: self.reserve_fee_min,
  59. percent_fee_reserve: self.fee_percent,
  60. };
  61. let cln = cdk_cln::Cln::new(cln_socket, fee_reserve).await?;
  62. Ok(cln)
  63. }
  64. }
  65. #[cfg(feature = "lnbits")]
  66. #[async_trait]
  67. impl LnBackendSetup for config::LNbits {
  68. async fn setup(
  69. &self,
  70. _routers: &mut Vec<Router>,
  71. _settings: &Settings,
  72. _unit: CurrencyUnit,
  73. _runtime: Option<std::sync::Arc<tokio::runtime::Runtime>>,
  74. _work_dir: &Path,
  75. _kv_store: Option<Arc<dyn MintKVStore<Err = cdk::cdk_database::Error> + Send + Sync>>,
  76. ) -> anyhow::Result<cdk_lnbits::LNbits> {
  77. let admin_api_key = &self.admin_api_key;
  78. let invoice_api_key = &self.invoice_api_key;
  79. let fee_reserve = FeeReserve {
  80. min_fee_reserve: self.reserve_fee_min,
  81. percent_fee_reserve: self.fee_percent,
  82. };
  83. let lnbits = cdk_lnbits::LNbits::new(
  84. admin_api_key.clone(),
  85. invoice_api_key.clone(),
  86. self.lnbits_api.clone(),
  87. fee_reserve,
  88. )
  89. .await?;
  90. // Use v1 websocket API
  91. lnbits.subscribe_ws().await?;
  92. Ok(lnbits)
  93. }
  94. }
  95. #[cfg(feature = "lnd")]
  96. #[async_trait]
  97. impl LnBackendSetup for config::Lnd {
  98. async fn setup(
  99. &self,
  100. _routers: &mut Vec<Router>,
  101. _settings: &Settings,
  102. _unit: CurrencyUnit,
  103. _runtime: Option<std::sync::Arc<tokio::runtime::Runtime>>,
  104. _work_dir: &Path,
  105. _kv_store: Option<Arc<dyn MintKVStore<Err = cdk::cdk_database::Error> + Send + Sync>>,
  106. ) -> anyhow::Result<cdk_lnd::Lnd> {
  107. let address = &self.address;
  108. let cert_file = &self.cert_file;
  109. let macaroon_file = &self.macaroon_file;
  110. let fee_reserve = FeeReserve {
  111. min_fee_reserve: self.reserve_fee_min,
  112. percent_fee_reserve: self.fee_percent,
  113. };
  114. let lnd = cdk_lnd::Lnd::new(
  115. address.to_string(),
  116. cert_file.clone(),
  117. macaroon_file.clone(),
  118. fee_reserve,
  119. )
  120. .await?;
  121. Ok(lnd)
  122. }
  123. }
  124. #[cfg(feature = "fakewallet")]
  125. #[async_trait]
  126. impl LnBackendSetup for config::FakeWallet {
  127. async fn setup(
  128. &self,
  129. _router: &mut Vec<Router>,
  130. _settings: &Settings,
  131. unit: CurrencyUnit,
  132. _runtime: Option<std::sync::Arc<tokio::runtime::Runtime>>,
  133. _work_dir: &Path,
  134. _kv_store: Option<Arc<dyn MintKVStore<Err = cdk::cdk_database::Error> + Send + Sync>>,
  135. ) -> anyhow::Result<cdk_fake_wallet::FakeWallet> {
  136. let fee_reserve = FeeReserve {
  137. min_fee_reserve: self.reserve_fee_min,
  138. percent_fee_reserve: self.fee_percent,
  139. };
  140. // calculate random delay time
  141. let mut rng = thread_rng();
  142. let delay_time = rng.gen_range(self.min_delay_time..=self.max_delay_time);
  143. let fake_wallet = cdk_fake_wallet::FakeWallet::new(
  144. fee_reserve,
  145. HashMap::default(),
  146. HashSet::default(),
  147. delay_time,
  148. unit,
  149. );
  150. Ok(fake_wallet)
  151. }
  152. }
  153. #[cfg(feature = "grpc-processor")]
  154. #[async_trait]
  155. impl LnBackendSetup for config::GrpcProcessor {
  156. async fn setup(
  157. &self,
  158. _routers: &mut Vec<Router>,
  159. _settings: &Settings,
  160. _unit: CurrencyUnit,
  161. _runtime: Option<std::sync::Arc<tokio::runtime::Runtime>>,
  162. _work_dir: &Path,
  163. _kv_store: Option<Arc<dyn MintKVStore<Err = cdk::cdk_database::Error> + Send + Sync>>,
  164. ) -> anyhow::Result<cdk_payment_processor::PaymentProcessorClient> {
  165. let payment_processor = cdk_payment_processor::PaymentProcessorClient::new(
  166. &self.addr,
  167. self.port,
  168. self.tls_dir.clone(),
  169. )
  170. .await?;
  171. Ok(payment_processor)
  172. }
  173. }
  174. #[cfg(feature = "ldk-node")]
  175. #[async_trait]
  176. impl LnBackendSetup for config::LdkNode {
  177. async fn setup(
  178. &self,
  179. _routers: &mut Vec<Router>,
  180. _settings: &Settings,
  181. _unit: CurrencyUnit,
  182. runtime: Option<std::sync::Arc<tokio::runtime::Runtime>>,
  183. work_dir: &Path,
  184. _kv_store: Option<Arc<dyn MintKVStore<Err = cdk::cdk_database::Error> + Send + Sync>>,
  185. ) -> anyhow::Result<cdk_ldk_node::CdkLdkNode> {
  186. use std::net::SocketAddr;
  187. use bitcoin::Network;
  188. let fee_reserve = FeeReserve {
  189. min_fee_reserve: self.reserve_fee_min,
  190. percent_fee_reserve: self.fee_percent,
  191. };
  192. // Parse network from config
  193. let network = match self
  194. .bitcoin_network
  195. .as_ref()
  196. .map(|n| n.to_lowercase())
  197. .as_deref()
  198. .unwrap_or("regtest")
  199. {
  200. "mainnet" | "bitcoin" => Network::Bitcoin,
  201. "testnet" => Network::Testnet,
  202. "signet" => Network::Signet,
  203. _ => Network::Regtest,
  204. };
  205. // Parse chain source from config
  206. let chain_source = match self
  207. .chain_source_type
  208. .as_ref()
  209. .map(|s| s.to_lowercase())
  210. .as_deref()
  211. .unwrap_or("esplora")
  212. {
  213. "bitcoinrpc" => {
  214. let host = self
  215. .bitcoind_rpc_host
  216. .clone()
  217. .unwrap_or_else(|| "127.0.0.1".to_string());
  218. let port = self.bitcoind_rpc_port.unwrap_or(18443);
  219. let user = self
  220. .bitcoind_rpc_user
  221. .clone()
  222. .unwrap_or_else(|| "testuser".to_string());
  223. let password = self
  224. .bitcoind_rpc_password
  225. .clone()
  226. .unwrap_or_else(|| "testpass".to_string());
  227. cdk_ldk_node::ChainSource::BitcoinRpc(cdk_ldk_node::BitcoinRpcConfig {
  228. host,
  229. port,
  230. user,
  231. password,
  232. })
  233. }
  234. _ => {
  235. let esplora_url = self
  236. .esplora_url
  237. .clone()
  238. .unwrap_or_else(|| "https://mutinynet.com/api".to_string());
  239. cdk_ldk_node::ChainSource::Esplora(esplora_url)
  240. }
  241. };
  242. // Parse gossip source from config
  243. let gossip_source = match self.rgs_url.clone() {
  244. Some(rgs_url) => cdk_ldk_node::GossipSource::RapidGossipSync(rgs_url),
  245. None => cdk_ldk_node::GossipSource::P2P,
  246. };
  247. // Get storage directory path
  248. let storage_dir_path = if let Some(dir_path) = &self.storage_dir_path {
  249. dir_path.clone()
  250. } else {
  251. let mut work_dir = work_dir.to_path_buf();
  252. work_dir.push("ldk-node");
  253. work_dir.to_string_lossy().to_string()
  254. };
  255. // Get LDK node listen address
  256. let host = self
  257. .ldk_node_host
  258. .clone()
  259. .unwrap_or_else(|| "127.0.0.1".to_string());
  260. let port = self.ldk_node_port.unwrap_or(8090);
  261. let socket_addr = SocketAddr::new(host.parse()?, port);
  262. // Parse socket address using ldk_node's SocketAddress
  263. // We need to get the actual socket address struct from ldk_node
  264. // For now, let's construct it manually based on the cdk-ldk-node implementation
  265. let listen_address = vec![socket_addr.into()];
  266. let mut ldk_node = cdk_ldk_node::CdkLdkNode::new(
  267. network,
  268. chain_source,
  269. gossip_source,
  270. storage_dir_path,
  271. fee_reserve,
  272. listen_address,
  273. runtime,
  274. )?;
  275. // Configure webserver address if specified
  276. let webserver_addr = if let Some(host) = &self.webserver_host {
  277. let port = self.webserver_port.unwrap_or(8091);
  278. let socket_addr: SocketAddr = format!("{host}:{port}").parse()?;
  279. Some(socket_addr)
  280. } else if self.webserver_port.is_some() {
  281. // If only port is specified, use default host
  282. let port = self.webserver_port.unwrap_or(8091);
  283. let socket_addr: SocketAddr = format!("127.0.0.1:{port}").parse()?;
  284. Some(socket_addr)
  285. } else {
  286. // Use default webserver address if nothing is configured
  287. Some(cdk_ldk_node::CdkLdkNode::default_web_addr())
  288. };
  289. println!("webserver: {:?}", webserver_addr);
  290. ldk_node.set_web_addr(webserver_addr);
  291. Ok(ldk_node)
  292. }
  293. }