@@ -13,21 +13,27 @@ import kotlinx.coroutines.flow.asStateFlow
1313import kotlinx.coroutines.flow.update
1414import kotlinx.coroutines.launch
1515import to.bitkit.di.BgDispatcher
16+ import to.bitkit.ext.callbackAmountMsats
1617import to.bitkit.ext.getClipboardText
1718import to.bitkit.ext.maxSendableSat
1819import to.bitkit.ext.minSendableSat
20+ import to.bitkit.ext.nowMs
21+ import to.bitkit.ext.runSuspendCatching
1922import to.bitkit.ext.totalNextOutboundHtlcLimitSats
2023import to.bitkit.models.BITCOIN_SYMBOL
2124import to.bitkit.models.Toast
22- import to.bitkit.models.satsToMsat
2325import to.bitkit.repositories.LightningRepo
26+ import to.bitkit.repositories.LnurlPayInvoiceMismatchError
2427import to.bitkit.repositories.ProbeError
2528import to.bitkit.repositories.ProbeOutcome
2629import to.bitkit.services.CoreService
2730import to.bitkit.ui.shared.toast.ToastEventBus
2831import to.bitkit.utils.Logger
2932import javax.inject.Inject
33+ import kotlin.time.Clock
34+ import kotlin.time.ExperimentalTime
3035
36+ @OptIn(ExperimentalTime ::class )
3137@HiltViewModel
3238class ProbingToolViewModel @Inject constructor(
3339 @ApplicationContext private val context : Context ,
@@ -77,6 +83,7 @@ class ProbingToolViewModel @Inject constructor(
7783
7884 viewModelScope.launch(bgDispatcher) {
7985 _uiState .update { it.copy(isLoading = true , probeResult = null ) }
86+ val startTime = Clock .System .nowMs()
8087
8188 try {
8289 val state = _uiState .value
@@ -145,7 +152,6 @@ class ProbingToolViewModel @Inject constructor(
145152 }
146153 }
147154
148- val startTime = System .currentTimeMillis()
149155 val dispatch = if (isNodeIdTarget) {
150156 lightningRepo.sendProbeForNode(requireNotNull(nodeId), requireNotNull(amountSats))
151157 } else {
@@ -159,6 +165,8 @@ class ProbingToolViewModel @Inject constructor(
159165 .onFailure { handleProbeFailure(startTime, it) }
160166 }
161167 .onFailure { handleProbeFailure(startTime, it) }
168+ } catch (error: LnurlPayInvoiceMismatchError ) {
169+ handleProbeFailure(startTime, error)
162170 } finally {
163171 _uiState .update { it.copy(isLoading = false ) }
164172 }
@@ -221,30 +229,38 @@ class ProbingToolViewModel @Inject constructor(
221229 return lightning?.invoice?.amountSatoshis == 0uL
222230 }
223231
224- private suspend fun extractBolt11Invoice (input : String , amountSats : ULong? ): String? = runCatching {
225- when (val decoded = coreService.decode(input)) {
226- is Scanner .Lightning -> decoded.invoice.bolt11
227- is Scanner .OnChain -> {
228- val lightningParam = decoded.invoice.params?.get(" lightning" ) ? : return @runCatching null
229- (coreService.decode(lightningParam) as ? Scanner .Lightning )?.invoice?.bolt11
230- }
232+ private suspend fun extractBolt11Invoice (input : String , amountSats : ULong? ): String? {
233+ return runSuspendCatching {
234+ when (val decoded = coreService.decode(input)) {
235+ is Scanner .Lightning -> decoded.invoice.bolt11
236+ is Scanner .OnChain -> {
237+ val lightningParam = decoded.invoice.params?.get(" lightning" ) ? : return @runSuspendCatching null
238+ (coreService.decode(lightningParam) as ? Scanner .Lightning )?.invoice?.bolt11
239+ }
231240
232- is Scanner .LnurlPay -> {
233- val amount = amountSats ? : return @runCatching null
234- lightningRepo.fetchLnurlInvoice(decoded.data.callback, satsToMsat(amount)).getOrThrow().bolt11
235- }
241+ is Scanner .LnurlPay -> {
242+ val amount = amountSats ? : return @runSuspendCatching null
243+ lightningRepo.fetchLnurlInvoice(
244+ data = decoded.data,
245+ amountMsats = decoded.data.callbackAmountMsats(amount),
246+ ).getOrThrow().bolt11
247+ }
236248
237- else -> null
249+ else -> null
250+ }
251+ }.getOrElse {
252+ if (it is LnurlPayInvoiceMismatchError ) throw it
253+ null
238254 }
239- }.getOrNull()
255+ }
240256
241257 private suspend fun handleProbeOutcome (
242258 startTime : Long ,
243259 outcome : ProbeOutcome ,
244260 invoice : String? ,
245261 amountSats : ULong? ,
246262 ) {
247- val durationMs = System .currentTimeMillis () - startTime
263+ val durationMs = Clock . System .nowMs () - startTime
248264 when (outcome) {
249265 is ProbeOutcome .Success -> {
250266 Logger .info(
@@ -288,7 +304,7 @@ class ProbingToolViewModel @Inject constructor(
288304 }
289305
290306 private suspend fun handleProbeFailure (startTime : Long , error : Throwable ) {
291- val durationMs = System .currentTimeMillis () - startTime
307+ val durationMs = Clock . System .nowMs () - startTime
292308 Logger .error(" Failed probe in '${durationMs} ms'" , error, context = TAG )
293309
294310 val friendlyMessage = getFriendlyErrorMessage(error)
0 commit comments