Skip to content

Commit

Permalink
Support new on-the-fly funding (#632)
Browse files Browse the repository at this point in the history
Now using lightning-kmp 1.8.0.

- Updated the liquidity policy (see NodeParamsManager). We
are using a policy that does not target additional liquidity
and that does not use fee credit yet.

- Updated the received-with database object with new types
- Updated the liquidity-purchase database objects with new
purchase & payment-details types. The lease data are now
legacy and are removed wherever possible.

- Updated the iOS and Android payment screens for liquidity 
purchases. Liquidity events are now stored as separate payments.
These payments may be linked to incoming payments, if so
a button is added in the liquidity screen to navigate to these
payments.

- (android) Completed the Portuguese (BR) translation.

---------

Co-authored-by: Robbie Hanson <[email protected]>
  • Loading branch information
dpad85 and robbiehanson authored Oct 4, 2024
1 parent 46397f8 commit 5fbe04e
Show file tree
Hide file tree
Showing 124 changed files with 4,417 additions and 2,165 deletions.
4 changes: 2 additions & 2 deletions 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.7.3"
const val lightningKmp = "1.8.0"
const val secp256k1 = "0.14.0"
const val torMobile = "0.2.0"

Expand All @@ -18,7 +18,7 @@ object Versions {
const val lifecycle = "2.6.0"
const val prefs = "1.2.0"
const val datastore = "1.0.0"
const val compose = "1.6.2"
const val compose = "1.6.8"
const val composeCompiler = "1.5.8"
const val navCompose = "2.6.0"
const val accompanist = "0.30.1"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2024 ACINQ SAS
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package fr.acinq.phoenix.android.components

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.MaterialTheme
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BottomSheetDialog(
onDismiss: () -> Unit,
modifier: Modifier = Modifier,
skipPartiallyExpanded: Boolean = true,
horizontalAlignment: Alignment.Horizontal = Alignment.Start,
scrimAlpha: Float = 0.2f,
internalPadding: PaddingValues = PaddingValues(top = 0.dp, start = 20.dp, end = 20.dp, bottom = 64.dp),
content: @Composable ColumnScope.() -> Unit,
) {
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded)
ModalBottomSheet(
sheetState = sheetState,
onDismissRequest = {
// executed when user click outside the sheet, and after sheet has been hidden thru state.
onDismiss()
},
modifier = modifier,
containerColor = MaterialTheme.colors.surface,
contentColor = MaterialTheme.colors.onSurface,
scrimColor = MaterialTheme.colors.onBackground.copy(alpha = scrimAlpha),
) {
Column(
horizontalAlignment = horizontalAlignment,
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
.verticalScroll(rememberScrollState())
.padding(internalPadding)
) {
content()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -336,11 +336,13 @@ fun Button(
}
}

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun Clickable(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
onLongClick: (() -> Unit)? = null,
textStyle: TextStyle = MaterialTheme.typography.button,
backgroundColor: Color = Color.Unspecified, // transparent by default!
shape: Shape = RectangleShape,
Expand All @@ -360,8 +362,11 @@ fun Clickable(
elevation = 0.dp,
modifier = modifier
.clip(shape)
.clickable(
.combinedClickable(
onClick = onClick,
onLongClick = onLongClick,
onLongClickLabel = null,
onDoubleClick = null,
enabled = enabled,
role = Role.Button,
onClickLabel = clickDescription,
Expand Down Expand Up @@ -422,7 +427,7 @@ fun AddressLinkButton(
}

@Composable
fun TransactionLinkButton(
fun InlineTransactionLink(
modifier: Modifier = Modifier,
txId: TxId,
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ fun RowScope.IconPopup(
popupLink: Pair<String, String>? = null,
spaceLeft: Dp? = 8.dp,
spaceRight: Dp? = null,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
) {
var showPopup by remember { mutableStateOf(false) }
spaceLeft?.let { Spacer(Modifier.requiredWidth(it)) }
Expand All @@ -191,7 +191,7 @@ fun RowScope.IconPopup(
padding = PaddingValues(iconPadding),
modifier = modifier.requiredSize(iconSize),
interactionSource = interactionSource,
onClick = { showPopup = true }
onClick = { showPopup = true },
)
if (showPopup) {
PopupDialog(onDismiss = { showPopup = false }, message = popupMessage, button = popupLink?.let { (text, link) ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
Expand All @@ -34,7 +33,6 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
Expand Down Expand Up @@ -105,8 +103,8 @@ fun SplashLayout(
}
Column(
modifier = Modifier
.widthIn(max = 500.dp)
.padding(horizontal = 24.dp),
.widthIn(max = 700.dp)
.padding(horizontal = 6.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
bottomContent()
Expand All @@ -127,27 +125,30 @@ fun SplashLabelRow(
) {
Row {
Row(
modifier = Modifier.weight(1f).alignByBaseline(),
modifier = Modifier
.weight(1f)
.heightIn(min = 22.dp)
.alignByBaseline(),
horizontalArrangement = Arrangement.End
) {
Spacer(modifier = Modifier.weight(1f))
if (helpMessage != null) {
IconPopup(modifier = Modifier.offset(y = (-3).dp), popupMessage = helpMessage, popupLink = helpLink, spaceLeft = 0.dp, spaceRight = 5.dp)
}
Text(
text = label.uppercase(),
style = MaterialTheme.typography.subtitle1.copy(fontSize = 12.sp, textAlign = TextAlign.End),
style = MaterialTheme.typography.subtitle1.copy(fontSize = 12.sp),
maxLines = 2,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.weight(1f)
)
if (helpMessage != null) {
IconPopup(modifier = Modifier.offset(y = (-3).dp), popupMessage = helpMessage, popupLink = helpLink, spaceLeft = 4.dp, spaceRight = 0.dp)
}
if (icon != null) {
Spacer(modifier = Modifier.width(4.dp))
Spacer(modifier = Modifier.width(3.dp))
Image(
painter = painterResource(id = icon),
colorFilter = ColorFilter.tint(iconTint),
contentDescription = null,
modifier = Modifier
.size(ButtonDefaults.IconSize)
.size(17.dp)
.offset(y = (-2).dp)
)
}
Expand Down Expand Up @@ -175,7 +176,7 @@ fun SplashClickableContent(
.offset(x = (-8).dp),
shape = RoundedCornerShape(12.dp)
) {
Column(modifier = Modifier.padding(8.dp)) {
Column(modifier = Modifier.padding(horizontal = 8.dp, vertical = 6.dp)) {
content()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import fr.acinq.bitcoin.Satoshi
import fr.acinq.lightning.blockchain.fee.FeeratePerByte
import fr.acinq.lightning.blockchain.fee.FeeratePerKw
import fr.acinq.lightning.channel.ChannelCommand
import fr.acinq.lightning.channel.ChannelFundingResponse
import fr.acinq.lightning.utils.msat
import fr.acinq.lightning.utils.sat
import fr.acinq.phoenix.managers.PeerManager
Expand All @@ -42,7 +43,7 @@ sealed class CpfpState {
data class Executing(val actualFeerate: FeeratePerKw) : CpfpState()
sealed class Complete : CpfpState() {
object Success: Complete()
data class Failed(val failure: ChannelCommand.Commitment.Splice.Response.Failure): Complete()
data class Failed(val failure: ChannelFundingResponse.Failure): Complete()
}
sealed class Error: CpfpState() {
data class Thrown(val e: Throwable): Error()
Expand Down Expand Up @@ -102,11 +103,11 @@ class CpfpViewModel(val peerManager: PeerManager) : ViewModel() {
log.info("failed to execute cpfp splice: assuming no channels")
state = CpfpState.Error.NoChannels
}
is ChannelCommand.Commitment.Splice.Response.Created -> {
is ChannelFundingResponse.Success -> {
log.info("successfully executed cpfp splice: $res")
state = CpfpState.Complete.Success
}
is ChannelCommand.Commitment.Splice.Response.Failure -> {
is ChannelFundingResponse.Failure -> {
log.info("failed to execute cpfp splice: $res")
state = CpfpState.Complete.Failed(res)
}
Expand Down
Loading

0 comments on commit 5fbe04e

Please sign in to comment.