Skip to content

Commit

Permalink
Remove minInboundLiquidityTarget
Browse files Browse the repository at this point in the history
We previously forced wallets to purchase additional inbound liquidity
every time an on-chain transaction was created. We now allow wallets
to disable automatic liquidity purchases: the LSP will need to add
enough funds on their side to cover the commitment fees, which the
wallet won't be paying for. But we still make a dummy purchase of 1 sat
to ensure that the liquidity ads flow is used and the wallet refunds
the mining fees paid by the LSP.
  • Loading branch information
t-bast committed Sep 12, 2024
1 parent c5e4ccd commit 4ce61b1
Show file tree
Hide file tree
Showing 5 changed files with 17 additions and 23 deletions.
6 changes: 4 additions & 2 deletions src/commonMain/kotlin/fr/acinq/lightning/io/Peer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -1272,9 +1272,11 @@ class Peer(
val currentFeerates = peerFeeratesFlow.filterNotNull().first()
val requestRemoteFunding = run {
// We need our peer to contribute, because they must have enough funds to pay the commitment fees.
// That means they will add at least one input to the funding transaction, and pay the corresponding mining fees.
// We always request a liquidity purchase, even for a dummy amount, which ensures that we refund their mining fees.
val inboundLiquidityTarget = when (val policy = nodeParams.liquidityPolicy.first()) {
is LiquidityPolicy.Disable -> LiquidityPolicy.minInboundLiquidityTarget
is LiquidityPolicy.Auto -> policy.inboundLiquidityTarget ?: LiquidityPolicy.minInboundLiquidityTarget
is LiquidityPolicy.Disable -> 1.sat
is LiquidityPolicy.Auto -> policy.inboundLiquidityTarget ?: 1.sat
}
// We assume that the liquidity policy is correctly configured to match a funding lease offered by our peer.
val fundingRate = walletParams.remoteFundingRates.findRate(inboundLiquidityTarget)!!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,9 +298,9 @@ class IncomingPaymentHandler(val nodeParams: NodeParams, val db: PaymentsDb, pri
return when (val liquidityPolicy = nodeParams.liquidityPolicy.value) {
is LiquidityPolicy.Disable -> Either.Left(LiquidityEvents.Rejected(willAddHtlcAmount, 0.msat, LiquidityEvents.Source.OffChainPayment, LiquidityEvents.Rejected.Reason.PolicySetToDisabled))
is LiquidityPolicy.Auto -> {
// Whenever we receive on-the-fly funding, we take this opportunity to purchase inbound liquidity.
// Whenever we receive on-the-fly funding, we take this opportunity to purchase inbound liquidity, if configured.
// This reduces the frequency of on-chain funding and thus the overall on-chain fees paid.
val additionalInboundLiquidity = liquidityPolicy.inboundLiquidityTarget ?: LiquidityPolicy.minInboundLiquidityTarget
val additionalInboundLiquidity = liquidityPolicy.inboundLiquidityTarget ?: 0.sat
// We must round up to the nearest satoshi value instead of rounding down.
val requestedAmount = (willAddHtlcAmount + 999.msat).truncateToSatoshi() + additionalInboundLiquidity
when (val fundingRate = remoteFundingRates.findRate(requestedAmount)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,4 @@ sealed class LiquidityPolicy {
}
}?.let { reason -> LiquidityEvents.Rejected(amount, fee, source, reason) }
}

companion object {
/**
* We usually need our peer to contribute to channel funding, because they must have enough funds to pay the commitment fees.
* When we don't have an inbound liquidity target set, we use the following default amount.
*/
val minInboundLiquidityTarget: Satoshi = 100_000.sat
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ class PeerTest : LightningTestSuite() {
@Test
fun `swap funds into a channel`() = runSuspendTest {
val nodeParams = Pair(TestConstants.Alice.nodeParams, TestConstants.Bob.nodeParams)
nodeParams.second.liquidityPolicy.emit(LiquidityPolicy.Auto(inboundLiquidityTarget = null, maxAbsoluteFee = 20_000.sat, maxRelativeFeeBasisPoints = 1000, skipAbsoluteFeeCheck = false))
nodeParams.second.liquidityPolicy.emit(LiquidityPolicy.Auto(inboundLiquidityTarget = 100_000.sat, maxAbsoluteFee = 20_000.sat, maxRelativeFeeBasisPoints = 1000, skipAbsoluteFeeCheck = false))
val walletParams = Pair(TestConstants.Alice.walletParams, TestConstants.Bob.walletParams)
val (_, bob, _, bob2alice) = newPeers(this, nodeParams, walletParams, automateMessaging = false)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ class IncomingPaymentHandlerTestsCommon : LightningTestSuite() {
assertIs<AddLiquidityForIncomingPayment>(addLiquidity)
assertEquals(incomingPayment.preimage, addLiquidity.preimage)
assertEquals(defaultAmount, addLiquidity.paymentAmount)
assertTrue(defaultAmount < addLiquidity.requestedAmount)
assertEquals(defaultAmount, addLiquidity.requestedAmount.toMilliSatoshi())
assertEquals(TestConstants.fundingRates.fundingRates.first(), addLiquidity.fundingRate)
assertEquals(listOf(willAddHtlc), addLiquidity.willAddHtlcs)
// We don't update the payments DB: we're waiting to receive HTLCs after the open/splice.
Expand Down Expand Up @@ -359,7 +359,7 @@ class IncomingPaymentHandlerTestsCommon : LightningTestSuite() {
assertIs<AddLiquidityForIncomingPayment>(addLiquidity)
assertEquals(incomingPayment.preimage, addLiquidity.preimage)
assertEquals(defaultAmount, addLiquidity.paymentAmount)
assertTrue(defaultAmount < addLiquidity.requestedAmount)
assertEquals(defaultAmount, addLiquidity.requestedAmount.toMilliSatoshi())
assertEquals(TestConstants.fundingRates.fundingRates.first(), addLiquidity.fundingRate)
assertNull(paymentHandler.db.getIncomingPayment(incomingPayment.paymentHash)?.received)
}
Expand Down Expand Up @@ -464,7 +464,7 @@ class IncomingPaymentHandlerTestsCommon : LightningTestSuite() {
@Test
fun `receive multipart payment with a mix of HTLC and will_add_htlc`() = runSuspendTest {
val channelId = randomBytes32()
val (amount1, amount2) = listOf(50_000_000.msat, 60_000_000.msat)
val (amount1, amount2) = listOf(50_000_000.msat, 100_000_000.msat)
val totalAmount = amount1 + amount2
val (paymentHandler, incomingPayment, paymentSecret) = createFixture(totalAmount)
checkDbPayment(incomingPayment, paymentHandler.db)
Expand All @@ -489,7 +489,7 @@ class IncomingPaymentHandlerTestsCommon : LightningTestSuite() {
assertEquals(1, result.actions.size)
val addLiquidity = result.actions.first() as AddLiquidityForIncomingPayment
assertEquals(incomingPayment.preimage, addLiquidity.preimage)
assertEquals(amount2.truncateToSatoshi() + LiquidityPolicy.minInboundLiquidityTarget, addLiquidity.requestedAmount)
assertEquals(amount2.truncateToSatoshi(), addLiquidity.requestedAmount)
assertEquals(totalAmount, addLiquidity.paymentAmount)
assertNull(paymentHandler.db.getIncomingPayment(incomingPayment.paymentHash)?.received)
}
Expand Down Expand Up @@ -617,7 +617,7 @@ class IncomingPaymentHandlerTestsCommon : LightningTestSuite() {
@Test
fun `receive multipart payment with funding fee`() = runSuspendTest {
val channelId = randomBytes32()
val (amount1, amount2) = listOf(50_000_000.msat, 60_000_000.msat)
val (amount1, amount2) = listOf(50_000_000.msat, 100_000_000.msat)
val totalAmount = amount1 + amount2
val (paymentHandler, incomingPayment, paymentSecret) = createFixture(totalAmount)
checkDbPayment(incomingPayment, paymentHandler.db)
Expand Down Expand Up @@ -676,7 +676,7 @@ class IncomingPaymentHandlerTestsCommon : LightningTestSuite() {
@Test
fun `receive payment with funding fee -- from channel balance`() = runSuspendTest {
val channelId = randomBytes32()
val amount = 50_000_000.msat
val amount = 100_000_000.msat
val (paymentHandler, incomingPayment, paymentSecret) = createFixture(amount)
checkDbPayment(incomingPayment, paymentHandler.db)

Expand Down Expand Up @@ -743,7 +743,7 @@ class IncomingPaymentHandlerTestsCommon : LightningTestSuite() {

// We have a matching transaction in our DB.
val purchase = LiquidityAds.Purchase.Standard(
defaultAmount.truncateToSatoshi() + LiquidityPolicy.minInboundLiquidityTarget,
defaultAmount.truncateToSatoshi(),
LiquidityAds.Fees(2000.sat, 3000.sat),
LiquidityAds.PaymentDetails.FromFutureHtlc(listOf(incomingPayment.paymentHash)),
)
Expand Down Expand Up @@ -779,7 +779,7 @@ class IncomingPaymentHandlerTestsCommon : LightningTestSuite() {

// We have a matching transaction in our DB, but we paid the fees from our channel balance already.
val purchase = LiquidityAds.Purchase.Standard(
defaultAmount.truncateToSatoshi() + LiquidityPolicy.minInboundLiquidityTarget,
defaultAmount.truncateToSatoshi(),
LiquidityAds.Fees(2000.sat, 3000.sat),
LiquidityAds.PaymentDetails.FromChannelBalanceForFutureHtlc(listOf(incomingPayment.paymentHash)),
)
Expand All @@ -801,7 +801,7 @@ class IncomingPaymentHandlerTestsCommon : LightningTestSuite() {

// We have a matching transaction in our DB, but the fees must be paid with a different payment_hash.
val purchase = LiquidityAds.Purchase.Standard(
defaultAmount.truncateToSatoshi() + LiquidityPolicy.minInboundLiquidityTarget,
defaultAmount.truncateToSatoshi(),
LiquidityAds.Fees(2000.sat, 3000.sat),
LiquidityAds.PaymentDetails.FromFutureHtlc(listOf(randomBytes32())),
)
Expand Down Expand Up @@ -1436,7 +1436,7 @@ class IncomingPaymentHandlerTestsCommon : LightningTestSuite() {

// We have a matching transaction in our DB, but the fees must be paid with a different payment_hash.
val purchase = LiquidityAds.Purchase.Standard(
defaultAmount.truncateToSatoshi() + LiquidityPolicy.minInboundLiquidityTarget,
defaultAmount.truncateToSatoshi(),
LiquidityAds.Fees(2000.sat, 3000.sat),
LiquidityAds.PaymentDetails.FromFutureHtlcWithPreimage(listOf(preimage)),
)
Expand Down

0 comments on commit 4ce61b1

Please sign in to comment.