# Cashu Wallet (NIP-60) — Implementation Plan

## Overview

Implement a Cashu wallet page (`www/cashu.html`) following the NIP-60 specification. The page will allow users to manage their ecash wallet stored on Nostr relays — view balance, receive tokens, send tokens, deposit via Lightning, and view transaction history.

## Key Discovery: NDK Bundle Already Includes Everything

The `ndk-core.bundle.js` already bundles:
- **`@cashu/cashu-ts`** — Full Cashu protocol library (mint interactions, token encoding/decoding, proof management)
- **`NDKCashuWallet`** — High-level NIP-60 wallet class with `create()`, `deposit()`, `send()`, `receive()`, `lnPay()`, balance tracking, state management
- **`NDKCashuToken`** (kind 7375) — Token event class with proof decryption
- **`NDKCashuWalletTx`** (kind 7376) — Transaction history event class
- **`NDKCashuMintList`** (kind 10019) — Mint list for nutzap reception
- **`NDKCashuDeposit`** — Lightning deposit flow with quote management
- **`NDKCashuWalletBackup`** (kind 375) — Wallet backup/restore
- **`NDKWalletStatus`** — Status enum (INITIAL, LOADING, READY, FAILED)

The `nostr.bundle.js` includes NIP-44 encryption support, and `init-ndk.mjs` already handles NIP-44 encrypt/decrypt sign requests from the worker.

## Architecture

```mermaid
graph TD
    A[cashu.html] --> B[init-ndk.mjs]
    B --> C[NDK SharedWorker]
    C --> D[Nostr Relays]
    A --> E[cashu-wallet.mjs - new module]
    E --> F[NDK.NDKCashuWallet]
    F --> G[cashu-ts CashuWallet]
    G --> H[Cashu Mint HTTP API]
    F --> D
    E --> I[window.nostr.nip44 - encryption]
```

### File Structure

- **`www/cashu.html`** — Page HTML + page-specific `<style>` + inline `<script type=module>`
- **`www/js/cashu-wallet.mjs`** — Cashu wallet logic module (keeps cashu.html clean)

The module approach follows the pattern used by `post-interactions.mjs` and `strudel-nostr.mjs`.

## UI Layout

The page uses a **single-column centered layout** (like `post.html`) with these sections:

```
┌─────────────────────────────────────┐
│  HEADER (hamburger + title)         │
├─────────────────────────────────────┤
│                                     │
│  ┌─────────────────────────────┐    │
│  │  BALANCE CARD               │    │
│  │  ₿ 1,234 sats              │    │
│  │  [mint1] 800  [mint2] 434   │    │
│  └─────────────────────────────┘    │
│                                     │
│  ┌──────┐ ┌──────┐ ┌──────┐        │
│  │RECEIVE│ │ SEND │ │DEPOSIT│       │
│  └──────┘ └──────┘ └──────┘        │
│                                     │
│  ┌─────────────────────────────┐    │
│  │  ACTION PANEL               │    │
│  │  (changes based on button)  │    │
│  │                             │    │
│  │  Receive: paste token input │    │
│  │  Send: amount + generate    │    │
│  │  Deposit: amount + LN inv   │    │
│  └─────────────────────────────┘    │
│                                     │
│  ┌─────────────────────────────┐    │
│  │  TRANSACTION HISTORY        │    │
│  │  ↓ 100 sats  2h ago        │    │
│  │  ↑  50 sats  5h ago        │    │
│  │  ...                        │    │
│  └─────────────────────────────┘    │
│                                     │
│  ┌─────────────────────────────┐    │
│  │  SETTINGS (collapsible)     │    │
│  │  Mints: [list + add/remove] │    │
│  └─────────────────────────────┘    │
│                                     │
├─────────────────────────────────────┤
│  FOOTER (relay status)              │
└─────────────────────────────────────┘
```

## CSS Strategy

Use existing CSS variables and patterns from `client.css`:
- `var(--primary-color)`, `var(--secondary-color)`, `var(--accent-color)`, `var(--muted-color)`
- `var(--border-width)`, `var(--border-radius)`, `var(--border-color)`
- `var(--font-family)`, `var(--font-mono)`
- `var(--button-color)`, `var(--button-background-color)`, `var(--button-hover-color)`
- Button styling pattern from `.btnKind` in `event.html`
- Card/pane styling pattern from `msg.html` (border + border-radius + background)
- `#divBody` override pattern: `flex-direction: column !important` etc.
- `.clsHidden` / `.clsVisible` for show/hide

