Phase 1 (feed2.html):
- Removed inline comment rendering and Comments toggle button
- Comment button now opens post-feed.html?event=<eventId> in new tab
- Removed inline reply composer (kept quote composer)
- Fixed missing queryCache dependency in initPostCards
- Fixed hardcoded color:red -> var(--primary-color)
Phase 2 (post-feed.html):
- New post thread page showing post + all replies + inline composer
- Parses ?event=<hex|nevent|note> URL parameter
- Fetches replies via { kinds: [1], '#e': [postId] }
- Real-time subscriptions for new replies
- Comment button on replies opens sub-threads in new tabs
- Error states for missing/invalid/not-found posts
- All CSS uses variables, no hardcoded colors
179 lines
8.4 KiB
Markdown
179 lines
8.4 KiB
Markdown
# Cashu Wallet Enhancements — Implementation Plan
|
||
|
||
## Overview
|
||
|
||
Enhance the existing `www/cashu.html` page and zap flow, centered on **Cashu as the primary (and only) payment rail**. The core functionality is already implemented — this plan adds UI improvements to show zap capabilities in the feed and let users choose their zap rail.
|
||
|
||
### Design philosophy: Cashu-only
|
||
|
||
The project uses **Cashu for everything** — no NWC, CLINK, onchain, or Lightning channels to maintain:
|
||
|
||
| Payment type | How it works | Already implemented? |
|
||
|-------------|-------------|---------------------|
|
||
| **Nutzap (NIP-61)** | Send ecash proofs locked to recipient's p2pk via kind 9321 | ✅ Yes — `walletSendNutzap` |
|
||
| **Lightning zap (NIP-57)** | Melt Cashu ecash at a mint to pay a BOLT11 invoice | ✅ Yes — `walletPayInvoice` |
|
||
| **P2P ecash transfer** | Send cashuB token directly to another user | ✅ Yes — `walletSendToken` |
|
||
| **Lightning deposit** | Pay a BOLT11 invoice, mint issues ecash proofs | ✅ Yes — `walletCreateDeposit` |
|
||
| **Lightning withdrawal** | Melt ecash to pay an external BOLT11 invoice | ✅ Yes — `walletPayInvoice` |
|
||
|
||
---
|
||
|
||
## Phase 1: NIP-60 Compliance Fix (DONE ✅)
|
||
|
||
Already completed and deployed (v0.7.19–v0.7.24):
|
||
- Fixed kind 17375 content format from proprietary `{mints, nutzap}` object to NIP-60 tag-array `[["mint",url],["privkey",hex]]`
|
||
- Removed non-standard `pubkey` tag from 17375 public tags
|
||
- Added `parseWalletContent()` backwards-compat shim for reading both formats
|
||
- Added auto-migration for legacy 17375 events on startup
|
||
- Added "Republish Wallet (kind 17375)" button with lightweight 17375-only republish
|
||
- Added `ensureDirectNutzapP2pk()` call in `publishDirectProofs` so privkey is always included
|
||
|
||
---
|
||
|
||
## Phase 2: Zap Capability Indicators in the Feed
|
||
|
||
Show zap capability badges on each post's interaction bar so users can see at a glance whether the recipient can receive nutzaps, Lightning zaps, or both.
|
||
|
||
### Current state
|
||
|
||
The interaction bar in [`www/js/post-interactions.mjs`](www/js/post-interactions.mjs) already renders:
|
||
- ⚡ Zap button with count
|
||
- 🥜 Nutzap count display (separate element showing total nutzaps received)
|
||
|
||
### What to add
|
||
|
||
Small capability icons/badges next to the zap button showing what the recipient can receive:
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────┐
|
||
│ ⚡ 5 🥜 2 🥜✅ ⚡✅ 💬 3 🔄 1 2h ago │
|
||
│ └─ zap ─┘ └─ nutzap ─┘ └─ capability badges ─┘ │
|
||
└──────────────────────────────────────────────────┘
|
||
```
|
||
|
||
Or a more compact design — color the zap icon differently based on capabilities:
|
||
|
||
| Visual | Meaning |
|
||
|--------|---------|
|
||
| ⚡ (default color) | Recipient can receive Lightning zaps (has lud16) |
|
||
| ⚡ + 🥜 (nut badge) | Recipient can also receive nutzaps (has kind 10019 with shared mint) |
|
||
| ⚡ (dimmed) | Recipient cannot receive any zaps (no lud16, no 10019) |
|
||
|
||
### Implementation
|
||
|
||
- [ ] **2.1** Create a `resolveZapCapabilities(pubkey)` function that checks:
|
||
- Does the recipient have a lud16 (Lightning address)? → can receive Lightning zaps
|
||
- Does the recipient have a kind 10019 (nutzap mint list)? → can receive nutzaps
|
||
- If yes to 10019, which mints? Do any overlap with the sender's wallet mints?
|
||
|
||
- [ ] **2.2** Cache the results per pubkey (the kind 10019 and lud16 don't change often). Use a simple in-memory Map with TTL.
|
||
|
||
- [ ] **2.3** Update `createInteractionItem` for the zap type to show capability indicators:
|
||
- Add a small 🥜 badge on the zap button if the recipient can receive nutzaps
|
||
- Add a tooltip showing the shared mints
|
||
- Dim the zap button if the recipient can't receive any zaps
|
||
|
||
- [ ] **2.4** Fetch kind 10019 events for post authors as the feed loads. The worker already fetches kind 10019 for nutzap sending — extend this to cache the results for feed display. Use the existing `walletFetchMintList` worker function.
|
||
|
||
- [ ] **2.5** Show shared mint info on hover/tooltip: "Can nutzap via mint.minibits.cash/Bitcoin" or "No shared mints — Lightning only" or "No zap capability"
|
||
|
||
### Where the code lives
|
||
|
||
| File | What to change |
|
||
|------|---------------|
|
||
| [`www/js/post-interactions.mjs`](www/js/post-interactions.mjs) | Add capability badges to zap button rendering |
|
||
| [`www/js/zaps.mjs`](www/js/zaps.mjs) | Add `resolveZapCapabilities()` function (or extend existing `resolveZapSpecForPubkey`) |
|
||
| [`www/ndk-worker.js`](www/ndk-worker.js) | May need a lightweight "fetch 10019 for display" message (or reuse `walletFetchMintList`) |
|
||
|
||
---
|
||
|
||
## Phase 3: Zap Rail Selector in the Zap Dialog
|
||
|
||
When the user taps the zap button, show which rails are available and let them choose.
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
A[User taps zap button] --> B[Show zap dialog with amount input]
|
||
B --> C{What rails are available?}
|
||
C -->|Nutzap + Lightning| D[Show rail toggle: 🥜 Nutzap | ⚡ Lightning]
|
||
C -->|Lightning only| E[Show Lightning only]
|
||
C -->|Nutzap only| F[Show Nutzap only]
|
||
C -->|Neither| G[Show error: recipient cannot receive zaps]
|
||
D --> H[User selects rail + amount]
|
||
H --> I{Rail selected}
|
||
I -->|Nutzap| J[Send NIP-61 nutzap via walletSendNutzap]
|
||
I -->|Lightning| K[Create LN invoice, melt Cashu via walletPayInvoice]
|
||
E --> K
|
||
F --> J
|
||
```
|
||
|
||
- [ ] **3.1** Update `promptZapDetails` in `zaps.mjs` to accept and display rail options:
|
||
- If nutzap is available (recipient has 10019 with shared mint) → show "🥜 Nutzap" option
|
||
- If Lightning is available (recipient has lud16) → show "⚡ Lightning" option
|
||
- Let the user pick which rail to use via a toggle/selector
|
||
|
||
- [ ] **3.2** Show balance info in the dialog:
|
||
- "Cashu balance: 261 sats"
|
||
- If amount > balance → show warning "Insufficient balance"
|
||
|
||
- [ ] **3.3** Default rail selection:
|
||
- If nutzap is available and amount < 1000 sats → default to nutzap (lower fees)
|
||
- If nutzap is available and amount ≥ 1000 sats → default to Lightning (more reliable for larger amounts)
|
||
- If nutzap is not available → default to Lightning
|
||
|
||
- [ ] **3.4** Pass the selected rail back to `handleZapClick` in `post-interactions.mjs` so it uses the right send function.
|
||
|
||
---
|
||
|
||
## Phase 4: cashu.html UI Polish
|
||
|
||
Minor UI improvements to the existing cashu.html page:
|
||
|
||
- [ ] **4.1** Consider renaming the page title from "CASHU" to "WALLET" since it's the project's unified wallet.
|
||
|
||
- [ ] **4.2** Update the sidenav entry in `index.html` from "CASHU" to "WALLET" (keeping the same `cashu.html` URL).
|
||
|
||
- [ ] **4.3** Add a "Zap via Lightning" info note in the Withdraw panel explaining that this melts ecash to pay a Lightning invoice — same mechanism used for Lightning zaps.
|
||
|
||
---
|
||
|
||
## NIP Compliance Reference
|
||
|
||
| Rail | NIP | Kind(s) | Status |
|
||
|------|-----|---------|--------|
|
||
| Cashu Wallet | NIP-60 | 17375, 7375, 7376, 375 | ✅ Fixed and working |
|
||
| Cashu Nutzap | NIP-61 | 10019, 9321 | ✅ Working |
|
||
| Lightning Zap | NIP-57 | 9734, 9735 | ✅ Working (via Cashu melt) |
|
||
|
||
---
|
||
|
||
## Key Files
|
||
|
||
### Files to modify
|
||
|
||
| File | Changes |
|
||
|------|---------|
|
||
| [`www/js/post-interactions.mjs`](www/js/post-interactions.mjs) | Add zap capability badges to interaction bar, pass selected rail to zap handler |
|
||
| [`www/js/zaps.mjs`](www/js/zaps.mjs) | Add `resolveZapCapabilities()`, update `promptZapDetails` with rail selector |
|
||
| [`www/cashu.html`](www/cashu.html) | Minor UI polish (title, info notes) |
|
||
| [`www/index.html`](www/index.html) | Sidenav label: "CASHU" → "WALLET" |
|
||
|
||
### Files reused as-is
|
||
|
||
| File | Why no changes needed |
|
||
|------|----------------------|
|
||
| [`www/js/cashu-wallet.mjs`](www/js/cashu-wallet.mjs) | Controller already wraps all worker functions |
|
||
| [`www/ndk-worker.js`](www/ndk-worker.js) | All wallet functions already exist (payInvoice, sendNutzap, fetchMintList) |
|
||
| [`www/js/init-ndk.mjs`](www/js/init-ndk.mjs) | All wallet exports already exist |
|
||
|
||
---
|
||
|
||
## Implementation Order
|
||
|
||
1. **Phase 1** (DONE) — NIP-60 compliance fix
|
||
2. **Phase 2** (zap capability indicators) — show what the recipient can receive in the feed
|
||
3. **Phase 3** (rail selector) — let users choose nutzap vs Lightning melt in the zap dialog
|
||
4. **Phase 4** (UI polish) — minor label/info changes
|
||
|
||
No new files needed. No new infrastructure. Just UI improvements on top of the existing working zap flow.
|