Skip to content

Commit

Permalink
Link liquidity events to swap-in payments (#636)
Browse files Browse the repository at this point in the history
Swap-ins that create a new channel trigger a liquidity event. To be
consistent, these liquidity events should display a link to the swap
payment.

Also lightning-kmp 1.8.1 fixes an issue with swap-in payments mining
fee, which is now split between local and purchase fees. For compat
with legacy leases, we do not store the local fee separately in
the database. Instead we store the full mining fee and retrieve
the local fee by subtracting this full fee with the purchase fee.

---------

Co-authored-by: Robbie Hanson <304604+robbiehanson@users.noreply.github.com>
  • Loading branch information
dpad85 and robbiehanson authored Oct 9, 2024
1 parent 3ed7c20 commit 39f9694
Show file tree
Hide file tree
Showing 27 changed files with 195 additions and 130 deletions.
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/Versions.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
object Versions {
const val lightningKmp = "1.8.0"
const val lightningKmp = "1.8.1-SNAPSHOT"
const val secp256k1 = "0.14.0"
const val torMobile = "0.2.0"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,14 +282,6 @@ private fun AmountSection(
rateThen = rateThen,
mSatDisplayPolicy = MSatDisplayPolicy.SHOW
)
payment.amountFeeCredit?.let {
TechnicalRowAmount(
label = stringResource(R.string.paymentdetails_amount_fee_credit_label),
amount = it,
rateThen = rateThen,
mSatDisplayPolicy = MSatDisplayPolicy.SHOW
)
}
val receivedWithNewChannel = payment.received?.receivedWith?.filterIsInstance<IncomingPayment.ReceivedWith.NewChannel>() ?: emptyList()
val receivedWithSpliceIn = payment.received?.receivedWith?.filterIsInstance<IncomingPayment.ReceivedWith.SpliceIn>() ?: emptyList()
if ((receivedWithNewChannel + receivedWithSpliceIn).isNotEmpty()) {
Expand Down Expand Up @@ -398,12 +390,7 @@ private fun DetailsForInboundLiquidity(
label = stringResource(id = R.string.paymentdetails_liquidity_caused_by_label),
onClick = { navigateToPaymentDetails(navController, it, isFromEvent = false) },
) {
TextWithIcon(
text = "(incoming) ${it.dbId}",
icon = R.drawable.ic_arrow_down_circle,
maxLines = 1, textOverflow = TextOverflow.Ellipsis,
space = 4.dp
)
Text(text = it.dbId, maxLines = 1, overflow = TextOverflow.Ellipsis)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ import fr.acinq.phoenix.android.utils.annotatedStringResource
import fr.acinq.phoenix.android.utils.mutedTextColor
import fr.acinq.phoenix.android.utils.negativeColor
import fr.acinq.phoenix.android.utils.positiveColor
import fr.acinq.phoenix.utils.extensions.isManualPurchase
import fr.acinq.phoenix.utils.extensions.minDepthForFunding
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.filterIsInstance
Expand Down Expand Up @@ -402,10 +403,9 @@ fun SplashLiquidityStatus(payment: InboundLiquidityOutgoingPayment, fromEvent: B
else -> {
PaymentStatusIcon(
message = {
if (payment.purchase.paymentDetails is LiquidityAds.PaymentDetails.FromChannelBalance) {
Text(text = annotatedStringResource(id = R.string.paymentdetails_status_inbound_liquidity_success, lockedAt.toRelativeDateString()))
} else {
Text(text = annotatedStringResource(id = R.string.paymentdetails_status_inbound_liquidity_auto_success, lockedAt.toRelativeDateString()))
when {
payment.isManualPurchase() -> Text(text = annotatedStringResource(id = R.string.paymentdetails_status_inbound_liquidity_success, lockedAt.toRelativeDateString()))
else -> Text(text = annotatedStringResource(id = R.string.paymentdetails_status_inbound_liquidity_auto_success, lockedAt.toRelativeDateString()))
}
},
imageResId = if (fromEvent) R.drawable.ic_payment_details_success_animated else R.drawable.ic_payment_details_success_static,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,61 +16,34 @@

package fr.acinq.phoenix.android.payments.details.splash

import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import fr.acinq.lightning.db.InboundLiquidityOutgoingPayment
import fr.acinq.lightning.utils.sat
import fr.acinq.lightning.wire.LiquidityAds
import fr.acinq.phoenix.android.LocalBitcoinUnit
import fr.acinq.phoenix.android.R
import fr.acinq.phoenix.android.Screen
import fr.acinq.phoenix.android.business
import fr.acinq.phoenix.android.components.BorderButton
import fr.acinq.phoenix.android.components.BottomSheetDialog
import fr.acinq.phoenix.android.components.Button
import fr.acinq.phoenix.android.components.Clickable
import fr.acinq.phoenix.android.components.SplashClickableContent
import fr.acinq.phoenix.android.components.SplashLabelRow
import fr.acinq.phoenix.android.components.TextWithIcon
import fr.acinq.phoenix.android.navController
import fr.acinq.phoenix.android.navigateToPaymentDetails
import fr.acinq.phoenix.android.payments.details.PaymentLine
import fr.acinq.phoenix.android.payments.details.PaymentLineLoading
import fr.acinq.phoenix.android.utils.Converter.toPrettyString
import fr.acinq.phoenix.android.utils.MSatDisplayPolicy
import fr.acinq.phoenix.android.utils.mutedBgColor
import fr.acinq.phoenix.data.WalletPaymentFetchOptions
import fr.acinq.phoenix.data.WalletPaymentId
import fr.acinq.phoenix.data.WalletPaymentInfo
import fr.acinq.phoenix.utils.extensions.isManualPurchase
import fr.acinq.phoenix.utils.extensions.isPaidInTheFuture
import fr.acinq.phoenix.utils.extensions.relatedPaymentIds
import kotlinx.coroutines.launch

@Composable
fun SplashLiquidityPurchase(
Expand All @@ -85,9 +58,11 @@ fun SplashLiquidityPurchase(
private fun SplashPurchase(
payment: InboundLiquidityOutgoingPayment,
) {
val btcUnit = LocalBitcoinUnit.current
SplashLabelRow(label = "Liquidity") {
Text(text = payment.purchase.amount.toPrettyString(btcUnit, withUnit = true, mSatDisplayPolicy = MSatDisplayPolicy.SHOW_IF_ZERO_SATS))
if (payment.purchase.amount > 1.sat) {
val btcUnit = LocalBitcoinUnit.current
SplashLabelRow(label = stringResource(id = R.string.paymentdetails_liquidity_purchase_label)) {
Text(text = payment.purchase.amount.toPrettyString(btcUnit, withUnit = true, mSatDisplayPolicy = MSatDisplayPolicy.SHOW_IF_ZERO_SATS))
}
}
}

Expand All @@ -97,28 +72,34 @@ private fun SplashFee(
) {
val btcUnit = LocalBitcoinUnit.current
if (!payment.isPaidInTheFuture()) {
Spacer(modifier = Modifier.height(8.dp))
val miningFee = payment.feePaidFromChannelBalance.miningFee
val serviceFee = payment.feePaidFromChannelBalance.serviceFee
SplashLabelRow(
label = stringResource(id = R.string.paymentdetails_liquidity_miner_fee_label),
helpMessage = stringResource(id = R.string.paymentdetails_liquidity_miner_fee_help)
) {
Text(text = miningFee.toPrettyString(btcUnit, withUnit = true, mSatDisplayPolicy = MSatDisplayPolicy.SHOW_IF_ZERO_SATS))
}
Spacer(modifier = Modifier.height(8.dp))
SplashLabelRow(
label = stringResource(id = R.string.paymentdetails_liquidity_service_fee_label),
helpMessage = stringResource(id = R.string.paymentdetails_liquidity_service_fee_help)
) {
Text(text = serviceFee.toPrettyString(btcUnit, withUnit = true, mSatDisplayPolicy = MSatDisplayPolicy.SHOW_IF_ZERO_SATS))
}
Spacer(modifier = Modifier.height(8.dp))
SplashLabelRow(
label = stringResource(id = R.string.paymentdetails_liquidity_miner_fee_label),
helpMessage = stringResource(id = R.string.paymentdetails_liquidity_miner_fee_help)
) {
Text(text = miningFee.toPrettyString(btcUnit, withUnit = true, mSatDisplayPolicy = MSatDisplayPolicy.SHOW_IF_ZERO_SATS))
}
}
}

@Composable
private fun SplashRelatedPayments(payment: InboundLiquidityOutgoingPayment) {
val relatedPaymentIds = payment.relatedPaymentIds()

val paymentsManager = business.paymentsManager
val relatedPaymentIds by produceState(initialValue = emptyList(), key1 = payment) {
value = if (payment.purchase.paymentDetails is LiquidityAds.PaymentDetails.FromChannelBalance) {
paymentsManager.listIncomingPaymentsForTxId(payment.txId)
} else payment.relatedPaymentIds()
}
if (relatedPaymentIds.isNotEmpty()) {
val navController = navController
val paymentId = relatedPaymentIds.first()
Expand All @@ -130,7 +111,6 @@ private fun SplashRelatedPayments(payment: InboundLiquidityOutgoingPayment) {
) {
Button(
text = paymentId.dbId,
icon = R.drawable.ic_zap,
onClick = { navigateToPaymentDetails(navController, paymentId, isFromEvent = false) },
maxLines = 1,
padding = PaddingValues(horizontal = 7.dp, vertical = 5.dp),
Expand Down
2 changes: 1 addition & 1 deletion phoenix-android/src/main/res/values-b+es+419/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@
<string name="paymentdetails_desc_legacy_migration">Migración desde aplicación heredada</string>
<string name="paymentdetails_desc_cpfp">Impulsar transacciones</string>
<string name="paymentdetails_desc_liquidity_manual">Liquidez manual (+%1$s)</string>
<string name="paymentdetails_desc_liquidity_automated">Liquidez automatizada</string>
<string name="paymentdetails_desc_liquidity_automated">Gestión de canales</string>
<string name="paymentdetails_desc_swapout">Intercambiar a %1$s</string>
<string name="paymentdetails_desc_swapin">Depósito en la cadena</string>

Expand Down
2 changes: 1 addition & 1 deletion phoenix-android/src/main/res/values-cs/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@
<string name="paymentdetails_desc_legacy_migration">Migrace ze staré aplikace</string>
<string name="paymentdetails_desc_cpfp">Postrčit transakci</string>
<string name="paymentdetails_desc_liquidity_manual">Manuální likvidita (+%1$s)</string>
<string name="paymentdetails_desc_liquidity_automated">Automatizovaná likvidita</string>
<string name="paymentdetails_desc_liquidity_automated">Správa kanálů</string>
<string name="paymentdetails_desc_swapout">Swap-out do %1$s</string>
<string name="paymentdetails_desc_swapin">On-Chain vklad</string>

Expand Down
2 changes: 1 addition & 1 deletion phoenix-android/src/main/res/values-de/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@
<string name="paymentdetails_desc_legacy_migration">Migration von Legacy-App</string>
<string name="paymentdetails_desc_cpfp">Beschleunigte Transaktion</string>
<string name="paymentdetails_desc_liquidity_manual">Manuelle Liquidität (+%1$s)</string>
<string name="paymentdetails_desc_liquidity_automated">Automatisierte Liquidität</string>
<string name="paymentdetails_desc_liquidity_automated">Kanal-Verwaltung</string>
<string name="paymentdetails_desc_swapout">Swap-out an %1$s</string>
<string name="paymentdetails_desc_swapin">On-Chain Einzahlung</string>

Expand Down
2 changes: 1 addition & 1 deletion phoenix-android/src/main/res/values-fr/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@
<string name="paymentdetails_desc_legacy_migration">Migration depuis l\'ancienne appli</string>
<string name="paymentdetails_desc_cpfp">Accélération de transactions</string>
<string name="paymentdetails_desc_liquidity_manual">Liquidité manuelle (+%1$s)</string>
<string name="paymentdetails_desc_liquidity_automated">Liquidité automatique</string>
<string name="paymentdetails_desc_liquidity_automated">Gestion de canaux</string>
<string name="paymentdetails_desc_swapout">Swap-out vers %1$s</string>
<string name="paymentdetails_desc_swapin">Dépôt on-chain</string>

Expand Down
2 changes: 1 addition & 1 deletion phoenix-android/src/main/res/values-pt-rBR/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@
<string name="paymentdetails_desc_legacy_migration">Migração de aplicativo legado</string>
<string name="paymentdetails_desc_cpfp">Impulsionar transações</string>
<string name="paymentdetails_desc_liquidity_manual">Liquidez manual (+%1$s)</string>
<string name="paymentdetails_desc_liquidity_automated">Liquidez automatizada</string>
<string name="paymentdetails_desc_liquidity_automated">Gerenciamento de canais</string>
<string name="paymentdetails_desc_swapout">Trocar para %1$s</string>
<string name="paymentdetails_desc_swapin">Depósito na rede</string>

Expand Down
2 changes: 1 addition & 1 deletion phoenix-android/src/main/res/values-sk/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@
<string name="paymentdetails_desc_legacy_migration">Migrácia zo staršej aplikácie</string>
<string name="paymentdetails_desc_cpfp">Urýchliť transakciu</string>
<string name="paymentdetails_desc_liquidity_manual">Manuálna likvidita (+%1$s)</string>
<string name="paymentdetails_desc_liquidity_automated">Automatizovaná likvidita</string>
<string name="paymentdetails_desc_liquidity_automated">Správa kanálo</string>
<string name="paymentdetails_desc_swapout">Swap-out na %1$s</string>
<string name="paymentdetails_desc_swapin">On-chain vklad</string>

Expand Down
2 changes: 1 addition & 1 deletion phoenix-android/src/main/res/values-sw/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@
<string name="paymentdetails_desc_legacy_migration">Uhamaji kutoka programu ya zamani</string>
<string name="paymentdetails_desc_cpfp">Kuweka vipaumbele vya muamala</string>
<string name="paymentdetails_desc_liquidity_manual">Ukwasi wa mwongozo (+%1$s)</string>
<string name="paymentdetails_desc_liquidity_automated">Ukwasi wa kiotomatiki</string>
<string name="paymentdetails_desc_liquidity_automated">Usimamizi wa Channel</string>
<string name="paymentdetails_desc_swapout">Kubadilisha kwa %1$s</string>
<string name="paymentdetails_desc_swapin">Depo ya on-chain</string>

Expand Down
2 changes: 1 addition & 1 deletion phoenix-android/src/main/res/values-vi/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@
<string name="paymentdetails_desc_legacy_migration">Di chuyển từ ứng dụng cũ</string>
<string name="paymentdetails_desc_cpfp">Các giao dịch tăng đột biến</string>
<string name="paymentdetails_desc_liquidity_manual">Thanh khoản thủ công (+%1$s)</string>
<string name="paymentdetails_desc_liquidity_automated">Thanh khoản tự động</string>
<string name="paymentdetails_desc_liquidity_automated">Quản lý kênh</string>
<string name="paymentdetails_desc_swapout">Swap-out thành %1$s</string>
<string name="paymentdetails_desc_swapin">Tiền cọc on-chain</string>

Expand Down
4 changes: 2 additions & 2 deletions phoenix-android/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@
<string name="paymentdetails_error">Could not find payment details</string>

<string name="paymentdetails_status_inbound_liquidity_success"><b>LIQUIDITY ADDED</b> %1$s</string>
<string name="paymentdetails_status_inbound_liquidity_auto_success"><b>CHANNEL RESIZED</b> %1$s</string>
<string name="paymentdetails_status_inbound_liquidity_auto_success"><b>CHANNEL MANAGEMENT</b> %1$s</string>
<string name="paymentdetails_status_channelclose_confirmed"><b>COMPLETE</b> %1$s</string>
<string name="paymentdetails_status_sent_successful"><b>SENT</b> %1$s</string>
<string name="paymentdetails_status_sent_pending">Pending…</string>
Expand Down Expand Up @@ -393,7 +393,7 @@
<string name="paymentdetails_desc_legacy_migration">Migration from legacy app</string>
<string name="paymentdetails_desc_cpfp">Bump transactions</string>
<string name="paymentdetails_desc_liquidity_manual">Manual liquidity (+%1$s)</string>
<string name="paymentdetails_desc_liquidity_automated">Automated liquidity</string>
<string name="paymentdetails_desc_liquidity_automated">Channel management</string>
<string name="paymentdetails_desc_swapout">Swap-out to %1$s</string>
<string name="paymentdetails_desc_swapin">On-chain deposit</string>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,3 +364,10 @@ extension Lightning_kmpBolt11Invoice {
return timestampSeconds.toDate(from: .seconds)
}
}

extension Lightning_kmpInboundLiquidityOutgoingPayment {

var hidesFees: Bool {
return self.isPaidInTheFuture()
}
}
2 changes: 1 addition & 1 deletion phoenix-ios/phoenix-ios/officers/BusinessManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ class BusinessManager {
public func stop() {

cancellables.removeAll()
business.stop()
business.stop(closeDatabases: true)
syncManager?.shutdown()
}

Expand Down
12 changes: 7 additions & 5 deletions phoenix-ios/phoenix-ios/views/inspect/DetailsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ fileprivate var log = LoggerFactory.shared.logger(filename, .warning)
struct DetailsView: View {

let location: PaymentView.Location

@Binding var paymentInfo: WalletPaymentInfo
@Binding var relatedPaymentIds: [WalletPaymentId]
@Binding var liquidityPayment: Lightning_kmpInboundLiquidityOutgoingPayment?

@Binding var showOriginalFiatValue: Bool
Expand Down Expand Up @@ -1086,7 +1088,7 @@ fileprivate struct DetailsInfoGrid: InfoGridView {

if payment.isManualPurchase() {
Text("Manual")
} else if payment.isPaidInTheFuture() {
} else if payment.purchase.paymentDetails is Lightning_kmpLiquidityAdsPaymentDetailsFromFutureHtlc {
Text("Automatic [FromFutureHtlc]")
} else {
Text("Automatic [FromChannelBalance]")
Expand Down Expand Up @@ -1493,13 +1495,13 @@ fileprivate struct DetailsInfoGrid: InfoGridView {
func minerFees() -> (Int64, String, String)? {

if let liquidity = paymentInfo.payment as? Lightning_kmpInboundLiquidityOutgoingPayment,
liquidity.isPaidInTheFuture() {
liquidity.hidesFees {
// We don't display the fees here.
// Instead we're displaying the fees on the corresponding IncomingPayment.
return nil
} else if let result = paymentInfo.payment.minerFees() {
return result
} else if let liquidityPayment, liquidityPayment.isPaidInTheFuture() {
} else if let liquidityPayment, liquidityPayment.hidesFees {
// This is the corresponding IncomingPayment, and we have the linked liquidityPayment.
return liquidityPayment.minerFees()
} else {
Expand All @@ -1510,13 +1512,13 @@ fileprivate struct DetailsInfoGrid: InfoGridView {
func serviceFees() -> (Int64, String, String)? {

if let liquidity = paymentInfo.payment as? Lightning_kmpInboundLiquidityOutgoingPayment,
liquidity.isPaidInTheFuture() {
liquidity.hidesFees {
// We don't display the fees here.
// Instead we're displaying the fees on the corresponding IncomingPayment.
return nil
} else if let result = paymentInfo.payment.serviceFees() {
return result
} else if let liquidityPayment, liquidityPayment.isPaidInTheFuture() {
} else if let liquidityPayment, liquidityPayment.hidesFees {
// This is the corresponding IncomingPayment, and we have the linked liquidityPayment.
return liquidityPayment.serviceFees()
} else {
Expand Down
Loading

0 comments on commit 39f9694

Please sign in to comment.