From e087cbe21ac23b4d92353bf8d28fa8ee9e47eb89 Mon Sep 17 00:00:00 2001 From: pm47 Date: Thu, 10 Oct 2024 13:24:44 +0200 Subject: [PATCH] add option to only consider the mining fee for the absolute fee check --- .../kotlin/fr/acinq/lightning/NodeParams.kt | 1 + .../fr/acinq/lightning/payment/LiquidityPolicy.kt | 6 ++++-- .../lightning/payment/LiquidityPolicyTestsCommon.kt | 12 ++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/commonMain/kotlin/fr/acinq/lightning/NodeParams.kt b/src/commonMain/kotlin/fr/acinq/lightning/NodeParams.kt index c1ab71dea..2778d28f5 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/NodeParams.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/NodeParams.kt @@ -239,6 +239,7 @@ data class NodeParams( maxAbsoluteFee = 2_000.sat, maxRelativeFeeBasisPoints = 3_000 /* 3000 = 30 % */, skipAbsoluteFeeCheck = false, + considerOnlyMiningFeeForAbsoluteFeeCheck = false, maxAllowedFeeCredit = 0.msat ) ), diff --git a/src/commonMain/kotlin/fr/acinq/lightning/payment/LiquidityPolicy.kt b/src/commonMain/kotlin/fr/acinq/lightning/payment/LiquidityPolicy.kt index 014dc999c..e375d0dae 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/payment/LiquidityPolicy.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/payment/LiquidityPolicy.kt @@ -20,9 +20,10 @@ sealed class LiquidityPolicy { * @param maxAbsoluteFee max absolute fee * @param maxRelativeFeeBasisPoints max relative fee (all included: service fee and mining fee) (1_000 bips = 10 %) * @param skipAbsoluteFeeCheck only applies for off-chain payments, being more lax may make sense when the sender doesn't retry payments + * @param considerOnlyMiningFeeForAbsoluteFeeCheck only consider the mining fee for the absolute fee check. This makes sense in `inboundLiquidityTarget` is used, and the funding rate predictable * @param maxAllowedFeeCredit maximum amount that can be added to fee credit (see [fr.acinq.lightning.Feature.FundingFeeCredit]) */ - data class Auto(val inboundLiquidityTarget: Satoshi?, val maxAbsoluteFee: Satoshi, val maxRelativeFeeBasisPoints: Int, val skipAbsoluteFeeCheck: Boolean, val maxAllowedFeeCredit: MilliSatoshi) : LiquidityPolicy() + data class Auto(val inboundLiquidityTarget: Satoshi?, val maxAbsoluteFee: Satoshi, val maxRelativeFeeBasisPoints: Int, val skipAbsoluteFeeCheck: Boolean, val maxAllowedFeeCredit: MilliSatoshi, val considerOnlyMiningFeeForAbsoluteFeeCheck: Boolean = false) : LiquidityPolicy() /** Make a decision for a particular liquidity event. */ fun maybeReject(amount: MilliSatoshi, fee: ChannelManagementFees, source: LiquidityEvents.Source, logger: MDCLogger): LiquidityEvents.Rejected? { @@ -34,7 +35,8 @@ sealed class LiquidityPolicy { logger.info { "liquidity policy check: amount=$amount liquidityTarget=${inboundLiquidityTarget ?: 0.sat} fee=$fee maxAbsoluteFee=$maxAbsoluteFee maxRelativeFee=$maxRelativeFee policy=$this" } when { fee.total.toMilliSatoshi() > maxRelativeFee -> LiquidityEvents.Rejected.Reason.TooExpensive.OverRelativeFee(maxRelativeFeeBasisPoints) - fee.total.toMilliSatoshi() > maxAbsoluteFee -> LiquidityEvents.Rejected.Reason.TooExpensive.OverAbsoluteFee(this.maxAbsoluteFee) + considerOnlyMiningFeeForAbsoluteFeeCheck && fee.miningFee.toMilliSatoshi() > maxAbsoluteFee -> LiquidityEvents.Rejected.Reason.TooExpensive.OverAbsoluteFee(this.maxAbsoluteFee) + !considerOnlyMiningFeeForAbsoluteFeeCheck && fee.total.toMilliSatoshi() > maxAbsoluteFee -> LiquidityEvents.Rejected.Reason.TooExpensive.OverAbsoluteFee(this.maxAbsoluteFee) else -> null // accept } } diff --git a/src/commonTest/kotlin/fr/acinq/lightning/payment/LiquidityPolicyTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/payment/LiquidityPolicyTestsCommon.kt index f05465756..146a78078 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/payment/LiquidityPolicyTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/payment/LiquidityPolicyTestsCommon.kt @@ -46,4 +46,16 @@ class LiquidityPolicyTestsCommon : LightningTestSuite() { actual = policy.maybeReject(amount = 4_000_000.msat, fee = ChannelManagementFees(miningFee = 2_000.sat, serviceFee = 0.sat), source = LiquidityEvents.Source.OnChainWallet, logger)?.reason ) } + + @Test + fun `policy rejection mining fee check`() { + val policy = LiquidityPolicy.Auto(maxAbsoluteFee = 1_000.sat, maxRelativeFeeBasisPoints = 5_000 /* 3000 = 30 % */, skipAbsoluteFeeCheck = false, inboundLiquidityTarget = null, maxAllowedFeeCredit = 0.msat, considerOnlyMiningFeeForAbsoluteFeeCheck = true) + // total fee is over absolute, but mining fee is below and we only consider the mining fee + assertNull(policy.maybeReject(amount = 10_000_000.msat, fee = ChannelManagementFees(miningFee = 900.sat, serviceFee = 2_000.sat), source = LiquidityEvents.Source.OnChainWallet, logger)) + // the mining fee is over absolute + assertEquals( + expected = LiquidityEvents.Rejected.Reason.TooExpensive.OverAbsoluteFee(policy.maxAbsoluteFee), + actual = policy.maybeReject(amount = 10_000_000.msat, fee = ChannelManagementFees(miningFee = 2_000.sat, serviceFee = 0.sat), source = LiquidityEvents.Source.OnChainWallet, logger)?.reason + ) + } } \ No newline at end of file