fix: send payment shows as failed even when succeeded
This commit is contained in:
Generated
+1
-1
@@ -4,7 +4,7 @@
|
||||
<selectionStates>
|
||||
<SelectionState runConfigName="app">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
<DropdownSelection timestamp="2026-05-31T17:55:52.851171Z">
|
||||
<DropdownSelection timestamp="2026-06-11T09:22:11.580091Z">
|
||||
<Target type="DEFAULT_BOOT">
|
||||
<handle>
|
||||
<DeviceId pluginId="PhysicalDevice" identifier="serial=48090DLAQ00119" />
|
||||
|
||||
Vendored
+7
-1
@@ -27,6 +27,7 @@
|
||||
# looked up by name at runtime via SerializersModule.
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
-keepattributes *Annotation*, InnerClasses
|
||||
-keep class kotlinx.serialization.SerializersKt { *; }
|
||||
-dontnote kotlinx.serialization.**
|
||||
-dontwarn kotlinx.serialization.**
|
||||
|
||||
@@ -51,10 +52,13 @@
|
||||
-keep,allowobfuscation,allowshrinking interface retrofit2.Call
|
||||
-keep,allowobfuscation,allowshrinking class retrofit2.Response
|
||||
-keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation
|
||||
-keep,allowobfuscation,allowshrinking class * extends kotlin.coroutines.CoroutineContext$Element { *; }
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# OkHttp 5.x / Okio
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
-keep class okhttp3.internal.publicsuffix.PublicSuffixDatabase { *; }
|
||||
-keepnames class okhttp3.** { *; }
|
||||
-dontwarn okhttp3.**
|
||||
-dontwarn okio.**
|
||||
-dontwarn javax.annotation.**
|
||||
@@ -101,8 +105,9 @@
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# Room 2.7.1
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
-keep class * extends androidx.room.RoomDatabase
|
||||
-keep @androidx.room.Entity class *
|
||||
-keep @androidx.room.Dao interface *
|
||||
-keep class * extends androidx.room.RoomDatabase { *; }
|
||||
-dontwarn androidx.room.**
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
@@ -124,6 +129,7 @@
|
||||
-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
|
||||
-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}
|
||||
-dontwarn kotlinx.coroutines.**
|
||||
-dontwarn kotlinx.coroutines.debug.*
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────
|
||||
# Lyricist 1.8.0
|
||||
|
||||
@@ -35,9 +35,9 @@ data class CreateInvoiceRequest(
|
||||
|
||||
@Serializable
|
||||
data class CreateInvoiceResponse(
|
||||
@SerialName("payment_hash") val paymentHash: String,
|
||||
@SerialName("payment_request") val paymentRequest: String,
|
||||
@SerialName("expiry") val expiry: String?
|
||||
@SerialName("payment_hash") val paymentHash: String = "",
|
||||
@SerialName("payment_request") val paymentRequest: String = "",
|
||||
@SerialName("expiry") val expiry: String? = null
|
||||
)
|
||||
|
||||
// ── Pay invoice ───────────────────────────────────────────────────────────────
|
||||
@@ -49,22 +49,22 @@ data class PayInvoiceRequest(
|
||||
|
||||
@Serializable
|
||||
data class PayInvoiceResponse(
|
||||
@SerialName("payment_hash") val paymentHash: String,
|
||||
@SerialName("checking_id") val checkingId: String
|
||||
@SerialName("payment_hash") val paymentHash: String = "",
|
||||
@SerialName("checking_id") val checkingId: String = ""
|
||||
)
|
||||
|
||||
// ── Check payment ─────────────────────────────────────────────────────────────
|
||||
@Serializable
|
||||
data class PaymentStatusResponse(
|
||||
val paid: Boolean,
|
||||
val paid: Boolean = false,
|
||||
val details: PaymentDetails? = null
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class PaymentDetails(
|
||||
val amount: Long?,
|
||||
val fee: Long?,
|
||||
val memo: String?
|
||||
val amount: Long? = null,
|
||||
val fee: Long? = null,
|
||||
val memo: String? = null
|
||||
)
|
||||
|
||||
// ── Decode BOLT-11 ────────────────────────────────────────────────────────────
|
||||
@@ -84,7 +84,7 @@ data class DecodeInvoiceResponse(
|
||||
|
||||
@Serializable
|
||||
data class RouteHintHop(
|
||||
@SerialName("public_key") val publicKey: String,
|
||||
@SerialName("public_key") val publicKey: String = "",
|
||||
@SerialName("short_channel_id") val shortChannelId: String? = null,
|
||||
@SerialName("base_fee") val baseFeeMsat: Long = 0,
|
||||
@SerialName("ppm_fee") val ppmFee: Long = 0,
|
||||
@@ -94,7 +94,7 @@ data class RouteHintHop(
|
||||
// ── LNURL scan ────────────────────────────────────────────────────────────────
|
||||
@Serializable
|
||||
data class LnurlScanResponse(
|
||||
val tag: String?,
|
||||
val tag: String? = null,
|
||||
// ── payRequest fields ─────────────────────────────────────────────────────
|
||||
val callback: String? = null,
|
||||
@SerialName("minSendable") val minSendable: Long? = null,
|
||||
@@ -121,7 +121,7 @@ data class LnurlScanResponse(
|
||||
// ── LNURL-pay callback response (LUD-06) ─────────────────────────────────────
|
||||
@Serializable
|
||||
data class LnurlCallbackResponse(
|
||||
val pr: String,
|
||||
val pr: String = "",
|
||||
val routes: List<JsonElement>? = null,
|
||||
@SerialName("successAction") val successAction: SuccessAction? = null,
|
||||
val status: String? = null,
|
||||
@@ -131,12 +131,12 @@ data class LnurlCallbackResponse(
|
||||
// ── LNURL pay ─────────────────────────────────────────────────────────────────
|
||||
@Serializable
|
||||
data class LnurlPayRes(
|
||||
val tag: String?,
|
||||
val callback: String?,
|
||||
@SerialName("minSendable") val minSendable: Long?,
|
||||
@SerialName("maxSendable") val maxSendable: Long?,
|
||||
val metadata: String?,
|
||||
@SerialName("commentAllowed") val commentAllowed: Int?,
|
||||
val tag: String? = null,
|
||||
val callback: String? = null,
|
||||
@SerialName("minSendable") val minSendable: Long? = null,
|
||||
@SerialName("maxSendable") val maxSendable: Long? = null,
|
||||
val metadata: String? = null,
|
||||
@SerialName("commentAllowed") val commentAllowed: Int? = null,
|
||||
@SerialName("allowsNostr") val allowsNostr: Boolean? = null,
|
||||
@SerialName("nostrPubkey") val nostrPubkey: String? = null
|
||||
)
|
||||
@@ -151,25 +151,25 @@ data class PayLnurlRequest(
|
||||
|
||||
@Serializable
|
||||
data class PayLnurlResponse(
|
||||
@SerialName("payment_hash") val paymentHash: String,
|
||||
@SerialName("checking_id") val checkingId: String
|
||||
@SerialName("payment_hash") val paymentHash: String = "",
|
||||
@SerialName("checking_id") val checkingId: String = ""
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class WithdrawCallbackResponse(
|
||||
val status: String,
|
||||
val status: String = "",
|
||||
val reason: String? = null
|
||||
)
|
||||
|
||||
// ── LNURLp pay link (lightning address) ──────────────────────────────────────
|
||||
@Serializable
|
||||
data class LnurlpLink(
|
||||
val id: String,
|
||||
val wallet: String,
|
||||
val username: String?, // the part before the @ in the lightning address
|
||||
val description: String?,
|
||||
@Serializable(with = LongAsDoubleSerializer::class) val min: Long,
|
||||
@Serializable(with = LongAsDoubleSerializer::class) val max: Long
|
||||
val id: String = "",
|
||||
val wallet: String = "",
|
||||
val username: String? = null,
|
||||
val description: String? = null,
|
||||
@Serializable(with = LongAsDoubleSerializer::class) val min: Long = 0L,
|
||||
@Serializable(with = LongAsDoubleSerializer::class) val max: Long = 0L
|
||||
)
|
||||
|
||||
// ── Payment history ───────────────────────────────────────────────────────────
|
||||
@@ -303,6 +303,7 @@ object SuccessActionSerializer : KSerializer<SuccessAction?> {
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class PaymentDetailResponse(
|
||||
val paid: Boolean,
|
||||
val details: PaymentRecord?
|
||||
@@ -311,30 +312,30 @@ data class PaymentDetailResponse(
|
||||
// ── WebSocket payment message ─────────────────────────────────────────────────
|
||||
@Serializable
|
||||
data class WsPaymentMessage(
|
||||
@SerialName("wallet_balance") val walletBalance: Long?,
|
||||
val payment: WsPayment?
|
||||
@SerialName("wallet_balance") val walletBalance: Long? = null,
|
||||
val payment: WsPayment? = null
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class WsPayment(
|
||||
@SerialName("payment_hash") val paymentHash: String,
|
||||
@SerialName("checking_id") val checkingId: String,
|
||||
@SerialName("amount") val amount: Long,
|
||||
@SerialName("fee") val fee: Long,
|
||||
@SerialName("memo") val memo: String?,
|
||||
@SerialName("time") val time: String,
|
||||
@SerialName("status") val status: String,
|
||||
@SerialName("bolt11") val bolt11: String?,
|
||||
@SerialName("pending") val pending: Boolean,
|
||||
@SerialName("preimage") val preimage: String?,
|
||||
@SerialName("extra") val extra: PaymentExtra?
|
||||
@SerialName("payment_hash") val paymentHash: String = "",
|
||||
@SerialName("checking_id") val checkingId: String = "",
|
||||
@SerialName("amount") val amount: Long = 0L,
|
||||
@SerialName("fee") val fee: Long = 0L,
|
||||
@SerialName("memo") val memo: String? = null,
|
||||
@SerialName("time") val time: String = "",
|
||||
@SerialName("status") val status: String = "",
|
||||
@SerialName("bolt11") val bolt11: String? = null,
|
||||
@SerialName("pending") val pending: Boolean = false,
|
||||
@SerialName("preimage") val preimage: String? = null,
|
||||
@SerialName("extra") val extra: PaymentExtra? = null
|
||||
)
|
||||
|
||||
// ── Fiat rate ─────────────────────────────────────────────────────────────────
|
||||
@Serializable
|
||||
data class FiatRateResponse(
|
||||
val rate: Double, // sat to fiat rate
|
||||
val price: Double // BTC price in the requested fiat currency
|
||||
val rate: Double = 0.0, // sat to fiat rate
|
||||
val price: Double = 0.0 // BTC price in the requested fiat currency
|
||||
)
|
||||
|
||||
// ── History sync ──────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -156,6 +156,17 @@ class SendViewModel(
|
||||
_sendState.value = SendState.Error(strings.paymentFailed)
|
||||
}
|
||||
}
|
||||
// hardening against a null detail
|
||||
detail == null -> {
|
||||
// Detail fetch failed entirely — treat as pending and poll once
|
||||
Timber.w("SEND [DETAIL NULL] polling as fallback")
|
||||
when (val result = poller.poll(paymentHash)) {
|
||||
is PaymentPoller.PollResult.Settled ->
|
||||
emitPaymentSent(paymentHash, amountSats, result.feeSats, bolt11, memo, pubkey, alias)
|
||||
else ->
|
||||
_sendState.value = SendState.Error(strings.paymentFailed)
|
||||
}
|
||||
}
|
||||
|
||||
// ── Failed or unknown
|
||||
else -> {
|
||||
|
||||
Reference in New Issue
Block a user