Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include liquidity purchase in NewChannelIncomingPayment #747

Closed
wants to merge 4 commits into from

Conversation

pm47
Copy link
Member

@pm47 pm47 commented Jan 21, 2025

Since we started using the standard liquidity ads protocol to handle swap-ins, the case of a new channel creation led to two db events: a NewChannelIncomingPayment and a InboundLiquidityOutgoingPayment. But both from a UX and from a technical point of view, these two operations actually happen atomically. Separating them creates integration hurdles, as they need to be merged again.

The first commit adds a LiquidityAds.Purchase to NewChannelIncomingPayment, and removes the InboundLiquidityOutgoingPayment db event. It also changes the meaning of NewChannelIncomingPayment.miningFee to be the overall mining fee (it was actually misnamed, should have been localMiningFee).

The second commit is just fixing consistency issues in naming.

The third commit removes localMiningFee from InboundLiquidityOutgoingPayment, for consistency with the above. Note that, while more pure from a technical point of view, having localMiningFee a main class attribute adds mental overhead, and has no use for integrators, who typically reason in total mining fee. In Phoenix this led to niceties such as: https://github.com/ACINQ/phoenix/blob/a07c153ad4e22b042dc38fed11fab89fd1f8a4de/phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/db/payments/InboundLiquidityQueries.kt#L100-L107

@pm47 pm47 requested review from dpad85 and t-bast January 21, 2025 18:09
Copy link
Member

@t-bast t-bast left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit torn, because I think this is a different trade-off and it's a bit unclear whether it's really better.

I think that the mining fee for new channel creation that includes a liquidity purchase is now simpler when the LSP computed it correctly and it exactly matches the actual tx on-chain fees, but doesn't solve the inconsistency when it doesn't, so I don't know if in practice this really removes confusion or just hides a subtlety that is still likely to come up.

We're also now introducing an inconsistency between swap-in for channel creation and other types of liquidity purchases: when creating a channel from a swap-in, we don't have a separate liquidity purchase in the DB, whereas we have one in every other type of liquidity purchase...this can be "hidden" if the DB correctly includes liquidity purchases from channel creation, but this is something that requires code outside of lightning-kmp: when implementing OutgoingPaymentsDb.getInboundLiquidityPurchase(fundingTxId: TxId) we now must also look at the incoming payments DB and check if we have a channel for this fundingTxId that includes a liquidity purchase. Is that implemented in Phoenix @dpad85?

data class ViaClose(val amount: Satoshi, override val miningFees: Satoshi, val address: String, override val txId: TxId, val isSentToDefaultAddress: Boolean, val closingType: ChannelClosingType) : StoreOutgoingPayment()
data class ViaSpliceOut(val amount: Satoshi, override val miningFee: Satoshi, val address: String, override val txId: TxId) : StoreOutgoingPayment()
data class ViaSpliceCpfp(override val miningFee: Satoshi, override val txId: TxId) : StoreOutgoingPayment()
data class ViaInboundLiquidityRequest(override val txId: TxId, override val miningFee: Satoshi, val purchase: LiquidityAds.Purchase) : StoreOutgoingPayment()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a different trade-off in terms of clarity: there is a subtlety here which is now completely hidden and should at least be explained in a comment (before your change, all the components of the total fee paid were IMO clearer because they were explicitly included in different variables).

In the miningFee field, we're including both the on-chain fees we're directly paying from the on-chain tx AND purchase.fees.miningFee, which aren't paid on-chain but rather refunded to the LSP off-chain. So miningFee should be close to the actual mining fees of the transaction, but may sometimes differ (and can be either larger or smaller than the real on-chain fees). This can be a source of confusion for users which I think must be explained.

@@ -45,10 +45,11 @@ object Deserialization {
private fun Input.readIncomingPayment(): IncomingPayment = when (val discriminator = read()) {
0x00 -> readBolt11IncomingPayment()
0x01 -> readBolt12IncomingPayment()
0x02 -> readNewChannelIncomingPayment()
// 0x02 -> do not use
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we need to keep deserializing this?

Comment on lines 146 to 148
// We only count the mining fees that we must refund to our peer as part of the liquidity purchase.
// If we're also contributing to the funding transaction, the mining fees we pay for our inputs and
// outputs will be recorded in the ViaNewChannel incoming payment entry below.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is now obsolete?

@dpad85
Copy link
Member

dpad85 commented Jan 22, 2025

getInboundLiquidityPurchase(fundingTxId: TxId) must also look at the incoming payments DB (...). Is that implemented in Phoenix

No it's not, we just look at the outgoing payments. It may be possible to also look at the incoming payments and try constructing an InboundLiquidityOutgoingPayment out of the data we find there, but it's a bit dirty.

Now both `OnChainIncomingPayment` and `LightningIncomingPayment` include
a liquidity purchase, saving a lookup for integrators.

`InboundLiquidityOutgoingPayment` is now only used for manual liquidity
requests and renamed to this effect.
@pm47
Copy link
Member Author

pm47 commented Jan 23, 2025

Superseded by #749.

@pm47 pm47 closed this Jan 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants