Finishes serialization features for NIP-47

This commit is contained in:
Vitor Pamplona
2026-03-16 16:35:05 -04:00
parent 2d959b0108
commit b916817247
13 changed files with 776 additions and 9 deletions
@@ -107,6 +107,18 @@ class KotlinSerializationMapper {
json.encodeToString(BunkerMessageKSerializer, value)
}
is Request -> {
json.encodeToString(Nip47RequestKSerializer, value)
}
is Response -> {
json.encodeToString(Nip47ResponseKSerializer, value)
}
is Notification -> {
json.encodeToString(Nip47NotificationKSerializer, value)
}
else -> {
throw IllegalArgumentException("Unsupported type: ${value::class}")
}
@@ -62,7 +62,7 @@ class NwcTransaction(
var expires_at: Long? = null,
var settled_at: Long? = null,
var settle_deadline: Long? = null,
var metadata: Any? = null,
var metadata: Map<String, Any?>? = null,
) {
fun parsedMetadata(): NwcTransactionMetadata? = NwcTransactionMetadata.parse(metadata)
}
@@ -31,7 +31,7 @@ abstract class Request(
class PayInvoiceParams(
var invoice: String? = null,
var amount: Long? = null,
var metadata: Any? = null,
var metadata: Map<String, Any?>? = null,
)
class PayInvoiceMethod(
@@ -74,7 +74,7 @@ class MakeInvoiceParams(
var description: String? = null,
var description_hash: String? = null,
var expiry: Long? = null,
var metadata: Any? = null,
var metadata: Map<String, Any?>? = null,
)
class MakeInvoiceMethod(
@@ -233,7 +233,7 @@ class CreateConnectionParams(
var budget_renewal: String? = null,
var expires_at: Long? = null,
var isolated: Boolean? = null,
var metadata: Any? = null,
var metadata: Map<String, Any?>? = null,
)
class CreateConnectionMethod(
@@ -249,7 +249,7 @@ class CreateConnectionMethod(
budgetRenewal: String? = null,
expiresAt: Long? = null,
isolated: Boolean? = null,
metadata: Any? = null,
metadata: Map<String, Any?>? = null,
): CreateConnectionMethod =
CreateConnectionMethod(
CreateConnectionParams(pubkey, name, requestMethods, notificationTypes, maxAmount, budgetRenewal, expiresAt, isolated, metadata),
@@ -105,7 +105,7 @@ class GetInfoSuccessResponse(
val block_hash: String? = null,
val methods: List<String>? = null,
val notifications: List<String>? = null,
val metadata: Any? = null,
val metadata: Map<String, Any?>? = null,
val lud16: String? = null,
)
}
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2025 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.quartz.nip47WalletConnect.kotlinSerialization
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
// Helper function to convert JsonElement to standard Kotlin types recursively
fun JsonElement.toAnyValue(): Any =
when (this) {
is JsonPrimitive -> {
if (isString) {
content
} else {
content.toBooleanStrictOrNull() ?: content.toDoubleOrNull() ?: content.toLongOrNull() ?: content
}
}
is JsonObject -> {
toAnyMap()
}
is JsonArray -> {
map { it.toAnyValue() }
}
}
fun JsonObject.toAnyMap(): Map<String, Any?> = entries.associate { it.key to it.value.toAnyValue() }
@@ -32,10 +32,13 @@ import kotlinx.serialization.descriptors.buildClassSerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.JsonDecoder
import kotlinx.serialization.json.JsonEncoder
import kotlinx.serialization.json.JsonNull
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import kotlinx.serialization.json.longOrNull
import kotlinx.serialization.json.put
object Nip47NotificationKSerializer : KSerializer<Notification> {
override val descriptor: SerialDescriptor =
@@ -44,7 +47,44 @@ object Nip47NotificationKSerializer : KSerializer<Notification> {
override fun serialize(
encoder: Encoder,
value: Notification,
): Unit = throw UnsupportedOperationException("NIP-47 Notification serialization not supported")
) {
val jsonEncoder = encoder as JsonEncoder
val jsonObject =
buildJsonObject {
put("notification_type", value.notification_type)
when (value) {
is PaymentReceivedNotification -> {
Nip47ResponseKSerializer.serializeTransaction(value.notification)?.let {
put("notification", it)
}
}
is PaymentSentNotification -> {
Nip47ResponseKSerializer.serializeTransaction(value.notification)?.let {
put("notification", it)
}
}
is HoldInvoiceAcceptedNotification -> {
value.notification?.let { data ->
put(
"notification",
buildJsonObject {
data.type?.let { put("type", it) }
data.invoice?.let { put("invoice", it) }
data.payment_hash?.let { put("payment_hash", it) }
data.amount?.let { put("amount", it) }
data.created_at?.let { put("created_at", it) }
data.expires_at?.let { put("expires_at", it) }
data.settle_deadline?.let { put("settle_deadline", it) }
},
)
}
}
}
}
jsonEncoder.encodeJsonElement(jsonObject)
}
override fun deserialize(decoder: Decoder): Notification {
val jsonDecoder = decoder as JsonDecoder
@@ -51,15 +51,23 @@ import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonDecoder
import kotlinx.serialization.json.JsonEncoder
import kotlinx.serialization.json.JsonNull
import kotlinx.serialization.json.JsonNull.content
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.add
import kotlinx.serialization.json.booleanOrNull
import kotlinx.serialization.json.buildJsonArray
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.encodeToJsonElement
import kotlinx.serialization.json.intOrNull
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import kotlinx.serialization.json.longOrNull
import kotlinx.serialization.json.put
object Nip47RequestKSerializer : KSerializer<Request> {
override val descriptor: SerialDescriptor =
@@ -68,7 +76,159 @@ object Nip47RequestKSerializer : KSerializer<Request> {
override fun serialize(
encoder: Encoder,
value: Request,
): Unit = throw UnsupportedOperationException("NIP-47 Request serialization not supported")
) {
val jsonEncoder = encoder as JsonEncoder
val jsonObject =
buildJsonObject {
put("method", value.method)
when (value) {
is PayInvoiceMethod -> {
value.params?.let { put("params", serializePayInvoiceParams(it)) }
}
is PayKeysendMethod -> {
value.params?.let { put("params", serializePayKeysendParams(it)) }
}
is MakeInvoiceMethod -> {
value.params?.let { put("params", serializeMakeInvoiceParams(it)) }
}
is LookupInvoiceMethod -> {
value.params?.let { put("params", serializeLookupInvoiceParams(it)) }
}
is ListTransactionsMethod -> {
value.params?.let { put("params", serializeListTransactionsParams(it)) }
}
is GetBalanceMethod -> {}
is GetInfoMethod -> {}
is GetBudgetMethod -> {}
is SignMessageMethod -> {
value.params?.let { put("params", serializeSignMessageParams(it)) }
}
is CreateConnectionMethod -> {
value.params?.let { put("params", serializeCreateConnectionParams(it)) }
}
is MakeHoldInvoiceMethod -> {
value.params?.let { put("params", serializeMakeHoldInvoiceParams(it)) }
}
is CancelHoldInvoiceMethod -> {
value.params?.let { put("params", serializeCancelHoldInvoiceParams(it)) }
}
is SettleHoldInvoiceMethod -> {
value.params?.let { put("params", serializeSettleHoldInvoiceParams(it)) }
}
}
}
jsonEncoder.encodeJsonElement(jsonObject)
}
private fun serializePayInvoiceParams(params: PayInvoiceParams): JsonObject =
buildJsonObject {
params.invoice?.let { put("invoice", it) }
params.amount?.let { put("amount", it) }
params.metadata?.let { put("metadata", Json.encodeToJsonElement(it)) }
}
private fun serializePayKeysendParams(params: PayKeysendParams): JsonObject =
buildJsonObject {
params.amount?.let { put("amount", it) }
params.pubkey?.let { put("pubkey", it) }
params.preimage?.let { put("preimage", it) }
params.tlv_records?.let { records ->
put(
"tlv_records",
buildJsonArray {
records.forEach { record ->
add(
buildJsonObject {
record.type?.let { put("type", it) }
record.value?.let { put("value", it) }
},
)
}
},
)
}
}
private fun serializeMakeInvoiceParams(params: MakeInvoiceParams): JsonObject =
buildJsonObject {
params.amount?.let { put("amount", it) }
params.description?.let { put("description", it) }
params.description_hash?.let { put("description_hash", it) }
params.expiry?.let { put("expiry", it) }
params.metadata?.let { put("metadata", Json.encodeToJsonElement(it)) }
}
private fun serializeLookupInvoiceParams(params: LookupInvoiceParams): JsonObject =
buildJsonObject {
params.payment_hash?.let { put("payment_hash", it) }
params.invoice?.let { put("invoice", it) }
}
private fun serializeListTransactionsParams(params: ListTransactionsParams): JsonObject =
buildJsonObject {
params.from?.let { put("from", it) }
params.until?.let { put("until", it) }
params.limit?.let { put("limit", it) }
params.offset?.let { put("offset", it) }
params.unpaid?.let { put("unpaid", it) }
params.unpaid_outgoing?.let { put("unpaid_outgoing", it) }
params.unpaid_incoming?.let { put("unpaid_incoming", it) }
params.type?.let { put("type", it) }
}
private fun serializeSignMessageParams(params: SignMessageParams): JsonObject =
buildJsonObject {
params.message?.let { put("message", it) }
}
private fun serializeCreateConnectionParams(params: CreateConnectionParams): JsonObject =
buildJsonObject {
params.pubkey?.let { put("pubkey", it) }
params.name?.let { put("name", it) }
params.request_methods?.let { methods ->
put("request_methods", buildJsonArray { methods.forEach { add(it) } })
}
params.notification_types?.let { types ->
put("notification_types", buildJsonArray { types.forEach { add(it) } })
}
params.max_amount?.let { put("max_amount", it) }
params.budget_renewal?.let { put("budget_renewal", it) }
params.expires_at?.let { put("expires_at", it) }
params.isolated?.let { put("isolated", it) }
params.metadata?.let { put("metadata", Json.encodeToJsonElement(it)) }
}
private fun serializeMakeHoldInvoiceParams(params: MakeHoldInvoiceParams): JsonObject =
buildJsonObject {
params.amount?.let { put("amount", it) }
params.description?.let { put("description", it) }
params.description_hash?.let { put("description_hash", it) }
params.expiry?.let { put("expiry", it) }
params.payment_hash?.let { put("payment_hash", it) }
params.min_cltv_expiry_delta?.let { put("min_cltv_expiry_delta", it) }
}
private fun serializeCancelHoldInvoiceParams(params: CancelHoldInvoiceParams): JsonObject =
buildJsonObject {
params.payment_hash?.let { put("payment_hash", it) }
}
private fun serializeSettleHoldInvoiceParams(params: SettleHoldInvoiceParams): JsonObject =
buildJsonObject {
params.preimage?.let { put("preimage", it) }
}
override fun deserialize(decoder: Decoder): Request {
val jsonDecoder = decoder as JsonDecoder
@@ -100,6 +260,7 @@ object Nip47RequestKSerializer : KSerializer<Request> {
PayInvoiceParams(
invoice = it["invoice"]?.jsonPrimitive?.content,
amount = it["amount"]?.jsonPrimitive?.longOrNull,
metadata = it["metadata"]?.jsonObject?.toAnyMap(),
)
},
)
@@ -135,6 +296,7 @@ object Nip47RequestKSerializer : KSerializer<Request> {
description = it["description"]?.jsonPrimitive?.content,
description_hash = it["description_hash"]?.jsonPrimitive?.content,
expiry = it["expiry"]?.jsonPrimitive?.longOrNull,
metadata = it["metadata"]?.jsonObject?.toAnyMap(),
)
},
)
@@ -194,6 +356,7 @@ object Nip47RequestKSerializer : KSerializer<Request> {
budget_renewal = it["budget_renewal"]?.jsonPrimitive?.content,
expires_at = it["expires_at"]?.jsonPrimitive?.longOrNull,
isolated = it["isolated"]?.jsonPrimitive?.booleanOrNull,
metadata = it["metadata"]?.jsonObject?.toAnyMap(),
)
},
)
@@ -45,13 +45,20 @@ import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonDecoder
import kotlinx.serialization.json.JsonEncoder
import kotlinx.serialization.json.JsonNull
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.add
import kotlinx.serialization.json.buildJsonArray
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.encodeToJsonElement
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import kotlinx.serialization.json.longOrNull
import kotlinx.serialization.json.put
object Nip47ResponseKSerializer : KSerializer<Response> {
override val descriptor: SerialDescriptor =
@@ -60,7 +67,154 @@ object Nip47ResponseKSerializer : KSerializer<Response> {
override fun serialize(
encoder: Encoder,
value: Response,
): Unit = throw UnsupportedOperationException("NIP-47 Response serialization not supported")
) {
val jsonEncoder = encoder as JsonEncoder
val jsonObject =
buildJsonObject {
put("result_type", value.resultType)
when (value) {
is NwcErrorResponse -> {
value.error?.let { put("error", serializeNwcError(it)) }
}
is PayInvoiceSuccessResponse -> {
value.result?.let { put("result", serializePayInvoiceResult(it)) }
}
is PayInvoiceErrorResponse -> {
value.error?.let { put("error", serializePayInvoiceErrorParams(it)) }
}
is PayKeysendSuccessResponse -> {
value.result?.let { put("result", serializePayKeysendResult(it)) }
}
is MakeInvoiceSuccessResponse -> {
serializeTransaction(value.result)?.let { put("result", it) }
}
is LookupInvoiceSuccessResponse -> {
serializeTransaction(value.result)?.let { put("result", it) }
}
is ListTransactionsSuccessResponse -> {
value.result?.let { put("result", serializeListTransactionsResult(it)) }
}
is GetBalanceSuccessResponse -> {
value.result?.let { put("result", serializeGetBalanceResult(it)) }
}
is GetInfoSuccessResponse -> {
value.result?.let { put("result", serializeGetInfoResult(it)) }
}
is GetBudgetSuccessResponse -> {
value.result?.let { put("result", serializeGetBudgetResult(it)) }
}
is SignMessageSuccessResponse -> {
value.result?.let { put("result", serializeSignMessageResult(it)) }
}
is CreateConnectionSuccessResponse -> {
value.result?.let { put("result", serializeCreateConnectionResult(it)) }
}
is MakeHoldInvoiceSuccessResponse -> {
serializeTransaction(value.result)?.let { put("result", it) }
}
is CancelHoldInvoiceSuccessResponse -> {
put("result", buildJsonObject {})
}
is SettleHoldInvoiceSuccessResponse -> {
put("result", buildJsonObject {})
}
}
}
jsonEncoder.encodeJsonElement(jsonObject)
}
private fun serializeNwcError(error: NwcError): JsonObject =
buildJsonObject {
error.code?.let { put("code", it.name) }
error.message?.let { put("message", it) }
}
private fun serializePayInvoiceResult(result: PayInvoiceSuccessResponse.PayInvoiceResultParams): JsonObject =
buildJsonObject {
result.preimage?.let { put("preimage", it) }
result.fees_paid?.let { put("fees_paid", it) }
}
private fun serializePayInvoiceErrorParams(error: PayInvoiceErrorResponse.PayInvoiceErrorParams): JsonObject =
buildJsonObject {
error.code?.let { put("code", it.name) }
error.message?.let { put("message", it) }
}
private fun serializePayKeysendResult(result: PayKeysendSuccessResponse.PayKeysendResult): JsonObject =
buildJsonObject {
result.preimage?.let { put("preimage", it) }
result.fees_paid?.let { put("fees_paid", it) }
}
private fun serializeListTransactionsResult(result: ListTransactionsSuccessResponse.ListTransactionsResult): JsonObject =
buildJsonObject {
result.transactions?.let { transactions ->
put(
"transactions",
buildJsonArray {
transactions.forEach { serializeTransaction(it)?.let { t -> add(t) } }
},
)
}
result.total_count?.let { put("total_count", it) }
}
private fun serializeGetBalanceResult(result: GetBalanceSuccessResponse.GetBalanceResult): JsonObject =
buildJsonObject {
result.balance?.let { put("balance", it) }
}
private fun serializeGetInfoResult(result: GetInfoSuccessResponse.GetInfoResult): JsonObject =
buildJsonObject {
result.alias?.let { put("alias", it) }
result.color?.let { put("color", it) }
result.pubkey?.let { put("pubkey", it) }
result.network?.let { put("network", it) }
result.block_height?.let { put("block_height", it) }
result.block_hash?.let { put("block_hash", it) }
result.methods?.let { methods ->
put("methods", buildJsonArray { methods.forEach { add(it) } })
}
result.notifications?.let { notifications ->
put("notifications", buildJsonArray { notifications.forEach { add(it) } })
}
result.metadata?.let { put("metadata", Json.encodeToJsonElement(it)) }
result.lud16?.let { put("lud16", it) }
}
private fun serializeGetBudgetResult(result: GetBudgetSuccessResponse.GetBudgetResult): JsonObject =
buildJsonObject {
result.used_budget?.let { put("used_budget", it) }
result.total_budget?.let { put("total_budget", it) }
result.renews_at?.let { put("renews_at", it) }
result.renewal_period?.let { put("renewal_period", it) }
}
private fun serializeSignMessageResult(result: SignMessageSuccessResponse.SignMessageResult): JsonObject =
buildJsonObject {
result.message?.let { put("message", it) }
result.signature?.let { put("signature", it) }
}
private fun serializeCreateConnectionResult(result: CreateConnectionSuccessResponse.CreateConnectionResult): JsonObject =
buildJsonObject {
result.wallet_pubkey?.let { put("wallet_pubkey", it) }
}
override fun deserialize(decoder: Decoder): Response {
val jsonDecoder = decoder as JsonDecoder
@@ -162,6 +316,26 @@ object Nip47ResponseKSerializer : KSerializer<Response> {
return NwcError(code, obj["message"]?.jsonPrimitive?.content)
}
fun serializeTransaction(transaction: NwcTransaction?): JsonObject? {
if (transaction == null) return null
return buildJsonObject {
transaction.type?.let { put("type", it) }
transaction.state?.let { put("state", it) }
transaction.invoice?.let { put("invoice", it) }
transaction.description?.let { put("description", it) }
transaction.description_hash?.let { put("description_hash", it) }
transaction.preimage?.let { put("preimage", it) }
transaction.payment_hash?.let { put("payment_hash", it) }
transaction.amount?.let { put("amount", it) }
transaction.fees_paid?.let { put("fees_paid", it) }
transaction.created_at?.let { put("created_at", it) }
transaction.expires_at?.let { put("expires_at", it) }
transaction.settled_at?.let { put("settled_at", it) }
transaction.settle_deadline?.let { put("settle_deadline", it) }
transaction.metadata?.let { put("metadata", Json.encodeToJsonElement(it)) }
}
}
fun parseTransaction(obj: JsonObject?): NwcTransaction? {
if (obj == null) return null
return NwcTransaction(
@@ -178,6 +352,7 @@ object Nip47ResponseKSerializer : KSerializer<Response> {
expires_at = obj["expires_at"]?.jsonPrimitive?.longOrNull,
settled_at = obj["settled_at"]?.jsonPrimitive?.longOrNull,
settle_deadline = obj["settle_deadline"]?.jsonPrimitive?.longOrNull,
metadata = obj["metadata"]?.jsonObject?.toAnyMap(),
)
}
@@ -260,6 +435,7 @@ object Nip47ResponseKSerializer : KSerializer<Response> {
block_hash = it["block_hash"]?.jsonPrimitive?.content,
methods = it["methods"]?.jsonArray?.map { m -> m.jsonPrimitive.content },
notifications = it["notifications"]?.jsonArray?.map { n -> n.jsonPrimitive.content },
metadata = it["metadata"]?.jsonObject?.toAnyMap(),
lud16 = it["lud16"]?.jsonPrimitive?.content,
)
},
@@ -56,8 +56,11 @@ import com.vitorpamplona.quartz.nip47WalletConnect.Notification
import com.vitorpamplona.quartz.nip47WalletConnect.Request
import com.vitorpamplona.quartz.nip47WalletConnect.Response
import com.vitorpamplona.quartz.nip47WalletConnect.jackson.NotificationDeserializer
import com.vitorpamplona.quartz.nip47WalletConnect.jackson.NotificationSerializer
import com.vitorpamplona.quartz.nip47WalletConnect.jackson.RequestDeserializer
import com.vitorpamplona.quartz.nip47WalletConnect.jackson.RequestSerializer
import com.vitorpamplona.quartz.nip47WalletConnect.jackson.ResponseDeserializer
import com.vitorpamplona.quartz.nip47WalletConnect.jackson.ResponseSerializer
import com.vitorpamplona.quartz.nip59Giftwrap.rumors.Rumor
import com.vitorpamplona.quartz.nip59Giftwrap.rumors.jackson.RumorDeserializer
import com.vitorpamplona.quartz.nip59Giftwrap.rumors.jackson.RumorSerializer
@@ -93,8 +96,11 @@ class JacksonMapper {
.addSerializer(Rumor::class.java, RumorSerializer())
.addDeserializer(Rumor::class.java, RumorDeserializer())
// nip 47
.addSerializer(Response::class.java, ResponseSerializer())
.addDeserializer(Response::class.java, ResponseDeserializer())
.addSerializer(Request::class.java, RequestSerializer())
.addDeserializer(Request::class.java, RequestDeserializer())
.addSerializer(Notification::class.java, NotificationSerializer())
.addDeserializer(Notification::class.java, NotificationDeserializer())
// nip 46
.addDeserializer(BunkerMessage::class.java, BunkerMessageDeserializer())
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2025 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.quartz.nip47WalletConnect.jackson
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.databind.SerializerProvider
import com.fasterxml.jackson.databind.ser.std.StdSerializer
import com.vitorpamplona.quartz.nip47WalletConnect.HoldInvoiceAcceptedNotification
import com.vitorpamplona.quartz.nip47WalletConnect.Notification
import com.vitorpamplona.quartz.nip47WalletConnect.PaymentReceivedNotification
import com.vitorpamplona.quartz.nip47WalletConnect.PaymentSentNotification
class NotificationSerializer : StdSerializer<Notification>(Notification::class.java) {
override fun serialize(
value: Notification,
gen: JsonGenerator,
provider: SerializerProvider,
) {
gen.writeStartObject()
gen.writeStringField("notification_type", value.notification_type)
when (value) {
is PaymentReceivedNotification -> {
if (value.notification != null) {
gen.writeObjectField("notification", value.notification)
}
}
is PaymentSentNotification -> {
if (value.notification != null) {
gen.writeObjectField("notification", value.notification)
}
}
is HoldInvoiceAcceptedNotification -> {
if (value.notification != null) {
gen.writeObjectField("notification", value.notification)
}
}
}
gen.writeEndObject()
}
}
@@ -0,0 +1,111 @@
/*
* Copyright (c) 2025 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.quartz.nip47WalletConnect.jackson
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.databind.SerializerProvider
import com.fasterxml.jackson.databind.ser.std.StdSerializer
import com.vitorpamplona.quartz.nip47WalletConnect.CancelHoldInvoiceMethod
import com.vitorpamplona.quartz.nip47WalletConnect.CreateConnectionMethod
import com.vitorpamplona.quartz.nip47WalletConnect.ListTransactionsMethod
import com.vitorpamplona.quartz.nip47WalletConnect.LookupInvoiceMethod
import com.vitorpamplona.quartz.nip47WalletConnect.MakeHoldInvoiceMethod
import com.vitorpamplona.quartz.nip47WalletConnect.MakeInvoiceMethod
import com.vitorpamplona.quartz.nip47WalletConnect.PayInvoiceMethod
import com.vitorpamplona.quartz.nip47WalletConnect.PayKeysendMethod
import com.vitorpamplona.quartz.nip47WalletConnect.Request
import com.vitorpamplona.quartz.nip47WalletConnect.SettleHoldInvoiceMethod
import com.vitorpamplona.quartz.nip47WalletConnect.SignMessageMethod
class RequestSerializer : StdSerializer<Request>(Request::class.java) {
override fun serialize(
value: Request,
gen: JsonGenerator,
provider: SerializerProvider,
) {
gen.writeStartObject()
if (value.method != null) {
gen.writeStringField("method", value.method)
}
when (value) {
is PayInvoiceMethod -> {
if (value.params != null) {
gen.writeObjectField("params", value.params)
}
}
is PayKeysendMethod -> {
if (value.params != null) {
gen.writeObjectField("params", value.params)
}
}
is MakeInvoiceMethod -> {
if (value.params != null) {
gen.writeObjectField("params", value.params)
}
}
is LookupInvoiceMethod -> {
if (value.params != null) {
gen.writeObjectField("params", value.params)
}
}
is ListTransactionsMethod -> {
if (value.params != null) {
gen.writeObjectField("params", value.params)
}
}
is MakeHoldInvoiceMethod -> {
if (value.params != null) {
gen.writeObjectField("params", value.params)
}
}
is CancelHoldInvoiceMethod -> {
if (value.params != null) {
gen.writeObjectField("params", value.params)
}
}
is SettleHoldInvoiceMethod -> {
if (value.params != null) {
gen.writeObjectField("params", value.params)
}
}
is SignMessageMethod -> {
if (value.params != null) {
gen.writeObjectField("params", value.params)
}
}
is CreateConnectionMethod -> {
if (value.params != null) {
gen.writeObjectField("params", value.params)
}
}
}
gen.writeEndObject()
}
}
@@ -0,0 +1,146 @@
/*
* Copyright (c) 2025 Vitor Pamplona
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.vitorpamplona.quartz.nip47WalletConnect.jackson
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.databind.SerializerProvider
import com.fasterxml.jackson.databind.ser.std.StdSerializer
import com.vitorpamplona.quartz.nip47WalletConnect.CancelHoldInvoiceSuccessResponse
import com.vitorpamplona.quartz.nip47WalletConnect.CreateConnectionSuccessResponse
import com.vitorpamplona.quartz.nip47WalletConnect.GetBalanceSuccessResponse
import com.vitorpamplona.quartz.nip47WalletConnect.GetBudgetSuccessResponse
import com.vitorpamplona.quartz.nip47WalletConnect.GetInfoSuccessResponse
import com.vitorpamplona.quartz.nip47WalletConnect.ListTransactionsSuccessResponse
import com.vitorpamplona.quartz.nip47WalletConnect.LookupInvoiceSuccessResponse
import com.vitorpamplona.quartz.nip47WalletConnect.MakeHoldInvoiceSuccessResponse
import com.vitorpamplona.quartz.nip47WalletConnect.MakeInvoiceSuccessResponse
import com.vitorpamplona.quartz.nip47WalletConnect.NwcErrorResponse
import com.vitorpamplona.quartz.nip47WalletConnect.PayInvoiceErrorResponse
import com.vitorpamplona.quartz.nip47WalletConnect.PayInvoiceSuccessResponse
import com.vitorpamplona.quartz.nip47WalletConnect.PayKeysendSuccessResponse
import com.vitorpamplona.quartz.nip47WalletConnect.Response
import com.vitorpamplona.quartz.nip47WalletConnect.SettleHoldInvoiceSuccessResponse
import com.vitorpamplona.quartz.nip47WalletConnect.SignMessageSuccessResponse
class ResponseSerializer : StdSerializer<Response>(Response::class.java) {
override fun serialize(
value: Response,
gen: JsonGenerator,
provider: SerializerProvider,
) {
gen.writeStartObject()
if (value.resultType.isNotEmpty()) {
gen.writeStringField("result_type", value.resultType)
}
when (value) {
is NwcErrorResponse -> {
if (value.error != null) {
gen.writeObjectField("error", value.error)
}
}
is PayInvoiceErrorResponse -> {
if (value.error != null) {
gen.writeObjectField("error", value.error)
}
}
is PayInvoiceSuccessResponse -> {
if (value.result != null) {
gen.writeObjectField("result", value.result)
}
}
is PayKeysendSuccessResponse -> {
if (value.result != null) {
gen.writeObjectField("result", value.result)
}
}
is MakeInvoiceSuccessResponse -> {
if (value.result != null) {
gen.writeObjectField("result", value.result)
}
}
is LookupInvoiceSuccessResponse -> {
if (value.result != null) {
gen.writeObjectField("result", value.result)
}
}
is ListTransactionsSuccessResponse -> {
if (value.result != null) {
gen.writeObjectField("result", value.result)
}
}
is GetBalanceSuccessResponse -> {
if (value.result != null) {
gen.writeObjectField("result", value.result)
}
}
is GetInfoSuccessResponse -> {
if (value.result != null) {
gen.writeObjectField("result", value.result)
}
}
is MakeHoldInvoiceSuccessResponse -> {
if (value.result != null) {
gen.writeObjectField("result", value.result)
}
}
is CancelHoldInvoiceSuccessResponse -> {
if (value.result != null) {
gen.writeObjectField("result", value.result)
}
}
is SettleHoldInvoiceSuccessResponse -> {
if (value.result != null) {
gen.writeObjectField("result", value.result)
}
}
is GetBudgetSuccessResponse -> {
if (value.result != null) {
gen.writeObjectField("result", value.result)
}
}
is SignMessageSuccessResponse -> {
if (value.result != null) {
gen.writeObjectField("result", value.result)
}
}
is CreateConnectionSuccessResponse -> {
if (value.result != null) {
gen.writeObjectField("result", value.result)
}
}
}
gen.writeEndObject()
}
}