mirror of
https://github.com/aljazceru/cdk.git
synced 2025-12-19 13:44:55 +01:00
feat: lnbits ln backend
fix: check webhook url is valid
This commit is contained in:
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
@@ -36,6 +36,7 @@ jobs:
|
|||||||
-p cdk-cln,
|
-p cdk-cln,
|
||||||
-p cdk-fake-wallet,
|
-p cdk-fake-wallet,
|
||||||
-p cdk-strike,
|
-p cdk-strike,
|
||||||
|
-p cdk-lnbits
|
||||||
-p cdk-integration-tests,
|
-p cdk-integration-tests,
|
||||||
--bin cdk-cli,
|
--bin cdk-cli,
|
||||||
--bin cdk-mintd,
|
--bin cdk-mintd,
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ cdk-rexie = { version = "0.3", path = "./crates/cdk-rexie", default-features = f
|
|||||||
cdk-sqlite = { version = "0.3", path = "./crates/cdk-sqlite", default-features = false }
|
cdk-sqlite = { version = "0.3", path = "./crates/cdk-sqlite", default-features = false }
|
||||||
cdk-redb = { version = "0.3", path = "./crates/cdk-redb", default-features = false }
|
cdk-redb = { version = "0.3", path = "./crates/cdk-redb", default-features = false }
|
||||||
cdk-cln = { version = "0.3", path = "./crates/cdk-cln", default-features = false }
|
cdk-cln = { version = "0.3", path = "./crates/cdk-cln", default-features = false }
|
||||||
|
cdk-lnbits = { version = "0.3", path = "./crates/cdk-lnbits", default-features = false }
|
||||||
cdk-axum = { version = "0.3", path = "./crates/cdk-axum", default-features = false }
|
cdk-axum = { version = "0.3", path = "./crates/cdk-axum", default-features = false }
|
||||||
cdk-fake-wallet = { version = "0.3", path = "./crates/cdk-fake-wallet", default-features = false }
|
cdk-fake-wallet = { version = "0.3", path = "./crates/cdk-fake-wallet", default-features = false }
|
||||||
cdk-strike = { version = "0.3", path = "./crates/cdk-strike", default-features = false }
|
cdk-strike = { version = "0.3", path = "./crates/cdk-strike", default-features = false }
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ The project is split up into several crates in the `crates/` directory:
|
|||||||
* [**cdk-axum**](./crates/cdk-axum/): Axum webserver for mint.
|
* [**cdk-axum**](./crates/cdk-axum/): Axum webserver for mint.
|
||||||
* [**cdk-cln**](./crates/cdk-cln/): CLN Lightning backend for mint.
|
* [**cdk-cln**](./crates/cdk-cln/): CLN Lightning backend for mint.
|
||||||
* [**cdk-strike**](./crates/cdk-strike/): Strike Lightning backend for mint.
|
* [**cdk-strike**](./crates/cdk-strike/): Strike Lightning backend for mint.
|
||||||
|
* [**cdk-lnbits**](./crates/cdk-lnbits/): [LNBits](https://lnbits.com/) Lightning backend for mint.
|
||||||
* [**cdk-fake-wallet**](./crates/cdk-fake-wallet/): Fake Lightning backend for mint. To be used only for testing, quotes are automatically filled.
|
* [**cdk-fake-wallet**](./crates/cdk-fake-wallet/): Fake Lightning backend for mint. To be used only for testing, quotes are automatically filled.
|
||||||
* Binaries:
|
* Binaries:
|
||||||
* [**cdk-cli**](./crates/cdk-cli/): Cashu wallet CLI.
|
* [**cdk-cli**](./crates/cdk-cli/): Cashu wallet CLI.
|
||||||
|
|||||||
22
crates/cdk-lnbits/Cargo.toml
Normal file
22
crates/cdk-lnbits/Cargo.toml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
[package]
|
||||||
|
name = "cdk-lnbits"
|
||||||
|
version = { workspace = true }
|
||||||
|
edition = "2021"
|
||||||
|
authors = ["CDK Developers"]
|
||||||
|
homepage.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
rust-version.workspace = true # MSRV
|
||||||
|
license.workspace = true
|
||||||
|
description = "CDK ln backend for lnbits"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
async-trait.workspace = true
|
||||||
|
anyhow.workspace = true
|
||||||
|
axum.workspace = true
|
||||||
|
bitcoin.workspace = true
|
||||||
|
cdk = { workspace = true, default-features = false, features = ["mint"] }
|
||||||
|
futures.workspace = true
|
||||||
|
tokio.workspace = true
|
||||||
|
tracing.workspace = true
|
||||||
|
thiserror.workspace = true
|
||||||
|
lnbits-rs = "0.1.0"
|
||||||
23
crates/cdk-lnbits/src/error.rs
Normal file
23
crates/cdk-lnbits/src/error.rs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
//! Error for Strike ln backend
|
||||||
|
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Strike Error
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Invoice amount not defined
|
||||||
|
#[error("Unknown invoice amount")]
|
||||||
|
UnknownInvoiceAmount,
|
||||||
|
/// Unknown invoice
|
||||||
|
#[error("Unknown invoice")]
|
||||||
|
UnknownInvoice,
|
||||||
|
/// Anyhow error
|
||||||
|
#[error(transparent)]
|
||||||
|
Anyhow(#[from] anyhow::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Error> for cdk::cdk_lightning::Error {
|
||||||
|
fn from(e: Error) -> Self {
|
||||||
|
Self::Lightning(Box::new(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
274
crates/cdk-lnbits/src/lib.rs
Normal file
274
crates/cdk-lnbits/src/lib.rs
Normal file
@@ -0,0 +1,274 @@
|
|||||||
|
//! CDK lightning backend for lnbits
|
||||||
|
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
#![warn(rustdoc::bare_urls)]
|
||||||
|
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use axum::Router;
|
||||||
|
use cdk::amount::Amount;
|
||||||
|
use cdk::cdk_lightning::{
|
||||||
|
self, to_unit, CreateInvoiceResponse, MintLightning, MintMeltSettings, PayInvoiceResponse,
|
||||||
|
PaymentQuoteResponse, Settings,
|
||||||
|
};
|
||||||
|
use cdk::mint::FeeReserve;
|
||||||
|
use cdk::nuts::{CurrencyUnit, MeltQuoteBolt11Request, MeltQuoteState, MintQuoteState};
|
||||||
|
use cdk::util::unix_time;
|
||||||
|
use cdk::{mint, Bolt11Invoice};
|
||||||
|
use error::Error;
|
||||||
|
use futures::stream::StreamExt;
|
||||||
|
use futures::Stream;
|
||||||
|
use lnbits_rs::api::invoice::CreateInvoiceRequest;
|
||||||
|
use lnbits_rs::LNBitsClient;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub mod error;
|
||||||
|
|
||||||
|
/// LNBits
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct LNBits {
|
||||||
|
lnbits_api: LNBitsClient,
|
||||||
|
mint_settings: MintMeltSettings,
|
||||||
|
melt_settings: MintMeltSettings,
|
||||||
|
fee_reserve: FeeReserve,
|
||||||
|
receiver: Arc<Mutex<Option<tokio::sync::mpsc::Receiver<String>>>>,
|
||||||
|
webhook_url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LNBits {
|
||||||
|
/// Create new [`LNBits`] wallet
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
pub async fn new(
|
||||||
|
admin_api_key: String,
|
||||||
|
invoice_api_key: String,
|
||||||
|
api_url: String,
|
||||||
|
mint_settings: MintMeltSettings,
|
||||||
|
melt_settings: MintMeltSettings,
|
||||||
|
fee_reserve: FeeReserve,
|
||||||
|
receiver: Arc<Mutex<Option<tokio::sync::mpsc::Receiver<String>>>>,
|
||||||
|
webhook_url: String,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
|
let lnbits_api = LNBitsClient::new("", &admin_api_key, &invoice_api_key, &api_url, None)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
lnbits_api,
|
||||||
|
mint_settings,
|
||||||
|
melt_settings,
|
||||||
|
receiver,
|
||||||
|
fee_reserve,
|
||||||
|
webhook_url,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl MintLightning for LNBits {
|
||||||
|
type Err = cdk_lightning::Error;
|
||||||
|
|
||||||
|
fn get_settings(&self) -> Settings {
|
||||||
|
Settings {
|
||||||
|
mpp: false,
|
||||||
|
unit: CurrencyUnit::Sat,
|
||||||
|
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 receiver = self
|
||||||
|
.receiver
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.take()
|
||||||
|
.ok_or(anyhow!("No receiver"))?;
|
||||||
|
|
||||||
|
let lnbits_api = self.lnbits_api.clone();
|
||||||
|
|
||||||
|
Ok(futures::stream::unfold(
|
||||||
|
(receiver, lnbits_api),
|
||||||
|
|(mut receiver, lnbits_api)| async move {
|
||||||
|
match receiver.recv().await {
|
||||||
|
Some(msg) => {
|
||||||
|
let check = lnbits_api.is_invoice_paid(&msg).await;
|
||||||
|
|
||||||
|
match check {
|
||||||
|
Ok(state) => {
|
||||||
|
if state {
|
||||||
|
Some((msg, (receiver, lnbits_api)))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.boxed())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_payment_quote(
|
||||||
|
&self,
|
||||||
|
melt_quote_request: &MeltQuoteBolt11Request,
|
||||||
|
) -> Result<PaymentQuoteResponse, Self::Err> {
|
||||||
|
if melt_quote_request.unit != CurrencyUnit::Sat {
|
||||||
|
return Err(Self::Err::Anyhow(anyhow!("Unsupported unit")));
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn pay_invoice(
|
||||||
|
&self,
|
||||||
|
melt_quote: mint::MeltQuote,
|
||||||
|
_partial_msats: Option<Amount>,
|
||||||
|
_max_fee_msats: Option<Amount>,
|
||||||
|
) -> Result<PayInvoiceResponse, Self::Err> {
|
||||||
|
let pay_response = self
|
||||||
|
.lnbits_api
|
||||||
|
.pay_invoice(&melt_quote.request)
|
||||||
|
.await
|
||||||
|
.map_err(|err| {
|
||||||
|
tracing::error!("Could not pay invoice");
|
||||||
|
tracing::error!("{}", err.to_string());
|
||||||
|
Self::Err::Anyhow(anyhow!("Could not pay invoice"))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let invoice_info = self
|
||||||
|
.lnbits_api
|
||||||
|
.find_invoice(&pay_response.payment_hash)
|
||||||
|
.await
|
||||||
|
.map_err(|err| {
|
||||||
|
tracing::error!("Could not find invoice");
|
||||||
|
tracing::error!("{}", err.to_string());
|
||||||
|
Self::Err::Anyhow(anyhow!("Could not find invoice"))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let status = match invoice_info.pending {
|
||||||
|
true => MeltQuoteState::Unpaid,
|
||||||
|
false => MeltQuoteState::Paid,
|
||||||
|
};
|
||||||
|
|
||||||
|
let total_spent = Amount::from((invoice_info.amount + invoice_info.fee).unsigned_abs());
|
||||||
|
|
||||||
|
Ok(PayInvoiceResponse {
|
||||||
|
payment_hash: pay_response.payment_hash,
|
||||||
|
payment_preimage: Some(invoice_info.payment_hash),
|
||||||
|
status,
|
||||||
|
total_spent,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn create_invoice(
|
||||||
|
&self,
|
||||||
|
amount: Amount,
|
||||||
|
unit: &CurrencyUnit,
|
||||||
|
description: String,
|
||||||
|
unix_expiry: u64,
|
||||||
|
) -> Result<CreateInvoiceResponse, Self::Err> {
|
||||||
|
if unit != &CurrencyUnit::Sat {
|
||||||
|
return Err(Self::Err::Anyhow(anyhow!("Unsupported unit")));
|
||||||
|
}
|
||||||
|
|
||||||
|
let time_now = unix_time();
|
||||||
|
assert!(unix_expiry > time_now);
|
||||||
|
|
||||||
|
let expiry = unix_expiry - time_now;
|
||||||
|
|
||||||
|
let invoice_request = CreateInvoiceRequest {
|
||||||
|
amount: to_unit(amount, unit, &CurrencyUnit::Sat)?.into(),
|
||||||
|
memo: Some(description),
|
||||||
|
unit: unit.to_string(),
|
||||||
|
expiry: Some(expiry),
|
||||||
|
webhook: Some(self.webhook_url.clone()),
|
||||||
|
internal: None,
|
||||||
|
out: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let create_invoice_response = self
|
||||||
|
.lnbits_api
|
||||||
|
.create_invoice(&invoice_request)
|
||||||
|
.await
|
||||||
|
.map_err(|err| {
|
||||||
|
tracing::error!("Could not create invoice");
|
||||||
|
tracing::error!("{}", err.to_string());
|
||||||
|
Self::Err::Anyhow(anyhow!("Could not create invoice"))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let request: Bolt11Invoice = create_invoice_response.payment_request.parse()?;
|
||||||
|
let expiry = request.expires_at().map(|t| t.as_secs());
|
||||||
|
|
||||||
|
Ok(CreateInvoiceResponse {
|
||||||
|
request_lookup_id: create_invoice_response.payment_hash,
|
||||||
|
request,
|
||||||
|
expiry,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn check_invoice_status(
|
||||||
|
&self,
|
||||||
|
request_lookup_id: &str,
|
||||||
|
) -> Result<MintQuoteState, Self::Err> {
|
||||||
|
let paid = self
|
||||||
|
.lnbits_api
|
||||||
|
.is_invoice_paid(request_lookup_id)
|
||||||
|
.await
|
||||||
|
.map_err(|err| {
|
||||||
|
tracing::error!("Could not check invoice status");
|
||||||
|
tracing::error!("{}", err.to_string());
|
||||||
|
Self::Err::Anyhow(anyhow!("Could not check invoice status"))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let state = match paid {
|
||||||
|
true => MintQuoteState::Paid,
|
||||||
|
false => MintQuoteState::Unpaid,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LNBits {
|
||||||
|
/// Create invoice webhook
|
||||||
|
pub async fn create_invoice_webhook_router(
|
||||||
|
&self,
|
||||||
|
webhook_endpoint: &str,
|
||||||
|
sender: tokio::sync::mpsc::Sender<String>,
|
||||||
|
) -> anyhow::Result<Router> {
|
||||||
|
self.lnbits_api
|
||||||
|
.create_invoice_webhook_router(webhook_endpoint, sender)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ cdk = { workspace = true, default-features = false, features = ["mint"] }
|
|||||||
cdk-redb = { workspace = true, default-features = false, features = ["mint"] }
|
cdk-redb = { workspace = true, default-features = false, features = ["mint"] }
|
||||||
cdk-sqlite = { workspace = true, default-features = false, features = ["mint"] }
|
cdk-sqlite = { workspace = true, default-features = false, features = ["mint"] }
|
||||||
cdk-cln = { workspace = true, default-features = false }
|
cdk-cln = { workspace = true, default-features = false }
|
||||||
|
cdk-lnbits = { workspace = true, default-features = false }
|
||||||
cdk-fake-wallet = { workspace = true, default-features = false }
|
cdk-fake-wallet = { workspace = true, default-features = false }
|
||||||
cdk-strike.workspace = true
|
cdk-strike.workspace = true
|
||||||
cdk-axum = { workspace = true, default-features = false }
|
cdk-axum = { workspace = true, default-features = false }
|
||||||
|
|||||||
@@ -37,3 +37,9 @@ ln_backend = "cln"
|
|||||||
# api_key=""
|
# api_key=""
|
||||||
# Optional default sats
|
# Optional default sats
|
||||||
# supported_units=[""]
|
# supported_units=[""]
|
||||||
|
|
||||||
|
|
||||||
|
# [lnbits]
|
||||||
|
# admin_api_key = ""
|
||||||
|
# invoice_api_key = ""
|
||||||
|
# lnbits_api = ""
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ pub enum LnBackend {
|
|||||||
#[default]
|
#[default]
|
||||||
Cln,
|
Cln,
|
||||||
Strike,
|
Strike,
|
||||||
|
LNBits,
|
||||||
FakeWallet,
|
FakeWallet,
|
||||||
// Greenlight,
|
// Greenlight,
|
||||||
// Ldk,
|
// Ldk,
|
||||||
@@ -40,6 +41,13 @@ pub struct Strike {
|
|||||||
pub supported_units: Option<Vec<CurrencyUnit>>,
|
pub supported_units: Option<Vec<CurrencyUnit>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
|
pub struct LNBits {
|
||||||
|
pub admin_api_key: String,
|
||||||
|
pub invoice_api_key: String,
|
||||||
|
pub lnbits_api: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
pub struct Cln {
|
pub struct Cln {
|
||||||
pub rpc_path: PathBuf,
|
pub rpc_path: PathBuf,
|
||||||
@@ -78,6 +86,7 @@ pub struct Settings {
|
|||||||
pub ln: Ln,
|
pub ln: Ln,
|
||||||
pub cln: Option<Cln>,
|
pub cln: Option<Cln>,
|
||||||
pub strike: Option<Strike>,
|
pub strike: Option<Strike>,
|
||||||
|
pub lnbits: Option<LNBits>,
|
||||||
pub fake_wallet: Option<FakeWallet>,
|
pub fake_wallet: Option<FakeWallet>,
|
||||||
pub database: Database,
|
pub database: Database,
|
||||||
}
|
}
|
||||||
@@ -141,8 +150,9 @@ impl Settings {
|
|||||||
|
|
||||||
match settings.ln.ln_backend {
|
match settings.ln.ln_backend {
|
||||||
LnBackend::Cln => assert!(settings.cln.is_some()),
|
LnBackend::Cln => assert!(settings.cln.is_some()),
|
||||||
LnBackend::FakeWallet => (),
|
|
||||||
LnBackend::Strike => assert!(settings.strike.is_some()),
|
LnBackend::Strike => assert!(settings.strike.is_some()),
|
||||||
|
LnBackend::LNBits => assert!(settings.lnbits.is_some()),
|
||||||
|
LnBackend::FakeWallet => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(settings)
|
Ok(settings)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ use cdk::cdk_database::{self, MintDatabase};
|
|||||||
use cdk::cdk_lightning;
|
use cdk::cdk_lightning;
|
||||||
use cdk::cdk_lightning::{MintLightning, MintMeltSettings};
|
use cdk::cdk_lightning::{MintLightning, MintMeltSettings};
|
||||||
use cdk::mint::{FeeReserve, Mint};
|
use cdk::mint::{FeeReserve, Mint};
|
||||||
|
use cdk::mint_url::MintUrl;
|
||||||
use cdk::nuts::{
|
use cdk::nuts::{
|
||||||
nut04, nut05, ContactInfo, CurrencyUnit, MeltMethodSettings, MintInfo, MintMethodSettings,
|
nut04, nut05, ContactInfo, CurrencyUnit, MeltMethodSettings, MintInfo, MintMethodSettings,
|
||||||
MintVersion, MppMethodSettings, Nuts, PaymentMethod,
|
MintVersion, MppMethodSettings, Nuts, PaymentMethod,
|
||||||
@@ -22,6 +23,7 @@ use cdk::nuts::{
|
|||||||
use cdk_axum::LnKey;
|
use cdk_axum::LnKey;
|
||||||
use cdk_cln::Cln;
|
use cdk_cln::Cln;
|
||||||
use cdk_fake_wallet::FakeWallet;
|
use cdk_fake_wallet::FakeWallet;
|
||||||
|
use cdk_lnbits::LNBits;
|
||||||
use cdk_redb::MintRedbDatabase;
|
use cdk_redb::MintRedbDatabase;
|
||||||
use cdk_sqlite::MintSqliteDatabase;
|
use cdk_sqlite::MintSqliteDatabase;
|
||||||
use cdk_strike::Strike;
|
use cdk_strike::Strike;
|
||||||
@@ -128,6 +130,8 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
let mut supported_units = HashMap::new();
|
let mut supported_units = HashMap::new();
|
||||||
let input_fee_ppk = settings.info.input_fee_ppk.unwrap_or(0);
|
let input_fee_ppk = settings.info.input_fee_ppk.unwrap_or(0);
|
||||||
|
|
||||||
|
let mint_url: MintUrl = settings.info.url.parse()?;
|
||||||
|
|
||||||
let ln_routers: Vec<Router> = match settings.ln.ln_backend {
|
let ln_routers: Vec<Router> = match settings.ln.ln_backend {
|
||||||
LnBackend::Cln => {
|
LnBackend::Cln => {
|
||||||
let cln_socket = expand_path(
|
let cln_socket = expand_path(
|
||||||
@@ -168,7 +172,7 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
let (sender, receiver) = tokio::sync::mpsc::channel(8);
|
let (sender, receiver) = tokio::sync::mpsc::channel(8);
|
||||||
let webhook_endpoint = format!("/webhook/{}/invoice", unit);
|
let webhook_endpoint = format!("/webhook/{}/invoice", unit);
|
||||||
|
|
||||||
let webhook_url = format!("{}{}", settings.info.url, webhook_endpoint);
|
let webhook_url = mint_url.join(&webhook_endpoint)?;
|
||||||
|
|
||||||
let strike = Strike::new(
|
let strike = Strike::new(
|
||||||
api_key.clone(),
|
api_key.clone(),
|
||||||
@@ -176,7 +180,7 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
MintMeltSettings::default(),
|
MintMeltSettings::default(),
|
||||||
unit,
|
unit,
|
||||||
Arc::new(Mutex::new(Some(receiver))),
|
Arc::new(Mutex::new(Some(receiver))),
|
||||||
webhook_url,
|
webhook_url.to_string(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@@ -194,6 +198,43 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
routers
|
routers
|
||||||
}
|
}
|
||||||
|
LnBackend::LNBits => {
|
||||||
|
let lnbits_settings = settings.lnbits.expect("Checked on config load");
|
||||||
|
let admin_api_key = lnbits_settings.admin_api_key;
|
||||||
|
let invoice_api_key = lnbits_settings.invoice_api_key;
|
||||||
|
|
||||||
|
// Channel used for lnbits web hook
|
||||||
|
let (sender, receiver) = tokio::sync::mpsc::channel(8);
|
||||||
|
let webhook_endpoint = "/webhook/lnbits/sat/invoice";
|
||||||
|
|
||||||
|
let webhook_url = mint_url.join(webhook_endpoint)?;
|
||||||
|
|
||||||
|
let lnbits = LNBits::new(
|
||||||
|
admin_api_key,
|
||||||
|
invoice_api_key,
|
||||||
|
lnbits_settings.lnbits_api,
|
||||||
|
MintMeltSettings::default(),
|
||||||
|
MintMeltSettings::default(),
|
||||||
|
fee_reserve,
|
||||||
|
Arc::new(Mutex::new(Some(receiver))),
|
||||||
|
webhook_url.to_string(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let router = lnbits
|
||||||
|
.create_invoice_webhook_router(webhook_endpoint, sender)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let unit = CurrencyUnit::Sat;
|
||||||
|
|
||||||
|
let ln_key = LnKey::new(unit, PaymentMethod::Bolt11);
|
||||||
|
|
||||||
|
ln_backends.insert(ln_key, Arc::new(lnbits));
|
||||||
|
|
||||||
|
supported_units.insert(unit, (input_fee_ppk, 64));
|
||||||
|
|
||||||
|
vec![router]
|
||||||
|
}
|
||||||
LnBackend::FakeWallet => {
|
LnBackend::FakeWallet => {
|
||||||
let units = settings.fake_wallet.unwrap_or_default().supported_units;
|
let units = settings.fake_wallet.unwrap_or_default().supported_units;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user