refactor: extract Bip21Parser and PaymentRecord.fromPayment

This commit is contained in:
2026-06-06 16:29:43 +02:00
parent ca2273f3e4
commit f73f7f348f
3 changed files with 53 additions and 40 deletions
@@ -175,6 +175,32 @@ data class PaymentRecord(
val amountSat: Long get() = kotlin.math.abs(amountMsat) / 1000L
val feeSat: Long get() = kotlin.math.abs(feeMsat) / 1000L
val isOutgoing: Boolean get() = amountMsat < 0
companion object {
fun fromPayment(
paymentHash : String,
amountSats : Long,
feeSats : Long?,
bolt11 : String?,
memo : String?,
pubkey : String?,
alias : String?,
): PaymentRecord = PaymentRecord(
paymentHash = paymentHash,
checkingId = paymentHash,
amountMsat = -(amountSats * 1_000L),
feeMsat = (feeSats ?: 0L) * 1_000L,
memo = memo,
time = (System.currentTimeMillis() / 1_000L).toString(),
status = "complete",
bolt11 = bolt11,
pending = false,
preimage = null,
extra = null,
pubkey = pubkey,
alias = alias,
)
}
}
data class PaymentExtra(
@@ -13,6 +13,7 @@ import com.bitcointxoko.gudariwallet.data.WalletRepository
import com.bitcointxoko.gudariwallet.ui.SendState
import com.bitcointxoko.gudariwallet.ui.balance.BalanceViewModel
import com.bitcointxoko.gudariwallet.util.BiometricHelper
import com.bitcointxoko.gudariwallet.util.Bip21Parser
import com.bitcointxoko.gudariwallet.util.LnurlMetadataParser
import com.bitcointxoko.gudariwallet.util.RouteHintAnalyzer
import com.bitcointxoko.gudariwallet.util.SendInputDetector
@@ -163,7 +164,7 @@ class SendViewModel(
amountSats = amountSats,
feeSats = feeSats,
paymentHash = paymentHash,
pendingRecord = buildPendingRecord(paymentHash, amountSats, feeSats, bolt11, memo, pubkey, alias)
pendingRecord = PaymentRecord.fromPayment(paymentHash, amountSats, feeSats, bolt11, memo, pubkey, alias)
)
balanceVm.refreshBalance()
}
@@ -333,7 +334,7 @@ class SendViewModel(
// ── Scan handlers ────────────────────────────────────────────────────────
private fun handleBip21Scan(rawInput: String, strings: SendStrings) {
val params = parseBip21Params(rawInput)
val params = Bip21Parser.parseParams(rawInput)
val bolt11 = params["lightning"]
val lnurl = params["lnurl"] ?: params["lnurlp"]
when {
@@ -520,42 +521,4 @@ class SendViewModel(
}
}
}
private fun parseBip21Params(raw: String): Map<String, String> {
val query = raw.trim().substringAfter("?", missingDelimiterValue = "")
if (query.isBlank()) return emptyMap()
return query.split("&").mapNotNull { pair ->
val key = pair.substringBefore("=").takeIf { it.isNotBlank() } ?: return@mapNotNull null
val value = runCatching {
java.net.URLDecoder.decode(
pair.substringAfter("=", "").replace("+", " "), "UTF-8"
)
}.getOrDefault("")
key to value
}.toMap()
}
private fun buildPendingRecord(
paymentHash : String,
amountSats : Long,
feeSats : Long?,
bolt11 : String?,
memo : String?,
pubkey : String?,
alias : String?
): PaymentRecord = PaymentRecord(
paymentHash = paymentHash,
checkingId = paymentHash,
amountMsat = -(amountSats * 1_000L),
feeMsat = (feeSats ?: 0L) * 1_000L,
memo = memo,
time = (System.currentTimeMillis() / 1_000L).toString(),
status = "complete",
bolt11 = bolt11,
pending = false,
preimage = null,
extra = null,
pubkey = pubkey,
alias = alias
)
}
@@ -0,0 +1,24 @@
package com.bitcointxoko.gudariwallet.util
import android.net.Uri
object Bip21Parser {
/**
* Parses the query string from a BIP-21 URI.
* Input can be the full URI ("bitcoin:addr?amount=...") or just the query
* string ("amount=0.001&label=Foo"). Returns an empty map on malformed input.
*/
fun parseParams(raw: String): Map<String, String> {
val query = if ('?' in raw) raw.substringAfter('?') else raw
if (query.isBlank()) return emptyMap()
return query.split('&')
.mapNotNull { pair ->
val idx = pair.indexOf('=')
if (idx < 1) null
else pair.substring(0, idx) to
Uri.decode(pair.substring(idx + 1))
}
.toMap()
}
}