-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathLnurlService.kt
More file actions
114 lines (94 loc) · 3.62 KB
/
LnurlService.kt
File metadata and controls
114 lines (94 loc) · 3.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package to.bitkit.services
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.request.get
import io.ktor.client.statement.HttpResponse
import io.ktor.http.isSuccess
import kotlinx.serialization.Serializable
import to.bitkit.utils.AppError
import to.bitkit.utils.HttpError
import to.bitkit.utils.Logger
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class LnurlService @Inject constructor(
private val client: HttpClient,
) {
suspend fun requestLnurlWithdraw(callbackUrl: String): Result<LnurlWithdrawResponse> = runCatching {
Logger.debug("Requesting LNURL withdraw via: '$callbackUrl'", context = TAG)
val response: HttpResponse = client.get(callbackUrl)
Logger.debug("Http call: $response", context = TAG)
if (!response.status.isSuccess()) {
throw HttpError("requestLnurlWithdraw error: '${response.status.description}'", response.status.value)
}
val withdrawResponse = response.body<LnurlWithdrawResponse>()
when {
withdrawResponse.status == "ERROR" -> {
throw AppError("requestLnurlWithdraw error: ${withdrawResponse.reason}")
}
else -> withdrawResponse
}
}.onFailure {
Logger.warn("Failed to request LNURL withdraw", it, context = TAG)
}
suspend fun fetchLnurlInvoice(
callbackUrl: String,
amountSats: ULong,
comment: String? = null,
): Result<LnurlPayResponse> = runCatching {
Logger.debug("Fetching LNURL pay invoice from: $callbackUrl", context = TAG)
val response = client.get(callbackUrl) {
url {
parameters["amount"] = "${amountSats * 1000u}" // convert to msat
comment?.takeIf { it.isNotBlank() }?.let {
parameters["comment"] = it
}
}
}
Logger.debug("Http call: $response", context = TAG)
if (!response.status.isSuccess()) {
throw HttpError("fetchLnurlInvoice error: '${response.status.description}'", response.status.value)
}
return@runCatching response.body<LnurlPayResponse>()
}
suspend fun requestLnurlChannel(url: String): Result<LnurlChannelResponse> = runCatching {
Logger.debug("Requesting LNURL channel request via: '$url'", context = TAG)
val response: HttpResponse = client.get(url)
Logger.debug("Http call: $response", context = TAG)
if (!response.status.isSuccess()) {
throw HttpError("requestLnurlChannel error: '${response.status.description}'", response.status.value)
}
val parsedResponse = response.body<LnurlChannelResponse>()
when (parsedResponse.status == "ERROR") {
true -> throw HttpError("requestLnurlChannel error: '${parsedResponse.reason}'", response.status.value)
else -> parsedResponse
}
}.onFailure {
Logger.warn("Failed to request LNURL channel", it, context = TAG)
}
companion object {
private const val TAG = "LnurlService"
}
}
@Serializable
data class LnurlWithdrawResponse(
val status: String? = null,
val reason: String? = null,
val tag: String? = null,
val callback: String? = null,
val k1: String? = null,
val defaultDescription: String? = null,
val minWithdrawable: Long? = null,
val maxWithdrawable: Long? = null,
val balanceCheck: String? = null,
)
@Serializable
data class LnurlPayResponse(
val pr: String,
val routes: List<String>,
)
@Serializable
data class LnurlChannelResponse(
val status: String? = null,
val reason: String? = null,
)