Skip to content

Commit

Permalink
Add post-tx callback for vasp1
Browse files Browse the repository at this point in the history
  • Loading branch information
jklein24 committed Sep 15, 2023
1 parent c97c200 commit 5b7a08c
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.lightspark.sdk.uma

import kotlinx.serialization.Serializable

@Serializable
data class UtxoWithAmount(
val utxo: String,
val amountMsats: Long,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.lightspark.sdk.util

import com.lightspark.sdk.model.CurrencyAmount
import com.lightspark.sdk.model.CurrencyUnit

fun CurrencyAmount.toMilliSats() = when (originalUnit) {
CurrencyUnit.SATOSHI -> originalValue * 1000L
CurrencyUnit.MILLISATOSHI -> originalValue
CurrencyUnit.BITCOIN -> originalValue * 100_000_000_000L
CurrencyUnit.MICROBITCOIN -> originalValue * 100_000L
CurrencyUnit.MILLIBITCOIN -> originalValue * 100_000_000L
CurrencyUnit.NANOBITCOIN -> originalValue * 100L
else -> throw IllegalArgumentException("Unsupported currency unit: $originalUnit")
}
4 changes: 4 additions & 0 deletions umaserverdemo/src/main/kotlin/com/lightspark/Logging.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ import io.ktor.server.application.ApplicationCall
fun ApplicationCall.debugLog(message: String) {
application.environment.log.debug(message)
}

fun ApplicationCall.errorLog(message: String, exception: Throwable? = null) {
application.environment.log.error(message, exception)
}
33 changes: 33 additions & 0 deletions umaserverdemo/src/main/kotlin/com/lightspark/Vasp1.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import com.lightspark.sdk.uma.LnurlpResponse
import com.lightspark.sdk.uma.PayReqResponse
import com.lightspark.sdk.uma.PayerDataOptions
import com.lightspark.sdk.uma.UmaProtocolHelper
import com.lightspark.sdk.uma.UtxoWithAmount
import com.lightspark.sdk.uma.selectHighestSupportedVersion
import com.lightspark.sdk.util.toMilliSats
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
Expand All @@ -30,6 +32,7 @@ import io.ktor.server.routing.get
import io.ktor.server.routing.post
import kotlinx.coroutines.delay
import kotlinx.datetime.Clock
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.buildJsonObject
Expand Down Expand Up @@ -318,6 +321,8 @@ class Vasp1(
return "Failed to pay invoice."
}

sendPostTransactionCallback(payment, payReqData, call)

call.respond(
buildJsonObject {
put("didSucceed", (payment.status == TransactionStatus.SUCCESS))
Expand All @@ -328,6 +333,34 @@ class Vasp1(
return "OK"
}

@OptIn(ExperimentalSerializationApi::class)
private suspend fun sendPostTransactionCallback(
payment: OutgoingPayment,
payReqData: Vasp1PayReqData,
call: ApplicationCall,
) {
val utxos = payment.umaPostTransactionData?.map { UtxoWithAmount(it.utxo, it.amount.toMilliSats()) }
?: emptyList()
val postTxHookResponse = try {
httpClient.post(payReqData.utxoCallback) {
contentType(ContentType.Application.Json)
setBody(
buildJsonObject {
putJsonArray("utxos") {
addAll(utxos.map { Json.encodeToJsonElement(it) })
}
},
)
}
} catch (e: Exception) {
call.errorLog("Failed to post tx hook", e)
null
}
if (postTxHookResponse?.status != HttpStatusCode.OK) {
call.errorLog("Failed to post tx hook: ${postTxHookResponse?.status}")
}
}

// TODO(Jeremy): Expose payInvoiceAndAwaitCompletion in the lightspark-sdk instead.
private suspend fun waitForPaymentCompletion(pendingPayment: OutgoingPayment): OutgoingPayment {
var attemptsLeft = 40
Expand Down
16 changes: 16 additions & 0 deletions umaserverdemo/src/main/kotlin/com/lightspark/plugins/Routing.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@ import com.lightspark.sdk.LightsparkCoroutinesClient
import com.lightspark.sdk.auth.AccountApiTokenAuthProvider
import com.lightspark.sdk.uma.InMemoryPublicKeyCache
import com.lightspark.sdk.uma.UmaProtocolHelper
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.Application
import io.ktor.server.application.call
import io.ktor.server.request.receive
import io.ktor.server.response.respond
import io.ktor.server.routing.get
import io.ktor.server.routing.routing
import kotlinx.serialization.json.JsonObject

fun Application.configureRouting(
config: UmaConfig,
Expand All @@ -37,5 +41,17 @@ fun Application.configureRouting(
get("/.well-known/lnurlpubkey") {
call.debugLog(handlePubKeyRequest(call, config))
}

get("/api/uma/utxoCallback") {
val request = try {
call.receive<JsonObject>()
} catch (e: Exception) {
call.respond(HttpStatusCode.BadRequest, "Invalid utxo callback.")
return@get
}

call.debugLog("Received UTXO callback: $request")
call.respond(HttpStatusCode.OK)
}
}
}

0 comments on commit 5b7a08c

Please sign in to comment.