Skip to content

Commit fbf58cb

Browse files
committed
Merge branch 'master' into fix/transfer-watch-pooling
# Conflicts: # app/src/main/java/to/bitkit/repositories/BlocktankRepo.kt
2 parents 4a077e6 + bc9f14c commit fbf58cb

35 files changed

+897
-236
lines changed

app/detekt-baseline.xml

Lines changed: 7 additions & 47 deletions
Large diffs are not rendered by default.

app/src/main/java/to/bitkit/data/BlocktankHttpClient.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class BlocktankHttpClient @Inject constructor(
1616
) {
1717
suspend fun fetchLatestRates(): FxRateResponse {
1818
val response = client.get(Env.btcRatesServer)
19-
Logger.debug("Http call: $response")
19+
Logger.verbose("Http call: $response")
2020

2121
return when (response.status.isSuccess()) {
2222
true -> response.body()

app/src/main/java/to/bitkit/data/SettingsStore.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ data class SettingsData(
7070
val primaryDisplay: PrimaryDisplay = PrimaryDisplay.BITCOIN,
7171
val displayUnit: BitcoinDisplayUnit = BitcoinDisplayUnit.MODERN,
7272
val selectedCurrency: String = "USD",
73-
val defaultTransactionSpeed: TransactionSpeed = TransactionSpeed.Medium,
73+
val defaultTransactionSpeed: TransactionSpeed = TransactionSpeed.default(),
7474
val showEmptyBalanceView: Boolean = true,
7575
val hasSeenSpendingIntro: Boolean = false,
7676
val hasSeenWidgetsIntro: Boolean = false,

app/src/main/java/to/bitkit/data/backup/VssBackupClient.kt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class VssBackupClient @Inject constructor(
2525
suspend fun setup() = withContext(bgDispatcher) {
2626
try {
2727
withTimeout(30.seconds) {
28-
Logger.debug("VSS client setting up…", context = TAG)
28+
Logger.verbose("VSS client setting up…", context = TAG)
2929
vssNewClient(
3030
baseUrl = Env.vssServerUrl,
3131
storeId = vssStoreIdProvider.getVssStoreId(),
@@ -44,34 +44,34 @@ class VssBackupClient @Inject constructor(
4444
data: ByteArray,
4545
): Result<VssItem> = withContext(bgDispatcher) {
4646
isSetup.await()
47-
Logger.debug("VSS 'putObject' call for '$key'", context = TAG)
47+
Logger.verbose("VSS 'putObject' call for '$key'", context = TAG)
4848
runCatching {
4949
vssStore(
5050
key = key,
5151
value = data,
5252
)
5353
}.onSuccess {
54-
Logger.debug("VSS 'putObject' success for '$key' at version: ${it.version}", context = TAG)
54+
Logger.verbose("VSS 'putObject' success for '$key' at version: ${it.version}", context = TAG)
5555
}.onFailure { e ->
56-
Logger.error("VSS 'putObject' error for '$key'", e = e, context = TAG)
56+
Logger.verbose("VSS 'putObject' error for '$key'", e = e, context = TAG)
5757
}
5858
}
5959

6060
suspend fun getObject(key: String): Result<VssItem?> = withContext(bgDispatcher) {
6161
isSetup.await()
62-
Logger.debug("VSS 'getObject' call for '$key'", context = TAG)
62+
Logger.verbose("VSS 'getObject' call for '$key'", context = TAG)
6363
runCatching {
6464
vssGet(
6565
key = key,
6666
)
6767
}.onSuccess {
6868
if (it == null) {
69-
Logger.warn("VSS 'getObject' success null for '$key'", context = TAG)
69+
Logger.verbose("VSS 'getObject' success null for '$key'", context = TAG)
7070
} else {
71-
Logger.debug("VSS 'getObject' success for '$key'", context = TAG)
71+
Logger.verbose("VSS 'getObject' success for '$key'", context = TAG)
7272
}
7373
}.onFailure { e ->
74-
Logger.error("VSS 'getObject' error for '$key'", e = e, context = TAG)
74+
Logger.verbose("VSS 'getObject' error for '$key'", e = e, context = TAG)
7575
}
7676
}
7777

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package to.bitkit.models
2+
3+
import androidx.annotation.DrawableRes
4+
import androidx.annotation.StringRes
5+
import androidx.compose.ui.graphics.Color
6+
import to.bitkit.R
7+
import to.bitkit.ui.theme.Colors
8+
9+
enum class FeeRate(
10+
@StringRes val title: Int,
11+
@StringRes val description: Int,
12+
@DrawableRes val icon: Int,
13+
val color: Color,
14+
) {
15+
FAST(
16+
title = R.string.fee__fast__title,
17+
description = R.string.fee__fast__description,
18+
color = Colors.Brand,
19+
icon = R.drawable.ic_speed_fast,
20+
),
21+
NORMAL(
22+
title = R.string.fee__normal__title,
23+
description = R.string.fee__normal__description,
24+
color = Colors.Brand,
25+
icon = R.drawable.ic_speed_normal,
26+
),
27+
SLOW(
28+
title = R.string.fee__slow__title,
29+
description = R.string.fee__slow__description,
30+
color = Colors.Brand,
31+
icon = R.drawable.ic_speed_slow,
32+
),
33+
CUSTOM(
34+
title = R.string.fee__custom__title,
35+
description = R.string.fee__custom__description,
36+
color = Colors.White64,
37+
icon = R.drawable.ic_settings,
38+
);
39+
40+
fun toSpeed(): TransactionSpeed {
41+
return when (this) {
42+
FAST -> TransactionSpeed.Fast
43+
NORMAL -> TransactionSpeed.Medium
44+
SLOW -> TransactionSpeed.Slow
45+
CUSTOM -> TransactionSpeed.Custom(0u)
46+
}
47+
}
48+
49+
companion object {
50+
fun fromSpeed(speed: TransactionSpeed): FeeRate {
51+
return when (speed) {
52+
is TransactionSpeed.Fast -> FAST
53+
is TransactionSpeed.Medium -> NORMAL
54+
is TransactionSpeed.Slow -> SLOW
55+
is TransactionSpeed.Custom -> CUSTOM
56+
}
57+
}
58+
}
59+
}

app/src/main/java/to/bitkit/models/TransactionSpeed.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ sealed class TransactionSpeed {
2626
}
2727

2828
companion object {
29+
fun default(): TransactionSpeed = Medium
30+
2931
fun fromString(value: String): TransactionSpeed = when {
3032
value == "fast" -> Fast
3133
value == "medium" -> Medium

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,15 +153,15 @@ class BackupRepo @Inject constructor(
153153
cacheStore.updateBackupStatus(category) {
154154
it.copy(required = System.currentTimeMillis())
155155
}
156-
Logger.debug("Marked backup required for: '$category'", context = TAG)
156+
Logger.verbose("Marked backup required for: '$category'", context = TAG)
157157
}
158158
}
159159

160160
private fun scheduleBackup(category: BackupCategory) {
161161
// Cancel existing backup job for this category
162162
backupJobs[category]?.cancel()
163163

164-
Logger.debug("Scheduling backup for: '$category'", context = TAG)
164+
Logger.verbose("Scheduling backup for: '$category'", context = TAG)
165165

166166
backupJobs[category] = scope.launch {
167167
delay(BACKUP_DEBOUNCE)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ class BlocktankRepo @Inject constructor(
117117
isRefreshing = true
118118

119119
try {
120-
Logger.debug("Refreshing blocktank orders…", context = TAG)
120+
Logger.verbose("Refreshing blocktank orders…", context = TAG)
121121

122122
val paidOrderIds = cacheStore.data.first().paidOrders.keys
123123

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

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package to.bitkit.repositories
22

33
import com.google.firebase.messaging.FirebaseMessaging
4+
import com.synonym.bitkitcore.FeeRates
45
import com.synonym.bitkitcore.LightningInvoice
56
import com.synonym.bitkitcore.Scanner
67
import com.synonym.bitkitcore.createWithdrawCallbackUrl
@@ -87,7 +88,7 @@ class LightningRepo @Inject constructor(
8788
waitTimeout: Duration = 1.minutes,
8889
operation: suspend () -> Result<T>,
8990
): Result<T> = withContext(bgDispatcher) {
90-
Logger.debug("Operation called: $operationName", context = TAG)
91+
Logger.verbose("Operation called: $operationName", context = TAG)
9192

9293
if (_lightningState.value.nodeLifecycleState.isRunning()) {
9394
return@withContext executeOperation(operationName, operation)
@@ -106,7 +107,7 @@ class LightningRepo @Inject constructor(
106107
}
107108

108109
// Otherwise, wait for it to transition to running state
109-
Logger.debug("Waiting for node runs to execute $operationName", context = TAG)
110+
Logger.verbose("Waiting for node runs to execute $operationName", context = TAG)
110111
_lightningState.first { it.nodeLifecycleState.isRunning() }
111112
Logger.debug("Operation executed: $operationName", context = TAG)
112113
true
@@ -480,28 +481,18 @@ class LightningRepo @Inject constructor(
480481
Result.success(paymentId)
481482
}
482483

483-
/**
484-
* Sends bitcoin to an on-chain address
485-
*
486-
* @param address The bitcoin address to send to
487-
* @param sats The amount in satoshis to send
488-
* @param speed The desired transaction speed determining the fee rate. If null, the user's default speed is used.
489-
* @param utxosToSpend Manually specify UTXO's to spend if not null.
490-
* @return A `Result` with the `Txid` of sent transaction, or an error if the transaction fails
491-
* or the fee rate cannot be retrieved.
492-
*/
493-
494484
suspend fun sendOnChain(
495485
address: Address,
496486
sats: ULong,
497487
speed: TransactionSpeed? = null,
498488
utxosToSpend: List<SpendableUtxo>? = null,
489+
feeRates: FeeRates? = null,
499490
isTransfer: Boolean = false,
500491
channelId: String? = null,
501492
): Result<Txid> =
502493
executeWhenNodeRunning("Send on-chain") {
503494
val transactionSpeed = speed ?: settingsStore.data.first().defaultTransactionSpeed
504-
val satsPerVByte = getFeeRateForSpeed(transactionSpeed).getOrThrow().toUInt()
495+
val satsPerVByte = getFeeRateForSpeed(transactionSpeed, feeRates).getOrThrow().toUInt()
505496

506497
// if utxos are manually specified, use them, otherwise run auto coin select if enabled
507498
val finalUtxosToSpend = utxosToSpend ?: determineUtxosToSpend(
@@ -531,33 +522,35 @@ class LightningRepo @Inject constructor(
531522
Result.success(txId)
532523
}
533524

534-
private suspend fun determineUtxosToSpend(
525+
suspend fun determineUtxosToSpend(
535526
sats: ULong,
536527
satsPerVByte: UInt,
537-
): List<SpendableUtxo>? {
538-
return runCatching {
528+
): List<SpendableUtxo>? = withContext(bgDispatcher) {
529+
return@withContext runCatching {
539530
val settings = settingsStore.data.first()
540531
if (settings.coinSelectAuto) {
541532
val coinSelectionPreference = settings.coinSelectPreference
542533

543534
val allSpendableUtxos = lightningService.listSpendableOutputs().getOrThrow()
544535

545536
if (coinSelectionPreference == CoinSelectionPreference.Consolidate) {
546-
Logger.info("Consolidating by spending all ${allSpendableUtxos.size} UTXOs", context = TAG)
547-
return allSpendableUtxos
537+
Logger.debug("Consolidating by spending all ${allSpendableUtxos.size} UTXOs", context = TAG)
538+
return@withContext allSpendableUtxos
548539
}
549540

550541
val coinSelectionAlgorithm = coinSelectionPreference.toCoinSelectAlgorithm().getOrThrow()
551542

552-
Logger.info("Selecting UTXOs with algorithm: $coinSelectionAlgorithm for sats: $sats", context = TAG)
553-
Logger.debug("All spendable UTXOs: $allSpendableUtxos", context = TAG)
543+
Logger.debug("Selecting UTXOs with algorithm: $coinSelectionAlgorithm for sats: $sats", context = TAG)
544+
Logger.verbose("All spendable UTXOs: $allSpendableUtxos", context = TAG)
554545

555546
lightningService.selectUtxosWithAlgorithm(
556547
targetAmountSats = sats,
557548
algorithm = coinSelectionAlgorithm,
558549
satsPerVByte = satsPerVByte,
559550
utxos = allSpendableUtxos,
560-
).getOrThrow()
551+
).onSuccess {
552+
Logger.debug("Selected ${it.size} UTXOs", context = TAG)
553+
}.getOrThrow()
561554
} else {
562555
null // let ldk-node handle utxos
563556
}
@@ -579,10 +572,11 @@ class LightningRepo @Inject constructor(
579572
address: Address? = null,
580573
speed: TransactionSpeed? = null,
581574
utxosToSpend: List<SpendableUtxo>? = null,
575+
feeRates: FeeRates? = null,
582576
): Result<ULong> = withContext(bgDispatcher) {
583577
return@withContext try {
584578
val transactionSpeed = speed ?: settingsStore.data.first().defaultTransactionSpeed
585-
val satsPerVByte = getFeeRateForSpeed(transactionSpeed).getOrThrow().toUInt()
579+
val satsPerVByte = getFeeRateForSpeed(transactionSpeed, feeRates).getOrThrow().toUInt()
586580

587581
val addressOrDefault = address ?: cacheStore.data.first().onchainAddress
588582

@@ -600,9 +594,12 @@ class LightningRepo @Inject constructor(
600594
}
601595
}
602596

603-
suspend fun getFeeRateForSpeed(speed: TransactionSpeed): Result<ULong> = withContext(bgDispatcher) {
597+
suspend fun getFeeRateForSpeed(
598+
speed: TransactionSpeed,
599+
feeRates: FeeRates? = null,
600+
): Result<ULong> = withContext(bgDispatcher) {
604601
return@withContext runCatching {
605-
val fees = coreService.blocktank.getFees().getOrThrow()
602+
val fees = feeRates ?: coreService.blocktank.getFees().getOrThrow()
606603
val satsPerVByte = fees.getSatsPerVByteFor(speed)
607604
satsPerVByte.toULong()
608605
}.onFailure { e ->

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ class WalletRepo @Inject constructor(
146146
}
147147

148148
suspend fun syncNodeAndWallet(): Result<Unit> = withContext(bgDispatcher) {
149-
Logger.debug("Refreshing node and wallet state…")
149+
Logger.verbose("Refreshing node and wallet state…")
150150
syncBalances()
151151
lightningRepo.sync().onSuccess {
152152
syncBalances()

0 commit comments

Comments
 (0)