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