| 
					
				 | 
			
			
				@@ -0,0 +1,272 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+//! CDK lightning backend for LND 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Copyright (c) 2023 Steffen (MIT) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#![warn(missing_docs)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#![warn(rustdoc::bare_urls)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use std::path::PathBuf; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use std::pin::Pin; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use std::str::FromStr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use std::sync::Arc; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use anyhow::anyhow; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use async_trait::async_trait; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use cdk::amount::Amount; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use cdk::cdk_lightning::{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    self, to_unit, CreateInvoiceResponse, MintLightning, MintMeltSettings, PayInvoiceResponse, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    PaymentQuoteResponse, Settings, MSAT_IN_SAT, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use cdk::mint::FeeReserve; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use cdk::nuts::{CurrencyUnit, MeltQuoteBolt11Request, MeltQuoteState, MintQuoteState}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use cdk::util::{hex, unix_time}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use cdk::{mint, Bolt11Invoice}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use error::Error; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use fedimint_tonic_lnd::lnrpc::fee_limit::Limit; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use fedimint_tonic_lnd::lnrpc::FeeLimit; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use fedimint_tonic_lnd::Client; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use futures::{Stream, StreamExt}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+use tokio::sync::Mutex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+pub mod error; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/// Lnd mint backend 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#[derive(Clone)] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+pub struct Lnd { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    address: String, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    cert_file: PathBuf, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    macaroon_file: PathBuf, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    client: Arc<Mutex<Client>>, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fee_reserve: FeeReserve, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    mint_settings: MintMeltSettings, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    melt_settings: MintMeltSettings, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+impl Lnd { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// Create new [`Lnd`] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pub async fn new( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        address: String, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        cert_file: PathBuf, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        macaroon_file: PathBuf, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fee_reserve: FeeReserve, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        mint_settings: MintMeltSettings, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        melt_settings: MintMeltSettings, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ) -> Result<Self, Error> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let client = fedimint_tonic_lnd::connect(address.to_string(), &cert_file, &macaroon_file) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .await 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .map_err(|err| { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                tracing::error!("Connection error: {}", err.to_string()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Error::Connection 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            })?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Ok(Self { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            address, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            cert_file, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            macaroon_file, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            client: Arc::new(Mutex::new(client)), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fee_reserve, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            mint_settings, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            melt_settings, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#[async_trait] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+impl MintLightning for Lnd { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    type Err = cdk_lightning::Error; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fn get_settings(&self) -> Settings { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Settings { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            mpp: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            unit: CurrencyUnit::Msat, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            mint_settings: self.mint_settings, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            melt_settings: self.melt_settings, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    async fn wait_any_invoice( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        &self, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ) -> Result<Pin<Box<dyn Stream<Item = String> + Send>>, Self::Err> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let mut client = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fedimint_tonic_lnd::connect(self.address.clone(), &self.cert_file, &self.macaroon_file) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .await 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .map_err(|_| Error::Connection)?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let stream_req = fedimint_tonic_lnd::lnrpc::InvoiceSubscription { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            add_index: 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            settle_index: 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let stream = client 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .lightning() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .subscribe_invoices(stream_req) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .await 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .unwrap() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .into_inner(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Ok(futures::stream::unfold(stream, |mut stream| async move { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            match stream.message().await { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Ok(Some(msg)) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if msg.state == 1 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        Some((hex::encode(msg.r_hash), stream)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Ok(None) => None, // End of stream 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Err(_) => None,   // Handle errors gracefully, ends the stream on error 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .boxed()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    async fn get_payment_quote( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        &self, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        melt_quote_request: &MeltQuoteBolt11Request, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ) -> Result<PaymentQuoteResponse, Self::Err> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let invoice_amount_msat = melt_quote_request 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .request 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .amount_milli_satoshis() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .ok_or(Error::UnknownInvoiceAmount)?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let amount = to_unit( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            invoice_amount_msat, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            &CurrencyUnit::Msat, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            &melt_quote_request.unit, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        )?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let relative_fee_reserve = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            (self.fee_reserve.percent_fee_reserve * u64::from(amount) as f32) as u64; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let absolute_fee_reserve: u64 = self.fee_reserve.min_fee_reserve.into(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let fee = match relative_fee_reserve > absolute_fee_reserve { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            true => relative_fee_reserve, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            false => absolute_fee_reserve, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Ok(PaymentQuoteResponse { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            request_lookup_id: melt_quote_request.request.payment_hash().to_string(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            amount, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fee: fee.into(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            state: MeltQuoteState::Unpaid, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    async fn pay_invoice( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        &self, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        melt_quote: mint::MeltQuote, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        partial_amount: Option<Amount>, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        max_fee: Option<Amount>, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ) -> Result<PayInvoiceResponse, Self::Err> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let payment_request = melt_quote.request; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let pay_req = fedimint_tonic_lnd::lnrpc::SendRequest { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            payment_request, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fee_limit: max_fee.map(|f| { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                let limit = Limit::Fixed(u64::from(f) as i64); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                FeeLimit { limit: Some(limit) } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            amt_msat: partial_amount 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .map(|a| { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    let msat = to_unit(a, &melt_quote.unit, &CurrencyUnit::Msat).unwrap(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    u64::from(msat) as i64 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .unwrap_or_default(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ..Default::default() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let payment_response = self 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .client 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .lock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .await 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .lightning() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .send_payment_sync(fedimint_tonic_lnd::tonic::Request::new(pay_req)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .await 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .unwrap() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .into_inner(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let total_spent = payment_response 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .payment_route 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .map_or(0, |route| route.total_fees_msat / MSAT_IN_SAT as i64) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            as u64; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Ok(PayInvoiceResponse { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            payment_hash: hex::encode(payment_response.payment_hash), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            payment_preimage: Some(hex::encode(payment_response.payment_preimage)), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            status: MeltQuoteState::Pending, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            total_spent: total_spent.into(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    async fn create_invoice( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        &self, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        amount: Amount, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        unit: &CurrencyUnit, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        description: String, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        unix_expiry: u64, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ) -> Result<CreateInvoiceResponse, Self::Err> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let time_now = unix_time(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        assert!(unix_expiry > time_now); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let amount = to_unit(amount, unit, &CurrencyUnit::Msat)?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let invoice_request = fedimint_tonic_lnd::lnrpc::Invoice { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            value_msat: u64::from(amount) as i64, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            memo: description, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ..Default::default() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let invoice = self 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .client 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .lock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .await 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .lightning() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .add_invoice(fedimint_tonic_lnd::tonic::Request::new(invoice_request)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .await 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .unwrap() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .into_inner(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let bolt11 = Bolt11Invoice::from_str(&invoice.payment_request)?; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Ok(CreateInvoiceResponse { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            request_lookup_id: bolt11.payment_hash().to_string(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            request: bolt11, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            expiry: Some(unix_expiry), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    async fn check_invoice_status( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        &self, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        request_lookup_id: &str, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ) -> Result<MintQuoteState, Self::Err> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let invoice_request = fedimint_tonic_lnd::lnrpc::PaymentHash { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            r_hash: hex::decode(request_lookup_id).unwrap(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ..Default::default() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let invoice = self 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .client 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .lock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .await 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .lightning() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .lookup_invoice(fedimint_tonic_lnd::tonic::Request::new(invoice_request)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .await 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .unwrap() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .into_inner(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        match invoice.state { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Open 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            0 => Ok(MintQuoteState::Unpaid), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Settled 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            1 => Ok(MintQuoteState::Paid), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Canceled 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            2 => Ok(MintQuoteState::Unpaid), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Accepted 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            3 => Ok(MintQuoteState::Unpaid), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _ => Err(Self::Err::Anyhow(anyhow!("Invalid status"))), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |