4346427e9f
Receipts were only being checked for a valid event signature — anyone could sign a kind:9735 and have it counted toward another user's zap totals. NIP-57 Appendix F mandates three additional checks: receipt.pubkey == LNURL provider's nostrPubkey (MUST), bolt11 invoice amount == zap request "amount" tag (MUST), and lnurl tag == recipient's lnurl (SHOULD). - Adds LnZapReceiptValidator + LnurlForm in quartz commonMain (pure logic). - Adds LnurlEndpointCache (jvmAndroid) and the LnurlEndpointResolver interface for async lookup. The cache is primed by outbound zaps (existing LightningAddressResolver fetches now extract nostrPubkey) and on demand for inbound receipts when no entry is present. - Adds OkHttpLnurlEndpointResolver in commons, wired into LocalCache via AppModules using the existing money-tier OkHttp builder (so Tor settings apply). - LocalCache.consume(LnZapEvent) now: drops receipts that fail MUST checks synchronously when the cache is warm, defers credit until async resolution finishes on cache miss, and falls back to legacy signature-only behavior when no resolver is wired (tests). - LnZapRequestEvent.create() now accepts amountMillisats + lnurl; both are threaded through Account.createZapRequestFor and emitted as tags so future receipts can be validated against them. 21 new tests cover validator reasons, lnurl form canonicalization across lud16/URL/bech32, and cache eviction.