mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-10 08:27:04 +00:00
fix(nwc): re-add #p to response filter for Alby relay routing
Dropping both `authors` and `#p` from the kind-23195 subscription filter fixed wallets that don't set those fields the way NIP-47 implies, but broke purpose-built NWC relays (notably relay.getalby.com/v1) that use `#p` as the routing key — without it the relay never delivers the response to our subscription, so the wallet screen sits on a spinner. Restore `#p: [client pubkey]` in the relay filter. Keep `authors` out since that field was the one actually causing the broader interop pain. Spec-compliant responses always carry the `p` tag, so adding it back does not exclude any conforming wallet. End-to-end authenticity is still enforced by NIP-04 decryption against the per-connection shared secret and by the client-side author check in NwcPaymentTracker. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
2dd0166fee
commit
cdb5e01821
+2
@@ -144,6 +144,7 @@ class NwcSignerState(
|
||||
|
||||
val filter =
|
||||
NWCPaymentQueryState(
|
||||
toUserHex = event.pubKey,
|
||||
replyingToHex = event.id,
|
||||
relay = walletService.relayUri,
|
||||
)
|
||||
@@ -183,6 +184,7 @@ class NwcSignerState(
|
||||
|
||||
val filter =
|
||||
NWCPaymentQueryState(
|
||||
toUserHex = event.pubKey,
|
||||
replyingToHex = event.id,
|
||||
relay = walletService.relayUri,
|
||||
)
|
||||
|
||||
+22
-9
@@ -25,15 +25,28 @@ import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import com.vitorpamplona.quartz.nip47WalletConnect.events.LnZapPaymentResponseEvent
|
||||
|
||||
// The request event id (#e) is a unique 32-byte identifier — sufficient on
|
||||
// its own to match the response. Adding `authors` or `#p` makes the filter
|
||||
// strictly stricter at the relay, which causes silent timeouts on services
|
||||
// or relays that don't set / index those fields the way NIP-47 expects
|
||||
// (e.g. wallets that omit the `p` tag, relays that don't index single-letter
|
||||
// tags on ephemeral kinds). Primal's client uses the same minimal filter
|
||||
// (kinds + #e), and the wallet's identity is still authenticated end-to-end
|
||||
// by NIP-04 decryption against the per-connection shared secret.
|
||||
fun filterNWCPaymentsFromRequests(paymentRequests: Set<HexKey>): Filter =
|
||||
// its own to match a spec-compliant kind-23195 response. We deliberately keep
|
||||
// `authors` out of the filter because some wallet services route through a
|
||||
// signer pubkey that differs from the one advertised in the connection URI,
|
||||
// which made the previous `authors`-strict filter time out.
|
||||
//
|
||||
// We DO keep `#p: [client pubkey]` because purpose-built NWC relays
|
||||
// (e.g. relay.getalby.com/v1) use the `#p` tag as the routing key — without
|
||||
// it the relay never delivers the response to our subscription, even though
|
||||
// the event is well-formed. Spec-compliant responses always set `p` to the
|
||||
// client pubkey, so including `#p` does not exclude any conforming wallet.
|
||||
// The wallet's identity is still authenticated end-to-end by NIP-04
|
||||
// decryption against the per-connection shared secret AND by a client-side
|
||||
// `event.pubKey == request.p` check in NwcPaymentTracker.
|
||||
fun filterNWCPaymentsFromRequests(
|
||||
paymentRequests: Set<HexKey>,
|
||||
fromUsers: Set<HexKey>,
|
||||
): Filter =
|
||||
Filter(
|
||||
kinds = listOf(LnZapPaymentResponseEvent.KIND),
|
||||
tags = mapOf("e" to paymentRequests.sorted()),
|
||||
tags =
|
||||
mapOf(
|
||||
"e" to paymentRequests.sorted(),
|
||||
"p" to fromUsers.sorted(),
|
||||
),
|
||||
)
|
||||
|
||||
+1
@@ -52,6 +52,7 @@ fun NWCFinderFilterAssemblerSubscription(
|
||||
noteEvent.walletServicePubKey()?.let {
|
||||
zapPaymentRequestNote.relays.map {
|
||||
NWCPaymentQueryState(
|
||||
toUserHex = noteEvent.pubKey,
|
||||
replyingToHex = noteEvent.id,
|
||||
relay = it,
|
||||
)
|
||||
|
||||
+6
-3
@@ -27,11 +27,14 @@ import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
|
||||
// This allows multiple screen to be listening to tags, even the same tag.
|
||||
// The subscription filter only needs the request event id (#e) — the wallet
|
||||
// service's identity is authenticated by NIP-04 decryption against the
|
||||
// per-connection shared secret, not by relay-side `authors`/`#p` filtering.
|
||||
// The subscription filter carries `#e: [request id]` plus `#p: [client pubkey]`.
|
||||
// The `#p` field is the routing key for purpose-built NWC relays (e.g.
|
||||
// relay.getalby.com/v1) — dropping it caused those relays to silently never
|
||||
// deliver the response. `authors` is intentionally left out because some
|
||||
// wallets sign responses with a key different from the URI-advertised one.
|
||||
@Stable
|
||||
class NWCPaymentQueryState(
|
||||
val toUserHex: HexKey,
|
||||
val replyingToHex: HexKey,
|
||||
val relay: NormalizedRelayUrl,
|
||||
)
|
||||
|
||||
+2
-1
@@ -33,12 +33,13 @@ class NWCPaymentWatcherSubAssembler(
|
||||
|
||||
return keys.groupBy { it.relay }.map { relayGroup ->
|
||||
val replyingToPayments = relayGroup.value.mapTo(mutableSetOf()) { it.replyingToHex }
|
||||
val aboutUsers = relayGroup.value.mapTo(mutableSetOf()) { it.toUserHex }
|
||||
|
||||
if (replyingToPayments.isEmpty()) return null
|
||||
|
||||
RelayBasedFilter(
|
||||
relay = relayGroup.key,
|
||||
filter = filterNWCPaymentsFromRequests(replyingToPayments),
|
||||
filter = filterNWCPaymentsFromRequests(replyingToPayments, aboutUsers),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user