From 33fdd34cf0244d687c703e8fb6d3ae4b4e7c8543 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 22 Jun 2026 01:12:20 +0000 Subject: [PATCH] fix(nutzaps): advertise inbox+dm relays in kind:10019, not outbox MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Complete the NIP-65 outbox-model alignment for NIP-61: the `relay` tags in our kind:10019 are, per spec, the relays where the recipient *reads* incoming token events — i.e. inbox-side relays others publish to. We were advertising our outbox (write) relays there. Both publish paths (initial wallet creation in CashuWalletViewModel and P2PK key rotation in CashuWalletState.recreateNutzapKey) now advertise the union of our NIP-65 inbox + DM relays. This mirrors the relay set the wallet subscribes to for inbound kind:9321, so senders following our kind:10019 publish exactly where we listen. Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_01JHcZ2gv8ro9Q2bEiTSiHD8 --- .../amethyst/model/nip60Cashu/CashuWalletOps.kt | 8 +++++--- .../amethyst/model/nip60Cashu/CashuWalletState.kt | 5 ++++- .../ui/screen/loggedIn/wallet/CashuWalletViewModel.kt | 6 +++++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip60Cashu/CashuWalletOps.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip60Cashu/CashuWalletOps.kt index bd8472aa6a..ae264b938d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip60Cashu/CashuWalletOps.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip60Cashu/CashuWalletOps.kt @@ -153,9 +153,11 @@ class CashuWalletOps( val walletEvent = signer.sign(walletTemplate) publish(walletEvent) - // Populate `relay` tags so senders know where to publish nutzaps — - // without these, they fall back to NIP-65 outbox and may miss our - // subscription scope on relays we don't read from. + // Populate `relay` tags so senders know where to publish nutzaps. + // Per NIP-61 these are the relays where the recipient reads incoming + // token events, so callers pass our inbox-side relays here (NIP-65 + // outbox model). Without them, senders fall back to NIP-65 and may + // publish where we don't subscribe for inbound nutzaps. val nutzapInfoTemplate = NutzapInfoEvent.build( mints = mints.map { NutzapMintTag(it, listOf("sat")) }, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip60Cashu/CashuWalletState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip60Cashu/CashuWalletState.kt index 7dc52b4ca1..785b8a8cce 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip60Cashu/CashuWalletState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/nip60Cashu/CashuWalletState.kt @@ -895,7 +895,10 @@ class CashuWalletState( ops.publishWalletEvents( mints = currentMints, p2pkPrivkeyHex = manualPrivkeyHex?.takeIf { it.isNotBlank() }, - nutzapRelays = outboxRelaysFlow.value.toList(), + // Advertise our inbox + DM relays as the nutzap relays (NIP-65 + // outbox model): senders publish kind:9321 where we read inbound + // events, matching the wallet's inbound-nutzap subscription set. + nutzapRelays = (inboxRelaysFlow.value + dmRelaysFlow.value).toList(), ) // The NUT-13 seed (derived from the P2PK key) is invalidated by // applyEvents when the new kind:17375 round-trips in, so it re-derives diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/CashuWalletViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/CashuWalletViewModel.kt index 0d0cd0ce79..7414865339 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/CashuWalletViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/wallet/CashuWalletViewModel.kt @@ -500,8 +500,12 @@ class CashuWalletViewModel : ViewModel() { ops.publishWalletEvents( mints = mints, p2pkPrivkeyHex = privkey, + // Advertise our inbox + DM relays as the nutzap relays, so + // senders publish kind:9321 where we read incoming events + // (NIP-65 outbox model). Mirrors the relay set the wallet + // subscribes to for inbound nutzaps. nutzapRelays = - acc.outboxRelays.flow.value + (acc.notificationRelays.flow.value + acc.dmRelays.flow.value) .toList(), ) _createState.value = CashuWalletCreateState.Success