uniffi_lipalightninglib/lightning/
mod.rspub mod bolt11;
pub mod lnurl;
pub mod receive_limits;
use crate::amount::{AsSats, Permyriad, ToAmount};
use crate::errors::Result;
use crate::lightning::bolt11::Bolt11;
use crate::lightning::lnurl::Lnurl;
use crate::lightning::receive_limits::ReceiveAmountLimits;
use crate::locker::Locker;
use crate::support::Support;
use crate::{
CalculateLspFeeResponseV2, ExchangeRate, LspFee, MaxRoutingFeeConfig, MaxRoutingFeeMode,
RuntimeErrorCode,
};
use breez_sdk_core::OpeningFeeParams;
use perro::MapToError;
use std::sync::Arc;
#[derive(Debug)]
pub enum PaymentAffordability {
NotEnoughFunds,
UnaffordableFees,
Affordable,
}
pub struct Lightning {
bolt11: Arc<Bolt11>,
lnurl: Arc<Lnurl>,
support: Arc<Support>,
}
impl Lightning {
#[allow(clippy::too_many_arguments)]
pub(crate) fn new(support: Arc<Support>) -> Self {
let bolt11 = Arc::new(Bolt11::new(Arc::clone(&support)));
let lnurl = Arc::new(Lnurl::new(Arc::clone(&support)));
Self {
bolt11,
lnurl,
support,
}
}
pub fn bolt11(&self) -> Arc<Bolt11> {
Arc::clone(&self.bolt11)
}
pub fn lnurl(&self) -> Arc<Lnurl> {
Arc::clone(&self.lnurl)
}
pub fn determine_max_routing_fee_mode(&self, amount_sat: u64) -> MaxRoutingFeeMode {
get_payment_max_routing_fee_mode(
&self.support.node_config.max_routing_fee_config,
amount_sat,
&self.support.get_exchange_rate(),
)
}
pub fn determine_payment_affordability(
&self,
amount_sat: u64,
) -> crate::Result<PaymentAffordability> {
let amount = amount_sat.as_sats();
let routing_fee_mode = self.determine_max_routing_fee_mode(amount_sat);
let max_fee_msats = match routing_fee_mode {
MaxRoutingFeeMode::Relative { max_fee_permyriad } => {
Permyriad(max_fee_permyriad).of(&amount).msats
}
MaxRoutingFeeMode::Absolute { max_fee_amount } => max_fee_amount.sats.as_sats().msats,
};
let node_state = self.support.sdk.node_info().map_to_runtime_error(
RuntimeErrorCode::NodeUnavailable,
"Failed to read node info",
)?;
if amount.msats > node_state.max_payable_msat {
return Ok(PaymentAffordability::NotEnoughFunds);
}
if amount.msats + max_fee_msats > node_state.max_payable_msat {
return Ok(PaymentAffordability::UnaffordableFees);
}
Ok(PaymentAffordability::Affordable)
}
pub fn determine_receive_amount_limits(&self) -> Result<ReceiveAmountLimits> {
let lsp_min_fee_amount = self.get_lsp_fee()?.channel_minimum_fee;
let max_inbound_amount = self
.support
.get_node_info()?
.channels_info
.total_inbound_capacity;
Ok(ReceiveAmountLimits::calculate(
max_inbound_amount.sats,
lsp_min_fee_amount.sats,
&self.support.get_exchange_rate(),
&self.support.node_config.receive_limits_config,
))
}
pub fn calculate_lsp_fee_for_amount(
&self,
amount_sat: u64,
) -> Result<CalculateLspFeeResponseV2> {
self.support
.calculate_lsp_fee_for_amount(amount_sat, self.get_lsp_fee_params()?)
}
pub fn get_lsp_fee(&self) -> Result<LspFee> {
let exchange_rate = self.support.get_exchange_rate();
let lsp_fee = self.get_lsp_fee_params()?;
Ok(LspFee {
channel_minimum_fee: lsp_fee.min_msat.as_msats().to_amount_up(&exchange_rate),
channel_fee_permyriad: lsp_fee.proportional as u64 / 100,
})
}
pub(crate) fn get_lsp_fee_params(&self) -> Result<OpeningFeeParams> {
self.support
.task_manager
.lock_unwrap()
.get_cheaper_lsp_fee()
}
}
fn get_payment_max_routing_fee_mode(
config: &MaxRoutingFeeConfig,
amount_sat: u64,
exchange_rate: &Option<ExchangeRate>,
) -> MaxRoutingFeeMode {
let max_fee_permyriad = Permyriad(config.max_routing_fee_permyriad);
let relative_fee = max_fee_permyriad.of(&amount_sat.as_sats());
if relative_fee.msats < config.max_routing_fee_exempt_fee_sats.as_sats().msats {
MaxRoutingFeeMode::Absolute {
max_fee_amount: config
.max_routing_fee_exempt_fee_sats
.as_sats()
.to_amount_up(exchange_rate),
}
} else {
MaxRoutingFeeMode::Relative {
max_fee_permyriad: max_fee_permyriad.0,
}
}
}
#[cfg(test)]
mod tests {
use crate::amount::{Permyriad, Sats};
use crate::lightning::get_payment_max_routing_fee_mode;
use crate::{MaxRoutingFeeConfig, MaxRoutingFeeMode};
const MAX_FEE_PERMYRIAD: Permyriad = Permyriad(150);
const EXEMPT_FEE: Sats = Sats::new(21);
#[test]
fn test_get_payment_max_routing_fee_mode_absolute() {
let max_routing_mode = get_payment_max_routing_fee_mode(
&MaxRoutingFeeConfig {
max_routing_fee_permyriad: MAX_FEE_PERMYRIAD.0,
max_routing_fee_exempt_fee_sats: EXEMPT_FEE.sats,
},
EXEMPT_FEE.msats / ((MAX_FEE_PERMYRIAD.0 as u64) / 10) - 1,
&None,
);
match max_routing_mode {
MaxRoutingFeeMode::Absolute { max_fee_amount } => {
assert_eq!(max_fee_amount.sats, EXEMPT_FEE.sats);
}
_ => {
panic!("Unexpected variant");
}
}
}
#[test]
fn test_get_payment_max_routing_fee_mode_relative() {
let max_routing_mode = get_payment_max_routing_fee_mode(
&MaxRoutingFeeConfig {
max_routing_fee_permyriad: MAX_FEE_PERMYRIAD.0,
max_routing_fee_exempt_fee_sats: EXEMPT_FEE.sats,
},
EXEMPT_FEE.msats / ((MAX_FEE_PERMYRIAD.0 as u64) / 10),
&None,
);
match max_routing_mode {
MaxRoutingFeeMode::Relative { max_fee_permyriad } => {
assert_eq!(max_fee_permyriad, MAX_FEE_PERMYRIAD.0);
}
_ => {
panic!("Unexpected variant");
}
}
}
}