feat: complete NIP-47 Nostr Wallet Connect implementation in Quartz
Implements the full NIP-47 specification with all request methods, response types, notification events, and JSON serialization. New request methods: - pay_invoice (updated with amount, metadata params) - pay_keysend (amount, pubkey, preimage, TLV records) - make_invoice, lookup_invoice, list_transactions - get_balance, get_info - make_hold_invoice, cancel_hold_invoice, settle_hold_invoice New response types: - Success responses for all methods above - NwcErrorResponse (generic error for any method) - NwcErrorCode enum with UNSUPPORTED_ENCRYPTION New event kinds: - NwcInfoEvent (kind 13194) - wallet service capabilities - NwcNotificationEvent (kind 23197) - NIP-44 encrypted notifications - Legacy kind 23196 support for NIP-04 notifications New data models: - NwcTransaction (shared invoice/payment object) - TlvRecord (for keysend TLV records) - Notification types: payment_received, payment_sent, hold_invoice_accepted - HoldInvoiceAcceptedData with settle_deadline Tags (following NIP-88 pattern): - EncryptionTag for encryption scheme negotiation - NotificationsTag for supported notification types Updated: - LnZapPaymentRequestEvent: generic createRequest() with NIP-44 support - URI parser: lud16 parameter support - Jackson deserializers: all methods routed correctly - EventFactory: new kinds registered https://claude.ai/code/session_01JFogiwyR4CPVP8cRznqahJ
This commit is contained in:
+30
-8
@@ -52,25 +52,47 @@ class LnZapPaymentRequestEvent(
|
||||
return OptimizedJsonMapper.fromJsonTo<Request>(jsonText)
|
||||
}
|
||||
|
||||
fun encryptionScheme() = tags.firstOrNull { it.size > 1 && it[0] == "encryption" }?.get(1)
|
||||
|
||||
companion object {
|
||||
const val KIND = 23194
|
||||
const val ALT = "Zap payment request"
|
||||
const val ALT = "NWC request"
|
||||
|
||||
suspend fun create(
|
||||
lnInvoice: String,
|
||||
walletServicePubkey: String,
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
): LnZapPaymentRequestEvent {
|
||||
val serializedRequest = OptimizedJsonMapper.toJson(PayInvoiceMethod.create(lnInvoice))
|
||||
): LnZapPaymentRequestEvent =
|
||||
createRequest(
|
||||
PayInvoiceMethod.create(lnInvoice),
|
||||
walletServicePubkey,
|
||||
signer,
|
||||
createdAt,
|
||||
)
|
||||
|
||||
val tags = arrayOf(arrayOf("p", walletServicePubkey), AltTag.assemble(ALT))
|
||||
suspend fun createRequest(
|
||||
request: Request,
|
||||
walletServicePubkey: String,
|
||||
signer: NostrSigner,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
useNip44: Boolean = false,
|
||||
): LnZapPaymentRequestEvent {
|
||||
val serializedRequest = OptimizedJsonMapper.toJson(request)
|
||||
|
||||
val tags =
|
||||
if (useNip44) {
|
||||
arrayOf(arrayOf("p", walletServicePubkey), AltTag.assemble(ALT), arrayOf("encryption", "nip44_v2"))
|
||||
} else {
|
||||
arrayOf(arrayOf("p", walletServicePubkey), AltTag.assemble(ALT))
|
||||
}
|
||||
|
||||
val encrypted =
|
||||
signer.nip04Encrypt(
|
||||
serializedRequest,
|
||||
walletServicePubkey,
|
||||
)
|
||||
if (useNip44) {
|
||||
signer.nip44Encrypt(serializedRequest, walletServicePubkey)
|
||||
} else {
|
||||
signer.nip04Encrypt(serializedRequest, walletServicePubkey)
|
||||
}
|
||||
|
||||
return signer.sign(createdAt, KIND, tags, encrypted)
|
||||
}
|
||||
|
||||
+7
-4
@@ -30,11 +30,10 @@ import com.vitorpamplona.quartz.utils.UriParser
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
// Rename to the corect nip number when ready.
|
||||
class Nip47WalletConnect {
|
||||
companion object {
|
||||
fun parse(uri: String): Nip47URINorm {
|
||||
// nostrwalletconnect://b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4?relay=wss%3A%2F%2Frelay.damus.io&metadata=%7B%22name%22%3A%22Example%22%7D
|
||||
// nostr+walletconnect://b889ff5b...?relay=wss%3A%2F%2Frelay.damus.io&secret=...&lud16=user@example.com
|
||||
|
||||
val url = UriParser(uri)
|
||||
|
||||
@@ -55,8 +54,9 @@ class Nip47WalletConnect {
|
||||
val relay = url.getQueryParameter("relay") ?: throw IllegalArgumentException("Relay cannot be null")
|
||||
val relayNorm = RelayUrlNormalizer.normalizeOrNull(relay) ?: throw IllegalArgumentException("Invalid relay Url")
|
||||
val secret = url.getQueryParameter("secret")
|
||||
val lud16 = url.getQueryParameter("lud16")
|
||||
|
||||
return Nip47URINorm(pubkeyHex, relayNorm, secret)
|
||||
return Nip47URINorm(pubkeyHex, relayNorm, secret, lud16)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ class Nip47WalletConnect {
|
||||
val pubKeyHex: HexKey,
|
||||
val relayUri: String,
|
||||
val secret: HexKey?,
|
||||
val lud16: String? = null,
|
||||
) {
|
||||
fun normalize(): Nip47URINorm? =
|
||||
RelayUrlNormalizer.normalizeOrNull(relayUri)?.let {
|
||||
@@ -72,6 +73,7 @@ class Nip47WalletConnect {
|
||||
pubKeyHex,
|
||||
it,
|
||||
secret,
|
||||
lud16,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -86,7 +88,8 @@ class Nip47WalletConnect {
|
||||
val pubKeyHex: HexKey,
|
||||
val relayUri: NormalizedRelayUrl,
|
||||
val secret: HexKey?,
|
||||
val lud16: String? = null,
|
||||
) {
|
||||
fun denormalize(): Nip47URI? = Nip47URI(pubKeyHex, relayUri.url, secret)
|
||||
fun denormalize(): Nip47URI? = Nip47URI(pubKeyHex, relayUri.url, secret, lud16)
|
||||
}
|
||||
}
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.OptimizedSerializable
|
||||
|
||||
object NwcNotificationType {
|
||||
const val PAYMENT_RECEIVED = "payment_received"
|
||||
const val PAYMENT_SENT = "payment_sent"
|
||||
const val HOLD_INVOICE_ACCEPTED = "hold_invoice_accepted"
|
||||
}
|
||||
|
||||
// NOTIFICATION OBJECTS
|
||||
abstract class Notification(
|
||||
val notification_type: String,
|
||||
) : OptimizedSerializable
|
||||
|
||||
// payment_received notification
|
||||
class PaymentReceivedNotification(
|
||||
val notification: NwcTransaction? = null,
|
||||
) : Notification(NwcNotificationType.PAYMENT_RECEIVED)
|
||||
|
||||
// payment_sent notification
|
||||
class PaymentSentNotification(
|
||||
val notification: NwcTransaction? = null,
|
||||
) : Notification(NwcNotificationType.PAYMENT_SENT)
|
||||
|
||||
// hold_invoice_accepted notification
|
||||
class HoldInvoiceAcceptedNotification(
|
||||
val notification: HoldInvoiceAcceptedData? = null,
|
||||
) : Notification(NwcNotificationType.HOLD_INVOICE_ACCEPTED)
|
||||
|
||||
class HoldInvoiceAcceptedData(
|
||||
var type: String? = null,
|
||||
var invoice: String? = null,
|
||||
var payment_hash: String? = null,
|
||||
var amount: Long? = null,
|
||||
var created_at: Long? = null,
|
||||
var expires_at: Long? = null,
|
||||
var settle_deadline: Long? = null,
|
||||
)
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
enum class NwcErrorCode {
|
||||
RATE_LIMITED,
|
||||
NOT_IMPLEMENTED,
|
||||
INSUFFICIENT_BALANCE,
|
||||
PAYMENT_FAILED,
|
||||
QUOTA_EXCEEDED,
|
||||
RESTRICTED,
|
||||
UNAUTHORIZED,
|
||||
INTERNAL,
|
||||
UNSUPPORTED_ENCRYPTION,
|
||||
OTHER,
|
||||
}
|
||||
|
||||
class NwcError(
|
||||
var code: NwcErrorCode? = null,
|
||||
var message: String? = null,
|
||||
)
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
||||
import com.vitorpamplona.quartz.nip31Alts.alt
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.tags.EncryptionTag
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.tags.NotificationsTag
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
|
||||
@Immutable
|
||||
class NwcInfoEvent(
|
||||
id: HexKey,
|
||||
pubKey: HexKey,
|
||||
createdAt: Long,
|
||||
tags: Array<Array<String>>,
|
||||
content: String,
|
||||
sig: HexKey,
|
||||
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||
fun capabilities(): List<String> = content.split(" ").filter { it.isNotBlank() }
|
||||
|
||||
fun supportsMethod(method: String): Boolean = capabilities().contains(method)
|
||||
|
||||
fun supportsNotifications(): Boolean = capabilities().contains("notifications")
|
||||
|
||||
fun encryptionSchemes() = tags.mapNotNull(EncryptionTag::parse).flatten()
|
||||
|
||||
fun notificationTypes() = tags.mapNotNull(NotificationsTag::parse).flatten()
|
||||
|
||||
companion object {
|
||||
const val KIND = 13194
|
||||
const val ALT_DESCRIPTION = "Wallet service info"
|
||||
|
||||
fun build(
|
||||
capabilities: List<String>,
|
||||
encryptionSchemes: List<String>? = null,
|
||||
notificationTypes: List<String>? = null,
|
||||
createdAt: Long = TimeUtils.now(),
|
||||
initializer: TagArrayBuilder<NwcInfoEvent>.() -> Unit = {},
|
||||
) = eventTemplate(KIND, capabilities.joinToString(" "), createdAt) {
|
||||
alt(ALT_DESCRIPTION)
|
||||
encryptionSchemes?.let { addUnique(EncryptionTag.assemble(it)) }
|
||||
notificationTypes?.let { addUnique(NotificationsTag.assemble(it)) }
|
||||
initializer()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
object NwcMethod {
|
||||
const val PAY_INVOICE = "pay_invoice"
|
||||
const val PAY_KEYSEND = "pay_keysend"
|
||||
const val MAKE_INVOICE = "make_invoice"
|
||||
const val LOOKUP_INVOICE = "lookup_invoice"
|
||||
const val LIST_TRANSACTIONS = "list_transactions"
|
||||
const val GET_BALANCE = "get_balance"
|
||||
const val GET_INFO = "get_info"
|
||||
const val MAKE_HOLD_INVOICE = "make_hold_invoice"
|
||||
const val CANCEL_HOLD_INVOICE = "cancel_hold_invoice"
|
||||
const val SETTLE_HOLD_INVOICE = "settle_hold_invoice"
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.core.OptimizedJsonMapper
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions
|
||||
|
||||
@Immutable
|
||||
class NwcNotificationEvent(
|
||||
id: HexKey,
|
||||
pubKey: HexKey,
|
||||
createdAt: Long,
|
||||
tags: Array<Array<String>>,
|
||||
content: String,
|
||||
sig: HexKey,
|
||||
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||
override fun isContentEncoded() = true
|
||||
|
||||
fun clientPubKey() = tags.firstOrNull { it.size > 1 && it[0] == "p" }?.get(1)
|
||||
|
||||
fun talkingWith(oneSideHex: String): HexKey = if (pubKey == oneSideHex) clientPubKey() ?: pubKey else pubKey
|
||||
|
||||
fun canDecrypt(signer: NostrSigner) = pubKey == signer.pubKey || clientPubKey() == signer.pubKey
|
||||
|
||||
suspend fun decryptNotification(signer: NostrSigner): Notification {
|
||||
if (!canDecrypt(signer)) throw SignerExceptions.UnauthorizedDecryptionException()
|
||||
val jsonText = signer.nip44Decrypt(content, talkingWith(signer.pubKey))
|
||||
return OptimizedJsonMapper.fromJsonTo<Notification>(jsonText)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val KIND = 23197
|
||||
const val LEGACY_KIND = 23196
|
||||
const val ALT = "Wallet notification"
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
class NwcTransaction(
|
||||
var type: String? = null,
|
||||
var state: String? = null,
|
||||
var invoice: String? = null,
|
||||
var description: String? = null,
|
||||
var description_hash: String? = null,
|
||||
var preimage: String? = null,
|
||||
var payment_hash: String? = null,
|
||||
var amount: Long? = null,
|
||||
var fees_paid: Long? = null,
|
||||
var created_at: Long? = null,
|
||||
var expires_at: Long? = null,
|
||||
var settled_at: Long? = null,
|
||||
var metadata: Any? = null,
|
||||
)
|
||||
|
||||
class TlvRecord(
|
||||
var type: Long? = null,
|
||||
var value: String? = null,
|
||||
)
|
||||
+161
-2
@@ -27,15 +27,174 @@ abstract class Request(
|
||||
var method: String? = null,
|
||||
) : OptimizedSerializable
|
||||
|
||||
// PayInvoice Call
|
||||
// pay_invoice
|
||||
class PayInvoiceParams(
|
||||
var invoice: String? = null,
|
||||
var amount: Long? = null,
|
||||
var metadata: Any? = null,
|
||||
)
|
||||
|
||||
class PayInvoiceMethod(
|
||||
var params: PayInvoiceParams? = null,
|
||||
) : Request("pay_invoice") {
|
||||
) : Request(NwcMethod.PAY_INVOICE) {
|
||||
companion object {
|
||||
fun create(bolt11: String): PayInvoiceMethod = PayInvoiceMethod(PayInvoiceParams(bolt11))
|
||||
|
||||
fun create(
|
||||
bolt11: String,
|
||||
amount: Long,
|
||||
): PayInvoiceMethod = PayInvoiceMethod(PayInvoiceParams(bolt11, amount))
|
||||
}
|
||||
}
|
||||
|
||||
// pay_keysend
|
||||
class PayKeysendParams(
|
||||
var amount: Long? = null,
|
||||
var pubkey: String? = null,
|
||||
var preimage: String? = null,
|
||||
var tlv_records: List<TlvRecord>? = null,
|
||||
)
|
||||
|
||||
class PayKeysendMethod(
|
||||
var params: PayKeysendParams? = null,
|
||||
) : Request(NwcMethod.PAY_KEYSEND) {
|
||||
companion object {
|
||||
fun create(
|
||||
amount: Long,
|
||||
pubkey: String,
|
||||
preimage: String? = null,
|
||||
tlvRecords: List<TlvRecord>? = null,
|
||||
): PayKeysendMethod = PayKeysendMethod(PayKeysendParams(amount, pubkey, preimage, tlvRecords))
|
||||
}
|
||||
}
|
||||
|
||||
// make_invoice
|
||||
class MakeInvoiceParams(
|
||||
var amount: Long? = null,
|
||||
var description: String? = null,
|
||||
var description_hash: String? = null,
|
||||
var expiry: Long? = null,
|
||||
var metadata: Any? = null,
|
||||
)
|
||||
|
||||
class MakeInvoiceMethod(
|
||||
var params: MakeInvoiceParams? = null,
|
||||
) : Request(NwcMethod.MAKE_INVOICE) {
|
||||
companion object {
|
||||
fun create(
|
||||
amount: Long,
|
||||
description: String? = null,
|
||||
descriptionHash: String? = null,
|
||||
expiry: Long? = null,
|
||||
): MakeInvoiceMethod = MakeInvoiceMethod(MakeInvoiceParams(amount, description, descriptionHash, expiry))
|
||||
}
|
||||
}
|
||||
|
||||
// lookup_invoice
|
||||
class LookupInvoiceParams(
|
||||
var payment_hash: String? = null,
|
||||
var invoice: String? = null,
|
||||
)
|
||||
|
||||
class LookupInvoiceMethod(
|
||||
var params: LookupInvoiceParams? = null,
|
||||
) : Request(NwcMethod.LOOKUP_INVOICE) {
|
||||
companion object {
|
||||
fun createByHash(paymentHash: String): LookupInvoiceMethod = LookupInvoiceMethod(LookupInvoiceParams(payment_hash = paymentHash))
|
||||
|
||||
fun createByInvoice(invoice: String): LookupInvoiceMethod = LookupInvoiceMethod(LookupInvoiceParams(invoice = invoice))
|
||||
}
|
||||
}
|
||||
|
||||
// list_transactions
|
||||
class ListTransactionsParams(
|
||||
var from: Long? = null,
|
||||
var until: Long? = null,
|
||||
var limit: Int? = null,
|
||||
var offset: Int? = null,
|
||||
var unpaid: Boolean? = null,
|
||||
var type: String? = null,
|
||||
)
|
||||
|
||||
class ListTransactionsMethod(
|
||||
var params: ListTransactionsParams? = null,
|
||||
) : Request(NwcMethod.LIST_TRANSACTIONS) {
|
||||
companion object {
|
||||
fun create(
|
||||
from: Long? = null,
|
||||
until: Long? = null,
|
||||
limit: Int? = null,
|
||||
offset: Int? = null,
|
||||
unpaid: Boolean? = null,
|
||||
type: String? = null,
|
||||
): ListTransactionsMethod = ListTransactionsMethod(ListTransactionsParams(from, until, limit, offset, unpaid, type))
|
||||
}
|
||||
}
|
||||
|
||||
// get_balance
|
||||
class GetBalanceMethod : Request(NwcMethod.GET_BALANCE) {
|
||||
companion object {
|
||||
fun create(): GetBalanceMethod = GetBalanceMethod()
|
||||
}
|
||||
}
|
||||
|
||||
// get_info
|
||||
class GetInfoMethod : Request(NwcMethod.GET_INFO) {
|
||||
companion object {
|
||||
fun create(): GetInfoMethod = GetInfoMethod()
|
||||
}
|
||||
}
|
||||
|
||||
// make_hold_invoice
|
||||
class MakeHoldInvoiceParams(
|
||||
var amount: Long? = null,
|
||||
var description: String? = null,
|
||||
var description_hash: String? = null,
|
||||
var expiry: Long? = null,
|
||||
var payment_hash: String? = null,
|
||||
var min_cltv_expiry_delta: Int? = null,
|
||||
)
|
||||
|
||||
class MakeHoldInvoiceMethod(
|
||||
var params: MakeHoldInvoiceParams? = null,
|
||||
) : Request(NwcMethod.MAKE_HOLD_INVOICE) {
|
||||
companion object {
|
||||
fun create(
|
||||
amount: Long,
|
||||
paymentHash: String,
|
||||
description: String? = null,
|
||||
descriptionHash: String? = null,
|
||||
expiry: Long? = null,
|
||||
minCltvExpiryDelta: Int? = null,
|
||||
): MakeHoldInvoiceMethod =
|
||||
MakeHoldInvoiceMethod(
|
||||
MakeHoldInvoiceParams(amount, description, descriptionHash, expiry, paymentHash, minCltvExpiryDelta),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// cancel_hold_invoice
|
||||
class CancelHoldInvoiceParams(
|
||||
var payment_hash: String? = null,
|
||||
)
|
||||
|
||||
class CancelHoldInvoiceMethod(
|
||||
var params: CancelHoldInvoiceParams? = null,
|
||||
) : Request(NwcMethod.CANCEL_HOLD_INVOICE) {
|
||||
companion object {
|
||||
fun create(paymentHash: String): CancelHoldInvoiceMethod = CancelHoldInvoiceMethod(CancelHoldInvoiceParams(paymentHash))
|
||||
}
|
||||
}
|
||||
|
||||
// settle_hold_invoice
|
||||
class SettleHoldInvoiceParams(
|
||||
var preimage: String? = null,
|
||||
)
|
||||
|
||||
class SettleHoldInvoiceMethod(
|
||||
var params: SettleHoldInvoiceParams? = null,
|
||||
) : Request(NwcMethod.SETTLE_HOLD_INVOICE) {
|
||||
companion object {
|
||||
fun create(preimage: String): SettleHoldInvoiceMethod = SettleHoldInvoiceMethod(SettleHoldInvoiceParams(preimage))
|
||||
}
|
||||
}
|
||||
|
||||
+80
-32
@@ -27,49 +27,97 @@ abstract class Response(
|
||||
val resultType: String,
|
||||
) : OptimizedSerializable
|
||||
|
||||
// PayInvoice Call
|
||||
// Generic error response for any method
|
||||
class NwcErrorResponse(
|
||||
resultType: String,
|
||||
val error: NwcError? = null,
|
||||
) : Response(resultType)
|
||||
|
||||
// pay_invoice success response
|
||||
class PayInvoiceSuccessResponse(
|
||||
val result: PayInvoiceResultParams? = null,
|
||||
) : Response("pay_invoice") {
|
||||
) : Response(NwcMethod.PAY_INVOICE) {
|
||||
class PayInvoiceResultParams(
|
||||
val preimage: String? = null,
|
||||
val fees_paid: Long? = null,
|
||||
)
|
||||
}
|
||||
|
||||
// pay_invoice error response (kept for backward compatibility)
|
||||
class PayInvoiceErrorResponse(
|
||||
val error: PayInvoiceErrorParams? = null,
|
||||
) : Response("pay_invoice") {
|
||||
) : Response(NwcMethod.PAY_INVOICE) {
|
||||
class PayInvoiceErrorParams(
|
||||
val code: ErrorType? = null,
|
||||
val code: NwcErrorCode? = null,
|
||||
val message: String? = null,
|
||||
)
|
||||
|
||||
enum class ErrorType {
|
||||
RATE_LIMITED,
|
||||
|
||||
// The client is sending commands too fast. It should retry in a few seconds.
|
||||
NOT_IMPLEMENTED,
|
||||
|
||||
// The command is not known or is intentionally not implemented.
|
||||
INSUFFICIENT_BALANCE,
|
||||
|
||||
// The command is not known or is intentionally not implemented.
|
||||
PAYMENT_FAILED,
|
||||
|
||||
// The wallet does not have enough funds to cover a fee reserve or the payment amount.
|
||||
QUOTA_EXCEEDED,
|
||||
|
||||
// The wallet has exceeded its spending quota.
|
||||
RESTRICTED,
|
||||
|
||||
// This public key is not allowed to do this operation.
|
||||
UNAUTHORIZED,
|
||||
|
||||
// This public key has no wallet connected.
|
||||
INTERNAL,
|
||||
|
||||
// An internal error.
|
||||
OTHER, // Other error.
|
||||
}
|
||||
}
|
||||
|
||||
// pay_keysend success response
|
||||
class PayKeysendSuccessResponse(
|
||||
val result: PayKeysendResult? = null,
|
||||
) : Response(NwcMethod.PAY_KEYSEND) {
|
||||
class PayKeysendResult(
|
||||
val preimage: String? = null,
|
||||
val fees_paid: Long? = null,
|
||||
)
|
||||
}
|
||||
|
||||
// make_invoice success response
|
||||
class MakeInvoiceSuccessResponse(
|
||||
val result: NwcTransaction? = null,
|
||||
) : Response(NwcMethod.MAKE_INVOICE)
|
||||
|
||||
// lookup_invoice success response
|
||||
class LookupInvoiceSuccessResponse(
|
||||
val result: NwcTransaction? = null,
|
||||
) : Response(NwcMethod.LOOKUP_INVOICE)
|
||||
|
||||
// list_transactions success response
|
||||
class ListTransactionsSuccessResponse(
|
||||
val result: ListTransactionsResult? = null,
|
||||
) : Response(NwcMethod.LIST_TRANSACTIONS) {
|
||||
class ListTransactionsResult(
|
||||
val transactions: List<NwcTransaction>? = null,
|
||||
)
|
||||
}
|
||||
|
||||
// get_balance success response
|
||||
class GetBalanceSuccessResponse(
|
||||
val result: GetBalanceResult? = null,
|
||||
) : Response(NwcMethod.GET_BALANCE) {
|
||||
class GetBalanceResult(
|
||||
val balance: Long? = null,
|
||||
)
|
||||
}
|
||||
|
||||
// get_info success response
|
||||
class GetInfoSuccessResponse(
|
||||
val result: GetInfoResult? = null,
|
||||
) : Response(NwcMethod.GET_INFO) {
|
||||
class GetInfoResult(
|
||||
val alias: String? = null,
|
||||
val color: String? = null,
|
||||
val pubkey: String? = null,
|
||||
val network: String? = null,
|
||||
val block_height: Long? = null,
|
||||
val block_hash: String? = null,
|
||||
val methods: List<String>? = null,
|
||||
val notifications: List<String>? = null,
|
||||
)
|
||||
}
|
||||
|
||||
// make_hold_invoice success response
|
||||
class MakeHoldInvoiceSuccessResponse(
|
||||
val result: NwcTransaction? = null,
|
||||
) : Response(NwcMethod.MAKE_HOLD_INVOICE)
|
||||
|
||||
// cancel_hold_invoice success response
|
||||
class CancelHoldInvoiceSuccessResponse(
|
||||
val result: Any? = null,
|
||||
) : Response(NwcMethod.CANCEL_HOLD_INVOICE)
|
||||
|
||||
// settle_hold_invoice success response
|
||||
class SettleHoldInvoiceSuccessResponse(
|
||||
val result: Any? = null,
|
||||
) : Response(NwcMethod.SETTLE_HOLD_INVOICE)
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.tags
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||
import com.vitorpamplona.quartz.utils.ensure
|
||||
|
||||
class EncryptionTag {
|
||||
companion object {
|
||||
const val TAG_NAME = "encryption"
|
||||
|
||||
fun isTag(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty()
|
||||
|
||||
fun parse(tag: Array<String>): List<String>? {
|
||||
ensure(tag.has(1)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(tag[1].isNotEmpty()) { return null }
|
||||
return tag.drop(1)
|
||||
}
|
||||
|
||||
fun assemble(schemes: List<String>) = arrayOf(TAG_NAME, *schemes.toTypedArray())
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.tags
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||
import com.vitorpamplona.quartz.utils.ensure
|
||||
|
||||
class NotificationsTag {
|
||||
companion object {
|
||||
const val TAG_NAME = "notifications"
|
||||
|
||||
fun isTag(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && tag[1].isNotEmpty()
|
||||
|
||||
fun parse(tag: Array<String>): List<String>? {
|
||||
ensure(tag.has(1)) { return null }
|
||||
ensure(tag[0] == TAG_NAME) { return null }
|
||||
ensure(tag[1].isNotEmpty()) { return null }
|
||||
return tag.drop(1)
|
||||
}
|
||||
|
||||
fun assemble(types: List<String>) = arrayOf(TAG_NAME, *types.toTypedArray())
|
||||
}
|
||||
}
|
||||
@@ -78,6 +78,8 @@ import com.vitorpamplona.quartz.nip42RelayAuth.RelayAuthEvent
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.NostrConnectEvent
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.LnZapPaymentRequestEvent
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.LnZapPaymentResponseEvent
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.NwcInfoEvent
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.NwcNotificationEvent
|
||||
import com.vitorpamplona.quartz.nip50Search.SearchRelayListEvent
|
||||
import com.vitorpamplona.quartz.nip51Lists.PinListEvent
|
||||
import com.vitorpamplona.quartz.nip51Lists.bookmarkList.BookmarkListEvent
|
||||
@@ -256,6 +258,9 @@ class EventFactory {
|
||||
LnZapEvent.KIND -> LnZapEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
LnZapPaymentRequestEvent.KIND -> LnZapPaymentRequestEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
LnZapPaymentResponseEvent.KIND -> LnZapPaymentResponseEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
NwcInfoEvent.KIND -> NwcInfoEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
NwcNotificationEvent.KIND -> NwcNotificationEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
NwcNotificationEvent.LEGACY_KIND -> NwcNotificationEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
LnZapPrivateEvent.KIND -> LnZapPrivateEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
LnZapRequestEvent.KIND -> LnZapRequestEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
LongTextNoteEvent.KIND -> LongTextNoteEvent(id, pubKey, createdAt, tags, content, sig)
|
||||
|
||||
+3
@@ -52,8 +52,10 @@ import com.vitorpamplona.quartz.nip46RemoteSigner.jackson.BunkerRequestDeseriali
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.jackson.BunkerRequestSerializer
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.jackson.BunkerResponseDeserializer
|
||||
import com.vitorpamplona.quartz.nip46RemoteSigner.jackson.BunkerResponseSerializer
|
||||
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.RequestDeserializer
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.jackson.ResponseDeserializer
|
||||
import com.vitorpamplona.quartz.nip59Giftwrap.rumors.Rumor
|
||||
@@ -93,6 +95,7 @@ class JacksonMapper {
|
||||
// nip 47
|
||||
.addDeserializer(Response::class.java, ResponseDeserializer())
|
||||
.addDeserializer(Request::class.java, RequestDeserializer())
|
||||
.addDeserializer(Notification::class.java, NotificationDeserializer())
|
||||
// nip 46
|
||||
.addDeserializer(BunkerMessage::class.java, BunkerMessageDeserializer())
|
||||
.addSerializer(BunkerRequest::class.java, BunkerRequestSerializer())
|
||||
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.JsonParser
|
||||
import com.fasterxml.jackson.databind.DeserializationContext
|
||||
import com.fasterxml.jackson.databind.JsonNode
|
||||
import com.fasterxml.jackson.databind.deser.std.StdDeserializer
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.HoldInvoiceAcceptedNotification
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.Notification
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.NwcNotificationType
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.PaymentReceivedNotification
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.PaymentSentNotification
|
||||
import com.vitorpamplona.quartz.utils.asTextOrNull
|
||||
|
||||
class NotificationDeserializer : StdDeserializer<Notification>(Notification::class.java) {
|
||||
override fun deserialize(
|
||||
jp: JsonParser,
|
||||
ctxt: DeserializationContext,
|
||||
): Notification? {
|
||||
val jsonObject: JsonNode = jp.codec.readTree(jp)
|
||||
val notificationType = jsonObject.get("notification_type")?.asTextOrNull()
|
||||
|
||||
return when (notificationType) {
|
||||
NwcNotificationType.PAYMENT_RECEIVED -> jp.codec.treeToValue(jsonObject, PaymentReceivedNotification::class.java)
|
||||
NwcNotificationType.PAYMENT_SENT -> jp.codec.treeToValue(jsonObject, PaymentSentNotification::class.java)
|
||||
NwcNotificationType.HOLD_INVOICE_ACCEPTED -> jp.codec.treeToValue(jsonObject, HoldInvoiceAcceptedNotification::class.java)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
-3
@@ -24,8 +24,18 @@ import com.fasterxml.jackson.core.JsonParser
|
||||
import com.fasterxml.jackson.databind.DeserializationContext
|
||||
import com.fasterxml.jackson.databind.JsonNode
|
||||
import com.fasterxml.jackson.databind.deser.std.StdDeserializer
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.CancelHoldInvoiceMethod
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.GetBalanceMethod
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.GetInfoMethod
|
||||
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.NwcMethod
|
||||
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.utils.asTextOrNull
|
||||
|
||||
class RequestDeserializer : StdDeserializer<Request>(Request::class.java) {
|
||||
@@ -36,9 +46,18 @@ class RequestDeserializer : StdDeserializer<Request>(Request::class.java) {
|
||||
val jsonObject: JsonNode = jp.codec.readTree(jp)
|
||||
val method = jsonObject.get("method")?.asTextOrNull()
|
||||
|
||||
if (method == "pay_invoice") {
|
||||
return jp.codec.treeToValue(jsonObject, PayInvoiceMethod::class.java)
|
||||
return when (method) {
|
||||
NwcMethod.PAY_INVOICE -> jp.codec.treeToValue(jsonObject, PayInvoiceMethod::class.java)
|
||||
NwcMethod.PAY_KEYSEND -> jp.codec.treeToValue(jsonObject, PayKeysendMethod::class.java)
|
||||
NwcMethod.MAKE_INVOICE -> jp.codec.treeToValue(jsonObject, MakeInvoiceMethod::class.java)
|
||||
NwcMethod.LOOKUP_INVOICE -> jp.codec.treeToValue(jsonObject, LookupInvoiceMethod::class.java)
|
||||
NwcMethod.LIST_TRANSACTIONS -> jp.codec.treeToValue(jsonObject, ListTransactionsMethod::class.java)
|
||||
NwcMethod.GET_BALANCE -> jp.codec.treeToValue(jsonObject, GetBalanceMethod::class.java)
|
||||
NwcMethod.GET_INFO -> jp.codec.treeToValue(jsonObject, GetInfoMethod::class.java)
|
||||
NwcMethod.MAKE_HOLD_INVOICE -> jp.codec.treeToValue(jsonObject, MakeHoldInvoiceMethod::class.java)
|
||||
NwcMethod.CANCEL_HOLD_INVOICE -> jp.codec.treeToValue(jsonObject, CancelHoldInvoiceMethod::class.java)
|
||||
NwcMethod.SETTLE_HOLD_INVOICE -> jp.codec.treeToValue(jsonObject, SettleHoldInvoiceMethod::class.java)
|
||||
else -> null
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
+44
-16
@@ -24,9 +24,21 @@ import com.fasterxml.jackson.core.JsonParser
|
||||
import com.fasterxml.jackson.databind.DeserializationContext
|
||||
import com.fasterxml.jackson.databind.JsonNode
|
||||
import com.fasterxml.jackson.databind.deser.std.StdDeserializer
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.CancelHoldInvoiceSuccessResponse
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.GetBalanceSuccessResponse
|
||||
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.NwcError
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.NwcErrorResponse
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.NwcMethod
|
||||
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.utils.asTextOrNull
|
||||
|
||||
class ResponseDeserializer : StdDeserializer<Response>(Response::class.java) {
|
||||
@@ -36,25 +48,41 @@ class ResponseDeserializer : StdDeserializer<Response>(Response::class.java) {
|
||||
): Response? {
|
||||
val jsonObject: JsonNode = jp.codec.readTree(jp)
|
||||
val resultType = jsonObject.get("result_type")?.asTextOrNull()
|
||||
val hasError = jsonObject.has("error") && !jsonObject.get("error").isNull
|
||||
val hasResult = jsonObject.has("result") && !jsonObject.get("result").isNull
|
||||
|
||||
if (resultType == "pay_invoice") {
|
||||
val result = jsonObject.get("result")
|
||||
val error = jsonObject.get("error")
|
||||
if (result != null) {
|
||||
return jp.codec.treeToValue(jsonObject, PayInvoiceSuccessResponse::class.java)
|
||||
}
|
||||
if (error != null) {
|
||||
return jp.codec.treeToValue(jsonObject, PayInvoiceErrorResponse::class.java)
|
||||
}
|
||||
} else {
|
||||
// tries to guess
|
||||
if (jsonObject.get("result")?.get("preimage") != null) {
|
||||
return jp.codec.treeToValue(jsonObject, PayInvoiceSuccessResponse::class.java)
|
||||
}
|
||||
if (jsonObject.get("error")?.get("code") != null) {
|
||||
return jp.codec.treeToValue(jsonObject, PayInvoiceErrorResponse::class.java)
|
||||
if (hasError) {
|
||||
return when (resultType) {
|
||||
NwcMethod.PAY_INVOICE -> jp.codec.treeToValue(jsonObject, PayInvoiceErrorResponse::class.java)
|
||||
else -> {
|
||||
val error = jp.codec.treeToValue(jsonObject.get("error"), NwcError::class.java)
|
||||
NwcErrorResponse(resultType ?: "", error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasResult || resultType != null) {
|
||||
return when (resultType) {
|
||||
NwcMethod.PAY_INVOICE -> jp.codec.treeToValue(jsonObject, PayInvoiceSuccessResponse::class.java)
|
||||
NwcMethod.PAY_KEYSEND -> jp.codec.treeToValue(jsonObject, PayKeysendSuccessResponse::class.java)
|
||||
NwcMethod.MAKE_INVOICE -> jp.codec.treeToValue(jsonObject, MakeInvoiceSuccessResponse::class.java)
|
||||
NwcMethod.LOOKUP_INVOICE -> jp.codec.treeToValue(jsonObject, LookupInvoiceSuccessResponse::class.java)
|
||||
NwcMethod.LIST_TRANSACTIONS -> jp.codec.treeToValue(jsonObject, ListTransactionsSuccessResponse::class.java)
|
||||
NwcMethod.GET_BALANCE -> jp.codec.treeToValue(jsonObject, GetBalanceSuccessResponse::class.java)
|
||||
NwcMethod.GET_INFO -> jp.codec.treeToValue(jsonObject, GetInfoSuccessResponse::class.java)
|
||||
NwcMethod.MAKE_HOLD_INVOICE -> jp.codec.treeToValue(jsonObject, MakeHoldInvoiceSuccessResponse::class.java)
|
||||
NwcMethod.CANCEL_HOLD_INVOICE -> jp.codec.treeToValue(jsonObject, CancelHoldInvoiceSuccessResponse::class.java)
|
||||
NwcMethod.SETTLE_HOLD_INVOICE -> jp.codec.treeToValue(jsonObject, SettleHoldInvoiceSuccessResponse::class.java)
|
||||
else -> {
|
||||
// tries to guess for backward compatibility
|
||||
if (jsonObject.get("result")?.get("preimage") != null) {
|
||||
return jp.codec.treeToValue(jsonObject, PayInvoiceSuccessResponse::class.java)
|
||||
}
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user