All page-specific styles go in `<style>` block inside `cashu.html`, never in `client.css`.

## Implementation Steps

### Phase 1: Page Setup & Wallet Initialization

1. **Update `cashu.html` page structure** — Change title, add `<style>` block with `#divBody` column layout override, add HTML skeleton for all UI sections inside `#divBody`

2. **Create `www/js/cashu-wallet.mjs`** — Module that:
   - Imports NDK cashu classes from `window.NDK` (the bundle exposes them globally)
   - Provides `initWallet(ndk, pubkey)` — loads or creates NIP-60 wallet
   - Provides `getBalance()`, `getBalanceByMint()` — balance queries
   - Provides `receiveToken(encodedToken)` — receive cashu token
   - Provides `sendToken(amount, mint)` — create sendable cashu token
   - Provides `createDeposit(amount, mint)` — Lightning deposit flow
   - Provides `getTransactionHistory()` — fetch kind 7376 events
   - Provides `getMints()`, `addMint(url)`, `removeMint(url)` — mint management

3. **Wire up initialization in `cashu.html`** — After `initNDKPage()` completes, call `initWallet()` and render initial state

### Phase 2: Balance Display

4. **Render balance card** — Show total balance in sats, with per-mint breakdown. Update on wallet state changes. Show loading spinner during sync.

5. **Handle wallet states** — Show appropriate UI for: no wallet found (offer to create), wallet loading, wallet ready, wallet error

### Phase 3: Receive Tokens

6. **Receive panel** — Textarea to paste a `cashuA...` or `cashuB...` token string, "Receive" button. On submit, call `wallet.receive(token)`, show success/error, update balance.

### Phase 4: Send Tokens

7. **Send panel** — Amount input, mint selector dropdown, "Generate Token" button. On submit, call `wallet.send(amount)`, display the generated cashu token string with a copy button.

### Phase 5: Lightning Deposit

8. **Deposit panel** — Amount input, mint selector, "Create Invoice" button. Uses `NDKCashuDeposit` to create a Lightning invoice. Display the bolt11 invoice as text with copy button. Poll for payment confirmation, update balance on success.

### Phase 6: Transaction History

9. **Transaction list** — Fetch kind 7376 events, decrypt content, display as a scrollable list with direction arrows, amounts, and relative timestamps.

### Phase 7: Settings / Mint Management

10. **Settings section** — Collapsible section showing configured mints. Add mint input + button. Remove mint button per entry. "Create New Wallet" button if no wallet exists.

### Phase 8: Wallet Creation Flow

11. **First-run experience** — If no kind 17375 wallet event found, show a setup panel: enter mint URL(s), click "Create Wallet". Uses `NDKCashuWallet.create()`.

## Technical Notes

### Accessing NDK Cashu Classes

The NDK bundle exposes everything via `window.NDK`:
```javascript
const { NDKCashuWallet, NDKCashuToken, NDKCashuWalletTx, 
        NDKCashuDeposit, NDKCashuMintList, NDKWalletStatus } = window.NDK;
```

### NIP-44 Encryption

NIP-60 wallet content is NIP-44 encrypted. The existing `init-ndk.mjs` sign request handler already supports `nip44Encrypt` and `nip44Decrypt` methods, so NDK's built-in encryption will work automatically through the message-based signer.

### Event Deletion (NIP-09)

When spending tokens, old kind 7375 events must be deleted via kind 5 events. The `publishEvent()` function from `init-ndk.mjs` can publish deletion events:
```javascript
const deleteEvent = {
  kind: 5,
  tags: [["e", tokenEventId], ["k", "7375"]],
  content: ""
};
await publishEvent(deleteEvent);
```

### Default Mints

Suggest these well-known mints as defaults in the UI:
- `https://mint.minibits.cash/Bitcoin`
- `https://mint.coinos.io`
- `https://stablenut.umint.cash`

### Worker vs Direct NDK

The current architecture uses a SharedWorker for NDK. However, `NDKCashuWallet` needs direct access to the NDK instance (not through the worker message protocol). Two approaches:

**Option A (Recommended): Direct NDK instance on the page**
Create a lightweight NDK instance directly in the page for cashu operations. This NDK instance uses the same signer (window.nostr) and connects to the same relays. The worker continues handling subscriptions and relay status.

**Option B: Extend worker protocol**
Add cashu-specific message types to the worker. This is more complex and less flexible.

Option A is simpler and aligns with how NDKCashuWallet expects to be used.
