Skip to content

Commit 809ce2f

Browse files
authored
Merge pull request #275 from synonymdev/feat/vss-auth
LDK-node JWT auth to VSS rust
2 parents 1059c1b + 3ba17ad commit 809ce2f

File tree

8 files changed

+56
-35
lines changed

8 files changed

+56
-35
lines changed

app/src/main/java/to/bitkit/env/Env.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,15 @@ internal object Env {
4040
val vssServerUrl
4141
get() = when (network) {
4242
Network.BITCOIN -> TODO("VSS not implemented for mainnet")
43+
// Network.REGTEST -> "http://localhost:5050/vss"
4344
else -> "https://bitkit.stag0.blocktank.to/vss_rs/"
4445
}
4546

47+
val lnurlAuthSeverUrl = when (network) {
48+
// Network.REGTEST -> "http://localhost:3000/auth"
49+
else -> "" // TODO implement LNURL-auth Server for other networks
50+
}
51+
4652
val vssStoreId
4753
get() = when (network) {
4854
Network.REGTEST -> "bitkit_regtest"

app/src/main/java/to/bitkit/repositories/BlocktankRepo.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,8 @@ class BlocktankRepo @Inject constructor(
230230
receivingBalanceSats: ULong,
231231
channelExpiryWeeks: UInt = DEFAULT_CHANNEL_EXPIRY_WEEKS,
232232
): Result<IBtEstimateFeeResponse2> = withContext(bgDispatcher) {
233+
Logger.info("Estimating order fee for spendingSats=$spendingBalanceSats, receivingSats=$receivingBalanceSats")
234+
233235
try {
234236
val options = defaultCreateOrderOptions(clientBalanceSat = spendingBalanceSats)
235237

@@ -239,6 +241,8 @@ class BlocktankRepo @Inject constructor(
239241
options = options,
240242
)
241243

244+
Logger.debug("Estimated order fee: '$estimate'")
245+
242246
Result.success(estimate)
243247
} catch (e: Throwable) {
244248
Logger.error("Failed to estimate order fee", e, context = TAG)

app/src/main/java/to/bitkit/repositories/WalletRepo.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -322,10 +322,8 @@ class WalletRepo @Inject constructor(
322322
}
323323

324324
try {
325-
val minFeeBuffer = 1000uL
326-
val amountSats = (totalOnchainSats - minFeeBuffer).coerceAtLeast(0uL)
327-
val fee = lightningRepo.calculateTotalFee(amountSats).getOrThrow()
328-
val maxSendable = (totalOnchainSats - fee).coerceAtLeast(0uL)
325+
val fee = lightningRepo.calculateTotalFee(totalOnchainSats).getOrThrow()
326+
val maxSendable = (totalOnchainSats - fee).coerceAtLeast(0u)
329327

330328
return@withContext maxSendable
331329
} catch (_: Throwable) {

app/src/main/java/to/bitkit/services/LightningService.kt

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,20 @@ class LightningService @Inject constructor(
113113

114114
ServiceQueue.LDK.background {
115115
node = try {
116-
builder.buildWithVssStoreAndFixedHeaders(
117-
vssUrl = Env.vssServerUrl,
118-
storeId = vssStoreId,
119-
fixedHeaders = emptyMap(),
120-
)
116+
if (Env.lnurlAuthSeverUrl.isNotBlank()) {
117+
builder.buildWithVssStore(
118+
vssUrl = Env.vssServerUrl,
119+
storeId = vssStoreId,
120+
lnurlAuthServerUrl = Env.lnurlAuthSeverUrl,
121+
fixedHeaders = emptyMap(),
122+
)
123+
} else {
124+
builder.buildWithVssStoreAndFixedHeaders(
125+
vssUrl = Env.vssServerUrl,
126+
storeId = vssStoreId,
127+
fixedHeaders = emptyMap(),
128+
)
129+
}
121130
} catch (e: BuildException) {
122131
throw LdkError(e)
123132
}

app/src/main/java/to/bitkit/ui/components/Spacers.kt

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,20 @@
11
package to.bitkit.ui.components
22

33
import androidx.annotation.FloatRange
4-
import androidx.compose.foundation.background
54
import androidx.compose.foundation.layout.ColumnScope
65
import androidx.compose.foundation.layout.RowScope
76
import androidx.compose.foundation.layout.Spacer
87
import androidx.compose.foundation.layout.WindowInsets
98
import androidx.compose.foundation.layout.asPaddingValues
10-
import androidx.compose.foundation.layout.fillMaxWidth
119
import androidx.compose.foundation.layout.height
1210
import androidx.compose.foundation.layout.statusBars
1311
import androidx.compose.foundation.layout.width
1412
import androidx.compose.material3.ExperimentalMaterial3Api
1513
import androidx.compose.material3.TopAppBarDefaults
1614
import androidx.compose.runtime.Composable
1715
import androidx.compose.ui.Modifier
18-
import androidx.compose.ui.platform.LocalDensity
1916
import androidx.compose.ui.unit.Dp
2017
import androidx.compose.ui.unit.dp
21-
import to.bitkit.ui.theme.Colors
2218

2319
@Composable
2420
fun VerticalSpacer(height: Dp) {
@@ -30,19 +26,25 @@ fun HorizontalSpacer(width: Dp) {
3026
Spacer(modifier = Modifier.width(width))
3127
}
3228

29+
@Suppress("ComposeMultipleContentEmitters")
3330
@Composable
3431
fun ColumnScope.FillHeight(
3532
@FloatRange weight: Float = 1f,
36-
fill: Boolean = true
33+
fill: Boolean = true,
34+
min: Dp = 0.dp,
3735
) {
36+
if (min > 0.dp) Spacer(modifier = Modifier.height(min))
3837
Spacer(modifier = Modifier.weight(weight, fill = fill))
3938
}
4039

40+
@Suppress("ComposeMultipleContentEmitters")
4141
@Composable
4242
fun RowScope.FillWidth(
4343
@FloatRange weight: Float = 1f,
44-
fill: Boolean = true
44+
fill: Boolean = true,
45+
min: Dp = 0.dp,
4546
) {
47+
if (min > 0.dp) Spacer(modifier = Modifier.width(min))
4648
Spacer(modifier = Modifier.weight(weight, fill = fill))
4749
}
4850

app/src/main/java/to/bitkit/ui/screens/transfer/external/LnurlChannelScreen.kt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,21 @@ import androidx.compose.runtime.getValue
1515
import androidx.compose.ui.Alignment
1616
import androidx.compose.ui.Modifier
1717
import androidx.compose.ui.res.stringResource
18+
import androidx.compose.ui.text.style.TextAlign
19+
import androidx.compose.ui.text.style.TextOverflow
1820
import androidx.compose.ui.tooling.preview.Preview
1921
import androidx.compose.ui.unit.dp
2022
import androidx.hilt.navigation.compose.hiltViewModel
2123
import androidx.lifecycle.compose.collectAsStateWithLifecycle
2224
import to.bitkit.R
23-
import to.bitkit.ext.ellipsisMiddle
2425
import to.bitkit.models.LnPeer
2526
import to.bitkit.ui.Routes
2627
import to.bitkit.ui.components.BodyM
2728
import to.bitkit.ui.components.Caption13Up
2829
import to.bitkit.ui.components.CaptionB
2930
import to.bitkit.ui.components.Display
3031
import to.bitkit.ui.components.FillHeight
32+
import to.bitkit.ui.components.FillWidth
3133
import to.bitkit.ui.components.PrimaryButton
3234
import to.bitkit.ui.components.SecondaryButton
3335
import to.bitkit.ui.components.VerticalSpacer
@@ -93,7 +95,7 @@ private fun Content(
9395
VerticalSpacer(8.dp)
9496

9597
val peer = uiState.peer
96-
if(peer != null) {
98+
if (peer != null) {
9799
BodyM(text = stringResource(R.string.other__lnurl_channel_message), color = Colors.White64)
98100
VerticalSpacer(48.dp)
99101

@@ -102,7 +104,7 @@ private fun Content(
102104

103105
InfoRow(
104106
label = stringResource(R.string.other__lnurl_channel_node),
105-
value = peer.nodeId.ellipsisMiddle(24),
107+
value = peer.nodeId,
106108
)
107109
InfoRow(
108110
label = stringResource(R.string.other__lnurl_channel_host),
@@ -151,14 +153,14 @@ private fun InfoRow(
151153
value: String,
152154
) {
153155
Row(
154-
horizontalArrangement = Arrangement.SpaceBetween,
155156
verticalAlignment = Alignment.CenterVertically,
156157
modifier = Modifier
157158
.fillMaxWidth()
158159
.padding(vertical = 16.dp)
159160
) {
160161
CaptionB(text = label)
161-
CaptionB(text = value)
162+
FillWidth(min = 24.dp)
163+
CaptionB(text = value, maxLines = 1, overflow = TextOverflow.MiddleEllipsis, textAlign = TextAlign.End)
162164
}
163165
HorizontalDivider()
164166
}

app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ class AppViewModel @Inject constructor(
8686
@ApplicationContext private val context: Context,
8787
@BgDispatcher private val bgDispatcher: CoroutineDispatcher,
8888
private val keychain: Keychain,
89-
private val lightningService: LightningRepo,
89+
private val lightningRepo: LightningRepo,
9090
private val walletRepo: WalletRepo,
9191
private val coreService: CoreService,
9292
private val ldkNodeEventBus: LdkNodeEventBus,
@@ -200,7 +200,7 @@ class AppViewModel @Inject constructor(
200200

201201
is Event.ChannelReady -> {
202202
// TODO: handle ONLY cjit as payment received. This makes it look like any channel confirmed is a received payment.
203-
val channel = lightningService.getChannels()?.find { it.channelId == event.channelId }
203+
val channel = lightningRepo.getChannels()?.find { it.channelId == event.channelId }
204204
if (channel != null) {
205205
showNewTransactionSheet(
206206
NewTransactionSheetDetails(
@@ -403,12 +403,12 @@ class AppViewModel @Inject constructor(
403403
val lnurl = _sendUiState.value.lnurl
404404

405405
val isValidLNAmount = when (lnurl) {
406-
null -> lightningService.canSend(amount)
406+
null -> lightningRepo.canSend(amount)
407407
is LnurlParams.LnurlPay -> {
408408
val minSat = lnurl.data.minSendableSat()
409409
val maxSat = lnurl.data.maxSendableSat()
410410

411-
amount in minSat..maxSat && lightningService.canSend(amount)
411+
amount in minSat..maxSat && lightningRepo.canSend(amount)
412412
}
413413

414414
is LnurlParams.LnurlWithdraw -> {
@@ -531,7 +531,7 @@ class AppViewModel @Inject constructor(
531531
val quickPayHandled = handleQuickPayIfApplicable(amountSats = invoice.amountSatoshis, invoice = invoice)
532532
if (quickPayHandled) return
533533

534-
if (!lightningService.canSend(invoice.amountSatoshis)) {
534+
if (!lightningRepo.canSend(invoice.amountSatoshis)) {
535535
toast(
536536
type = Toast.ToastType.ERROR,
537537
title = "Insufficient Funds",
@@ -574,7 +574,7 @@ class AppViewModel @Inject constructor(
574574
val minSendable = data.minSendableSat()
575575
val maxSendable = data.maxSendableSat()
576576

577-
if (!lightningService.canSend(minSendable)) {
577+
if (!lightningRepo.canSend(minSendable)) {
578578
toast(
579579
type = Toast.ToastType.WARNING,
580580
title = context.getString(R.string.other__lnurl_pay_error),
@@ -662,7 +662,7 @@ class AppViewModel @Inject constructor(
662662
fun requestLnurlAuth(callback: String, k1: String, domain: String) {
663663
viewModelScope.launch {
664664
// TODO pass callback and domain from bitkit-core when updated to accept decoded callback and return domain
665-
lightningService.requestLnurlAuth(
665+
lightningRepo.requestLnurlAuth(
666666
callback = callback,
667667
k1 = k1,
668668
domain = domain,
@@ -803,7 +803,7 @@ class AppViewModel @Inject constructor(
803803

804804
if (_sendUiState.value.payMethod != SendMethod.ONCHAIN) return
805805

806-
val totalFee = lightningService.calculateTotalFee(
806+
val totalFee = lightningRepo.calculateTotalFee(
807807
amountSats = amountSats,
808808
address = _sendUiState.value.address,
809809
speed = _sendUiState.value.speed,
@@ -841,7 +841,7 @@ class AppViewModel @Inject constructor(
841841
val isLnurlPay = lnurl is LnurlParams.LnurlPay
842842

843843
if (isLnurlPay) {
844-
lightningService.fetchLnurlInvoice(
844+
lightningRepo.fetchLnurlInvoice(
845845
callbackUrl = lnurl.data.callback,
846846
amountSats = amount,
847847
comment = _sendUiState.value.comment.takeIf { it.isNotEmpty() },
@@ -942,7 +942,7 @@ class AppViewModel @Inject constructor(
942942
)
943943
}
944944

945-
val invoice = lightningService.createInvoice(
945+
val invoice = lightningRepo.createInvoice(
946946
amountSats = _sendUiState.value.amount,
947947
description = lnurl.data.defaultDescription,
948948
expirySeconds = 3600u,
@@ -954,7 +954,7 @@ class AppViewModel @Inject constructor(
954954
return@launch
955955
}
956956

957-
lightningService.requestLnurlWithdraw(
957+
lightningRepo.requestLnurlWithdraw(
958958
k1 = lnurl.data.k1,
959959
callback = lnurl.data.callback,
960960
paymentRequest = invoice
@@ -994,7 +994,7 @@ class AppViewModel @Inject constructor(
994994

995995
private suspend fun sendOnchain(address: String, amount: ULong): Result<Txid> {
996996
val utxos = _sendUiState.value.selectedUtxos
997-
return lightningService.sendOnChain(
997+
return lightningRepo.sendOnChain(
998998
address = address,
999999
sats = amount,
10001000
utxosToSpend = utxos,
@@ -1005,7 +1005,7 @@ class AppViewModel @Inject constructor(
10051005
bolt11: String,
10061006
amount: ULong? = null,
10071007
): Result<PaymentId> {
1008-
return lightningService.payInvoice(bolt11 = bolt11, sats = amount).onSuccess { hash ->
1008+
return lightningRepo.payInvoice(bolt11 = bolt11, sats = amount).onSuccess { hash ->
10091009
// Wait until matching payment event is received
10101010
val result = ldkNodeEventBus.events.watchUntil { event ->
10111011
when (event) {

gradle/libs.versions.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[versions]
22
accompanistPermissions = "0.36.0"
33
activityCompose = "1.10.1"
4-
agp = "8.11.1"
4+
agp = "8.12.0"
55
appcompat = "1.7.0"
66
barcodeScanning = "17.3.0"
77
biometric = "1.4.0-alpha02"
@@ -86,7 +86,7 @@ ktor-client-logging = { module = "io.ktor:ktor-client-logging", version.ref = "k
8686
ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" }
8787
ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" }
8888
#ldk-node-android = { module = "org.lightningdevkit:ldk-node-android", version = "0.6.1" } # upstream
89-
ldk-node-android = { module = "com.github.synonymdev:ldk-node", version = "v0.6.1-rc.4" } # fork
89+
ldk-node-android = { module = "com.github.synonymdev:ldk-node", version = "v0.6.1-rc.5" } # fork
9090
lifecycle-process = { group = "androidx.lifecycle", name = "lifecycle-process", version.ref = "lifecycle" }
9191
lifecycle-runtime-compose = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "lifecycle" }
9292
lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycle" }

0 commit comments

Comments
 (0)