From a3217b57cb07f2388c2ac4b9a2ea449053c4837e Mon Sep 17 00:00:00 2001 From: Andrei <92177534+andrei-21@users.noreply.github.com> Date: Wed, 31 May 2023 08:43:28 +0100 Subject: [PATCH] Amount interface for limits (#401) --- eel/examples/eel-node/cli.rs | 12 ++++----- eel/src/lib.rs | 11 +++----- eel/src/limits.rs | 22 ++++++++-------- eel/src/utils.rs | 30 ---------------------- eel/tests/receiving_payments_test.rs | 14 +++++----- examples/3l-node/cli.rs | 19 +++++++++----- src/lib.rs | 38 ++++++++++++++++++++++++++-- src/lipalightninglib.udl | 14 +++++----- 8 files changed, 83 insertions(+), 77 deletions(-) delete mode 100644 eel/src/utils.rs diff --git a/eel/examples/eel-node/cli.rs b/eel/examples/eel-node/cli.rs index d5fad007..0e193985 100644 --- a/eel/examples/eel-node/cli.rs +++ b/eel/examples/eel-node/cli.rs @@ -127,16 +127,14 @@ fn lsp_fee(node: &LightningNode) { fn payment_amount_limits(node: &LightningNode) { let limits = node.get_payment_amount_limits().unwrap(); - println!(" Beta maximum receive: {} sats", limits.max_receive_sat); + println!(" Beta maximum receive: {} msats", limits.max_receive_msat); match limits.liquidity_limit { - LiquidityLimit::MinReceive { sat_amount } => { - println!(" Minimum payment amount: {sat_amount} sats. A setup fee will be charged."); + LiquidityLimit::MinReceive { amount_msat } => { + println!(" Minimum payment amount: {amount_msat} msats. A setup fee will be charged."); } - LiquidityLimit::MaxFreeReceive { sat_amount } => { - println!( - " If you want to receive more than {sat_amount} sats, a setup fee will be charged." - ); + LiquidityLimit::MaxFreeReceive { amount_msat } => { + println!(" If you want to receive more than {amount_msat} msats, a setup fee will be charged."); } LiquidityLimit::None => {} } diff --git a/eel/src/lib.rs b/eel/src/lib.rs index 26957352..5cb43d4f 100644 --- a/eel/src/lib.rs +++ b/eel/src/lib.rs @@ -32,7 +32,6 @@ mod task_manager; mod test_utils; mod tx_broadcaster; mod types; -pub mod utils; use crate::async_runtime::AsyncRuntime; use crate::config::{Config, TzConfig}; @@ -58,7 +57,6 @@ use crate::tx_broadcaster::TxBroadcaster; use crate::types::{ChainMonitor, ChannelManager, PeerManager, RapidGossipSync, Router, TxSync}; use std::fs; -use crate::utils::{round_down_to_sat, round_up_to_sat}; use bitcoin::hashes::hex::ToHex; pub use bitcoin::Network; use cipher::consts::U32; @@ -628,13 +626,12 @@ impl LightningNode { } pub fn get_payment_amount_limits(&self) -> Result { - let lsp_min_fee = round_up_to_sat(self.query_lsp_fee()?.channel_minimum_fee_msat); - let inbound_capacity = - round_down_to_sat(self.get_node_info().channels_info.inbound_capacity_msat); + let lsp_min_fee_msat = self.query_lsp_fee()?.channel_minimum_fee_msat; + let inbound_capacity_msat = self.get_node_info().channels_info.inbound_capacity_msat; Ok(PaymentAmountLimits::calculate( - inbound_capacity, - lsp_min_fee, + inbound_capacity_msat, + lsp_min_fee_msat, )) } diff --git a/eel/src/limits.rs b/eel/src/limits.rs index b82cf0b6..0b4d0bbc 100644 --- a/eel/src/limits.rs +++ b/eel/src/limits.rs @@ -1,37 +1,37 @@ -const MAX_RECEIVE_AMOUNT_BETA_SAT: u64 = 1_000_000; +const MAX_RECEIVE_AMOUNT_BETA_MSAT: u64 = 1_000_000_000; const MIN_RECEIVE_MULTIPLIER: u64 = 2; // Minimum receive = mutliple of setup fees #[derive(PartialEq, Eq, Debug)] pub struct PaymentAmountLimits { - pub max_receive_sat: u64, + pub max_receive_msat: u64, pub liquidity_limit: LiquidityLimit, } #[derive(PartialEq, Eq, Debug)] pub enum LiquidityLimit { None, - MaxFreeReceive { sat_amount: u64 }, - MinReceive { sat_amount: u64 }, + MaxFreeReceive { amount_msat: u64 }, + MinReceive { amount_msat: u64 }, } impl PaymentAmountLimits { - pub fn calculate(inbound_capacity: u64, lsp_min_fee: u64) -> Self { - let min_receive_amount = lsp_min_fee * MIN_RECEIVE_MULTIPLIER; + pub fn calculate(inbound_capacity_msat: u64, lsp_min_fee: u64) -> Self { + let min_receive_msat = lsp_min_fee * MIN_RECEIVE_MULTIPLIER; - let liquidity_limit = if inbound_capacity < min_receive_amount { + let liquidity_limit = if inbound_capacity_msat < min_receive_msat { LiquidityLimit::MinReceive { - sat_amount: min_receive_amount, + amount_msat: min_receive_msat, } - } else if inbound_capacity < MAX_RECEIVE_AMOUNT_BETA_SAT { + } else if inbound_capacity_msat < MAX_RECEIVE_AMOUNT_BETA_MSAT { LiquidityLimit::MaxFreeReceive { - sat_amount: inbound_capacity, + amount_msat: inbound_capacity_msat, } } else { LiquidityLimit::None }; PaymentAmountLimits { - max_receive_sat: MAX_RECEIVE_AMOUNT_BETA_SAT, + max_receive_msat: MAX_RECEIVE_AMOUNT_BETA_MSAT, liquidity_limit, } } diff --git a/eel/src/utils.rs b/eel/src/utils.rs deleted file mode 100644 index 55fe6c4f..00000000 --- a/eel/src/utils.rs +++ /dev/null @@ -1,30 +0,0 @@ -pub fn round_down_to_sat(amount_msat: u64) -> u64 { - amount_msat / 1000 -} - -pub fn round_up_to_sat(amount_msat: u64) -> u64 { - (amount_msat + 999) / 1000 -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - pub fn test_rounding_msat_down_to_satoshi() { - for i in 0..1000 { - assert_eq!(round_down_to_sat(i), 0); - } - - assert_eq!(round_down_to_sat(1000), 1); - } - - #[test] - pub fn test_rounding_msat_up_to_satoshi() { - assert_eq!(round_up_to_sat(0), 0); - - for i in 1..=1000 { - assert_eq!(round_up_to_sat(i), 1); - } - } -} diff --git a/eel/tests/receiving_payments_test.rs b/eel/tests/receiving_payments_test.rs index 33a0c51d..a7f0b664 100644 --- a/eel/tests/receiving_payments_test.rs +++ b/eel/tests/receiving_payments_test.rs @@ -5,7 +5,6 @@ mod setup_env; mod receiving_payments_test { use bitcoin::hashes::hex::ToHex; use eel::limits::LiquidityLimit; - use eel::utils::round_down_to_sat; use eel::LightningNode; use log::info; use serial_test::file_serial; @@ -296,22 +295,23 @@ mod receiving_payments_test { fn assert_low_inbound_capacity(node: &LightningNode) { let limits = node.get_payment_amount_limits().unwrap(); - assert_eq!(limits.max_receive_sat, 1_000_000); + assert_eq!(limits.max_receive_msat, 1_000_000_000); assert_eq!( limits.liquidity_limit, - LiquidityLimit::MinReceive { sat_amount: 4_000 }, + LiquidityLimit::MinReceive { + amount_msat: 4_000_000 + }, ); } fn assert_moderate_inbound_capacity(node: &LightningNode, inbound_capacity_msat: u64) { let limits = node.get_payment_amount_limits().unwrap(); - let inbound_capacity = round_down_to_sat(inbound_capacity_msat); - assert_eq!(limits.max_receive_sat, 1_000_000); + assert_eq!(limits.max_receive_msat, 1_000_000_000); assert_eq!( limits.liquidity_limit, LiquidityLimit::MaxFreeReceive { - sat_amount: inbound_capacity + amount_msat: inbound_capacity_msat }, ); } @@ -319,7 +319,7 @@ mod receiving_payments_test { fn assert_high_inbound_capacity(node: &LightningNode) { let limits = node.get_payment_amount_limits().unwrap(); - assert_eq!(limits.max_receive_sat, 1_000_000); + assert_eq!(limits.max_receive_msat, 1_000_000_000); assert_eq!(limits.liquidity_limit, LiquidityLimit::None); } } diff --git a/examples/3l-node/cli.rs b/examples/3l-node/cli.rs index 8a3c5c3b..3c5b7896 100644 --- a/examples/3l-node/cli.rs +++ b/examples/3l-node/cli.rs @@ -6,13 +6,13 @@ use bitcoin::secp256k1::PublicKey; use chrono::offset::FixedOffset; use chrono::{DateTime, Utc}; use colored::Colorize; -use eel::limits::LiquidityLimit; use rustyline::config::{Builder, CompletionType}; use rustyline::error::ReadlineError; use rustyline::history::DefaultHistory; use rustyline::Editor; use std::collections::HashSet; use std::path::Path; +use uniffi_lipalightninglib::LiquidityLimit; use crate::LightningNode; @@ -232,15 +232,22 @@ fn calculate_lsp_fee( fn payment_amount_limits(node: &LightningNode) { let limits = node.get_payment_amount_limits().unwrap(); - println!(" Beta maximum receive: {} SAT", limits.max_receive_sat); + println!( + " Beta maximum receive: {}", + amount_to_string(limits.max_receive) + ); match limits.liquidity_limit { - LiquidityLimit::MinReceive { sat_amount } => { - println!(" Minimum payment amount: {sat_amount} SAT. A setup fee will be charged."); + LiquidityLimit::MinReceive { amount } => { + println!( + " Minimum payment amount: {}. A setup fee will be charged.", + amount_to_string(amount) + ); } - LiquidityLimit::MaxFreeReceive { sat_amount } => { + LiquidityLimit::MaxFreeReceive { amount } => { println!( - " If you want to receive more than {sat_amount} SAT, a setup fee will be charged." + " If you want to receive more than {}, a setup fee will be charged.", + amount_to_string(amount) ); } LiquidityLimit::None => {} diff --git a/src/lib.rs b/src/lib.rs index 9bb20d82..3203317b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,7 +29,6 @@ use eel::errors::{Error as LnError, Result, RuntimeErrorCode}; pub use eel::interfaces::ExchangeRate; use eel::key_derivation::derive_key_pair_hex; use eel::keys_manager::{generate_secret, mnemonic_to_secret, words_by_prefix}; -use eel::limits::{LiquidityLimit, PaymentAmountLimits}; pub use eel::payment::FiatValues; use eel::payment::{PaymentState, PaymentType, TzTime}; use eel::secret::Secret; @@ -44,6 +43,17 @@ use std::sync::Arc; const BACKEND_AUTH_DERIVATION_PATH: &str = "m/76738065'/0'/0"; +pub struct PaymentAmountLimits { + pub max_receive: Amount, + pub liquidity_limit: LiquidityLimit, +} + +pub enum LiquidityLimit { + None, + MaxFreeReceive { amount: Amount }, + MinReceive { amount: Amount }, +} + pub struct LspFee { pub channel_minimum_fee: Amount, pub channel_fee_permyriad: u64, @@ -175,7 +185,10 @@ impl LightningNode { } pub fn get_payment_amount_limits(&self) -> Result { - self.core_node.get_payment_amount_limits() + let rate = self.get_exchange_rate(); + self.core_node + .get_payment_amount_limits() + .map(|limits| to_limits(limits, &rate)) } pub fn create_invoice( @@ -324,4 +337,25 @@ fn to_payment(payment: eel::payment::Payment) -> Payment { } } +fn to_limits( + limits: eel::limits::PaymentAmountLimits, + rate: &Option, +) -> PaymentAmountLimits { + let liquidity_limit = match limits.liquidity_limit { + eel::limits::LiquidityLimit::None => LiquidityLimit::None, + eel::limits::LiquidityLimit::MaxFreeReceive { amount_msat } => { + LiquidityLimit::MaxFreeReceive { + amount: amount_msat.to_amount_down(rate), + } + } + eel::limits::LiquidityLimit::MinReceive { amount_msat } => LiquidityLimit::MinReceive { + amount: amount_msat.to_amount_up(rate), + }, + }; + PaymentAmountLimits { + max_receive: limits.max_receive_msat.to_amount_down(rate), + liquidity_limit, + } +} + include!(concat!(env!("OUT_DIR"), "/lipalightninglib.uniffi.rs")); diff --git a/src/lipalightninglib.udl b/src/lipalightninglib.udl index 5b345245..e04a8b08 100644 --- a/src/lipalightninglib.udl +++ b/src/lipalightninglib.udl @@ -40,7 +40,7 @@ interface LightningNode { [Throws=LnError] LspFee query_lsp_fee(); - // Get the current limits for the amount (in SAT) that can be transferred in a single payment. Currently there are only limits for receiving payments. + // Get the current limits for the amount that can be transferred in a single payment. Currently there are only limits for receiving payments. // The limits (partly) depend on the channel situation of the node, so it should be called again every time the user is about to receive a payment. // The limits stay the same regardless of what amount wants to receive (= no changes while he's typing the amount) [Throws=LnError] @@ -235,15 +235,15 @@ dictionary LspFee { }; dictionary PaymentAmountLimits { - u64 max_receive_sat; // Hard limit: The maximum sat amount a user is allowed to receive per payment + Amount max_receive; // Hard limit: The maximum amount a user is allowed to receive per payment LiquidityLimit liquidity_limit; }; [Enum] interface LiquidityLimit { - None(); // inbound capacity >= max_receive_sat - MaxFreeReceive(u64 sat_amount); // Soft limit: The maximum sat amount a user can receive without being charged a setup fee - MinReceive(u64 sat_amount); // Hard limit: The minimum sat amount a user must receive with the next payment + None(); // inbound capacity >= max_receive + MaxFreeReceive(Amount amount); // Soft limit: The maximum amount a user can receive without being charged a setup fee + MinReceive(Amount amount); // Hard limit: The minimum amount a user must receive with the next payment // If this limit is provided, that means a setup fee will be charged for the incoming payment }; @@ -278,10 +278,10 @@ dictionary Payment { // it is possible that a hex hash of the description is provided instead, but that is uncommon. string? preimage; // Hex representation of the preimage. Will only be present on successful payments. Amount? network_fees; // Routing fees paid in an `Sending` payment. Will only be present if payment was successful. - // The cost of sending a payment is `amount_msat` + `network_fees_msat` + // The cost of sending a payment is `amount` + `network_fees` Amount? lsp_fees; // LSP fees paid in a `Receiving` payment. Will never be present for `Sending` payments but might be 0 for `Receiving` payments. // The amount is only paid if successful. - // The value that is received in practice is given by `amount_msat` - `lsp_fees_msat` + // The value that is received in practice is given by `amount` - `lsp_fees` string metadata; };